summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBill Peckham <bpeckham@google.com>2018-11-05 17:12:23 -0800
committerBill Peckham <bpeckham@google.com>2018-11-05 17:12:23 -0800
commitba167de93776a7e5d1b347d1ee646e161cf24ce5 (patch)
treef1ced04b88bd977af08011e6c7e4124ebe8aa293
parentf893260618712d3894d1279e27ee121d4be8817f (diff)
parent828551df83149d4b5754757d8b2dc36f55f24cad (diff)
Merge QP1A.181022.001
Change-Id: I0e200ff664739f0bce5a55806ac4fc95fbbff52d
-rwxr-xr-xAndroid.bp22
-rwxr-xr-xAndroid.mk13
-rw-r--r--PREUPLOAD.cfg1
-rwxr-xr-xapi/current.txt255
-rw-r--r--api/system-current.txt107
-rw-r--r--api/system-removed.txt32
-rw-r--r--api/test-current.txt4
-rw-r--r--cmds/statsd/Android.mk3
-rw-r--r--cmds/statsd/src/StatsLogProcessor.h6
-rw-r--r--cmds/statsd/src/StatsService.cpp9
-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.proto475
-rw-r--r--cmds/statsd/src/external/StatsPullerManager.cpp9
-rw-r--r--cmds/statsd/src/hash.cpp12
-rw-r--r--cmds/statsd/src/main.cpp35
-rw-r--r--cmds/statsd/src/matchers/EventMatcherWizard.cpp38
-rw-r--r--cmds/statsd/src/matchers/EventMatcherWizard.h41
-rw-r--r--cmds/statsd/src/metrics/GaugeMetricProducer.cpp27
-rw-r--r--cmds/statsd/src/metrics/GaugeMetricProducer.h13
-rw-r--r--cmds/statsd/src/metrics/MetricProducer.cpp48
-rw-r--r--cmds/statsd/src/metrics/MetricProducer.h60
-rw-r--r--cmds/statsd/src/metrics/MetricsManager.cpp22
-rw-r--r--cmds/statsd/src/metrics/MetricsManager.h8
-rw-r--r--cmds/statsd/src/metrics/metrics_manager_util.cpp50
-rw-r--r--cmds/statsd/src/metrics/metrics_manager_util.h2
-rw-r--r--cmds/statsd/src/shell/ShellSubscriber.cpp108
-rw-r--r--cmds/statsd/src/shell/ShellSubscriber.h25
-rw-r--r--cmds/statsd/src/shell/shell_config.proto2
-rw-r--r--cmds/statsd/src/shell/shell_data.proto29
-rw-r--r--cmds/statsd/src/stats_log.proto1
-rw-r--r--cmds/statsd/src/statsd_config.proto13
-rw-r--r--cmds/statsd/tests/MetricsManager_test.cpp42
-rw-r--r--cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp30
-rw-r--r--cmds/statsd/tests/e2e/MetricActivation_e2e_test.cpp242
-rw-r--r--cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp73
-rw-r--r--cmds/statsd/tests/shell/ShellSubscriber_test.cpp134
-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--config/preloaded-classes1
-rw-r--r--core/java/android/app/Activity.java11
-rw-r--r--core/java/android/app/ActivityManagerInternal.java66
-rw-r--r--core/java/android/app/ActivityOptions.java28
-rw-r--r--core/java/android/app/ActivityTaskManager.java6
-rw-r--r--core/java/android/app/ActivityThread.java4
-rw-r--r--core/java/android/app/ActivityTransitionCoordinator.java9
-rw-r--r--core/java/android/app/ActivityTransitionState.java36
-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/EnterTransitionCoordinator.java10
-rw-r--r--core/java/android/app/ExitTransitionCoordinator.java5
-rw-r--r--core/java/android/app/Notification.java71
-rw-r--r--core/java/android/app/SystemServiceRegistry.java2
-rw-r--r--core/java/android/app/admin/DevicePolicyManager.java110
-rw-r--r--core/java/android/app/admin/IDevicePolicyManager.aidl6
-rw-r--r--core/java/android/app/backup/BackupAgent.java13
-rwxr-xr-xcore/java/android/bluetooth/BluetoothA2dpSink.java3
-rw-r--r--core/java/android/bluetooth/BluetoothAvrcpController.java3
-rw-r--r--core/java/android/bluetooth/BluetoothDevice.java20
-rw-r--r--core/java/android/bluetooth/BluetoothGatt.java27
-rw-r--r--core/java/android/bluetooth/BluetoothGattServer.java4
-rw-r--r--core/java/android/bluetooth/BluetoothHeadsetClient.java3
-rw-r--r--core/java/android/bluetooth/BluetoothHealth.java3
-rw-r--r--core/java/android/bluetooth/BluetoothHearingAid.java3
-rw-r--r--core/java/android/bluetooth/BluetoothHidDevice.java3
-rw-r--r--core/java/android/bluetooth/BluetoothHidHost.java3
-rw-r--r--core/java/android/bluetooth/BluetoothMap.java3
-rw-r--r--core/java/android/bluetooth/BluetoothMapClient.java3
-rw-r--r--core/java/android/bluetooth/BluetoothPan.java3
-rw-r--r--core/java/android/bluetooth/BluetoothPbap.java3
-rw-r--r--core/java/android/bluetooth/BluetoothPbapClient.java3
-rw-r--r--core/java/android/bluetooth/BluetoothSap.java3
-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/ContentProvider.java42
-rw-r--r--core/java/android/content/ContentProviderOperation.java2
-rw-r--r--core/java/android/content/ContentResolver.java71
-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.java12
-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/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/camera2/CameraMetadata.java2
-rw-r--r--core/java/android/hardware/display/DisplayManager.java2
-rw-r--r--core/java/android/hardware/location/ContextHubClient.java17
-rw-r--r--core/java/android/hardware/location/ContextHubManager.java4
-rw-r--r--core/java/android/net/ConnectivityManager.java55
-rw-r--r--core/java/android/net/NetworkCapabilities.java10
-rw-r--r--core/java/android/net/NetworkInfo.java20
-rw-r--r--core/java/android/net/NetworkUtils.java31
-rw-r--r--core/java/android/net/Uri.java37
-rw-r--r--core/java/android/os/Build.java30
-rw-r--r--core/java/android/os/DumpstateOptions.java57
-rw-r--r--core/java/android/os/FileUtils.java13
-rw-r--r--core/java/android/os/GraphicsEnvironment.java169
-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/UserManager.java16
-rw-r--r--core/java/android/os/storage/StorageManager.java6
-rw-r--r--core/java/android/permission/PermissionManager.java55
-rw-r--r--core/java/android/provider/DocumentsContract.java82
-rw-r--r--core/java/android/provider/MediaStore.java264
-rw-r--r--core/java/android/provider/Settings.java148
-rw-r--r--core/java/android/security/keystore/recovery/KeyChainSnapshot.java25
-rw-r--r--core/java/android/security/keystore/recovery/RecoveryController.java90
-rw-r--r--core/java/android/security/keystore/recovery/RecoverySession.java44
-rw-r--r--core/java/android/security/keystore/recovery/WrappedApplicationKey.java18
-rw-r--r--core/java/android/service/textclassifier/TextClassifierService.java4
-rw-r--r--core/java/android/speech/tts/TextToSpeechService.java1
-rw-r--r--core/java/android/text/Layout.java31
-rw-r--r--core/java/android/text/MeasuredParagraph.java41
-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.java60
-rw-r--r--core/java/android/transition/Visibility.java24
-rw-r--r--core/java/android/util/FeatureFlagUtils.java2
-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/MotionEvent.java43
-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/ViewGroup.java4
-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.java18
-rw-r--r--core/java/android/view/textclassifier/TextClassifier.java98
-rw-r--r--core/java/android/view/textclassifier/TextLanguage.java307
-rw-r--r--core/java/android/webkit/WebViewClient.java19
-rw-r--r--core/java/android/widget/RemoteViews.java82
-rw-r--r--core/java/android/widget/TextView.java25
-rw-r--r--core/java/android/widget/Toast.java2
-rw-r--r--core/java/com/android/internal/app/AssistUtils.java21
-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/KernelWakelockReader.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/view/IInputMethodManager.aidl1
-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/java/com/google/android/collect/Lists.java2
-rw-r--r--core/java/com/google/android/collect/Maps.java2
-rw-r--r--core/jni/Android.bp6
-rw-r--r--core/jni/AndroidRuntime.cpp10
-rw-r--r--core/jni/android/graphics/NinePatch.cpp9
-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_opengl_EGL15.cpp557
-rw-r--r--core/jni/android_os_GraphicsEnvironment.cpp15
-rw-r--r--core/jni/android_util_Binder.cpp37
-rw-r--r--core/jni/com_android_internal_net_NetworkStatsFactory.cpp2
-rw-r--r--core/proto/android/internal/powerprofile.proto26
-rw-r--r--core/proto/android/os/system_properties.proto4
-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/attrs.xml12
-rw-r--r--core/res/res/values/config.xml32
-rw-r--r--core/res/res/values/public.xml15
-rw-r--r--core/res/res/values/strings.xml13
-rw-r--r--core/res/res/values/symbols.xml19
-rw-r--r--core/res/res/xml/sms_short_codes.xml11
-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/content/ContentResolverTest.java166
-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.java18
-rw-r--r--core/tests/coretests/src/android/provider/SettingsBackupTest.java3
-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/text/method/ForwardDeleteTest.java15
-rw-r--r--core/tests/coretests/src/android/view/DisplayCutoutTest.java12
-rw-r--r--core/tests/coretests/src/android/view/MotionEventTest.java7
-rw-r--r--core/tests/coretests/src/android/view/accessibility/AccessibilityNodeInfoTest.java2
-rw-r--r--core/tests/coretests/src/android/view/textclassifier/TextLanguageTest.java85
-rw-r--r--core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java68
-rw-r--r--data/etc/privapp-permissions-platform.xml2
-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/ColorSpace.java10
-rw-r--r--graphics/java/android/graphics/Point.java11
-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)186
-rw-r--r--graphics/java/android/graphics/text/MeasuredText.java348
-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.bp7
-rw-r--r--libs/hwui/CanvasState.cpp284
-rw-r--r--libs/hwui/CanvasState.h195
-rw-r--r--libs/hwui/ClipArea.cpp534
-rw-r--r--libs/hwui/ClipArea.h212
-rw-r--r--libs/hwui/FloatColor.h71
-rw-r--r--libs/hwui/ResourceCache.cpp145
-rw-r--r--libs/hwui/ResourceCache.h103
-rw-r--r--libs/hwui/Snapshot.cpp209
-rw-r--r--libs/hwui/Snapshot.h279
-rw-r--r--libs/hwui/Vertex.h1
-rw-r--r--libs/hwui/hwui/Bitmap.cpp1
-rw-r--r--libs/hwui/tests/common/TestUtils.h9
-rw-r--r--libs/hwui/tests/microbench/DisplayListCanvasBench.cpp47
-rw-r--r--libs/hwui/tests/unit/CanvasStateTests.cpp160
-rw-r--r--libs/hwui/tests/unit/ClipAreaTests.cpp353
-rw-r--r--libs/hwui/tests/unit/RenderNodeDrawableTests.cpp1
-rw-r--r--libs/hwui/tests/unit/SkiaBehaviorTests.cpp17
-rw-r--r--libs/hwui/tests/unit/SnapshotTests.cpp74
-rw-r--r--location/java/android/location/LocationManager.java4
-rw-r--r--media/OWNERS2
-rw-r--r--media/java/android/media/AudioManager.java19
-rw-r--r--media/java/android/media/ExifInterface.java6
-rw-r--r--media/java/android/media/IAudioService.aidl5
-rw-r--r--media/java/android/media/MediaDrm.java10
-rw-r--r--media/java/android/media/MediaPlayer2.java79
-rw-r--r--media/java/android/media/MediaPlayer2Impl.java138
-rw-r--r--media/java/android/media/RingtoneManager.java33
-rw-r--r--media/java/android/media/update/ApiLoader.java54
-rw-r--r--media/jni/android_media_MediaPlayer2.cpp41
-rw-r--r--opengl/java/android/opengl/EGL15.java149
-rw-r--r--opengl/java/android/opengl/EGLImage.java37
-rw-r--r--opengl/java/android/opengl/EGLSync.java37
-rw-r--r--packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CarrierActionUtils.java6
-rw-r--r--packages/CarrierDefaultApp/tests/unit/src/com/android/carrierdefaultapp/CarrierDefaultReceiverTest.java2
-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/src/com/android/packageinstaller/InstallStart.java9
-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/Android.bp4
-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.java17
-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.java2
-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/applications/DefaultAppInfoTest.java6
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java10
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java124
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java6
-rw-r--r--packages/SettingsProvider/test/src/com/android/providers/settings/SettingsProviderTest.java2
-rw-r--r--packages/Shell/AndroidManifest.xml2
-rw-r--r--packages/SystemUI/plugin/src/com/android/systemui/plugins/SensorManagerPlugin.java27
-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/config.xml3
-rw-r--r--packages/SystemUI/res/values/strings.xml5
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/system/RotationWatcher.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java49
-rw-r--r--packages/SystemUI/src/com/android/systemui/OverviewProxyService.java2
-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/SwipeHelper.java9
-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.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java13
-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/KeyguardIndicationController.java30
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java11
-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/VisibilityLocationProvider.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java98
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java66
-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/NotificationListContainer.java19
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java1390
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ViewState.java43
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java60
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java20
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java2
-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/NavigationBarFragment.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java40
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java75
-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/phone/StatusBarWindowView.java27
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java13
-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/volume/VolumeDialogControllerImpl.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java22
-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/NotificationViewHierarchyManagerTest.java3
-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/statusbar/phone/StatusBarWindowViewTest.java8
-rw-r--r--proto/src/metrics_constants/metrics_constants.proto15
-rw-r--r--services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java7
-rw-r--r--services/art-profile8
-rw-r--r--services/autofill/java/com/android/server/autofill/AutofillManagerService.java4
-rw-r--r--services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java42
-rw-r--r--services/autofill/java/com/android/server/autofill/Session.java63
-rw-r--r--services/autofill/java/com/android/server/autofill/ViewState.java8
-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.java303
-rw-r--r--services/core/java/com/android/server/DeviceIdleController.java66
-rw-r--r--services/core/java/com/android/server/LocationManagerService.java6
-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/TelephonyRegistry.java42
-rw-r--r--services/core/java/com/android/server/Watchdog.java2
-rw-r--r--services/core/java/com/android/server/WiredAccessoryManager.java3
-rw-r--r--services/core/java/com/android/server/am/ActiveServices.java30
-rw-r--r--services/core/java/com/android/server/am/ActivityDisplay.java21
-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.java3141
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerShellCommand.java6
-rw-r--r--services/core/java/com/android/server/am/ActivityMetricsLogger.java95
-rw-r--r--services/core/java/com/android/server/am/ActivityRecord.java125
-rw-r--r--services/core/java/com/android/server/am/ActivityStack.java97
-rw-r--r--services/core/java/com/android/server/am/ActivityStackSupervisor.java267
-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.java160
-rw-r--r--services/core/java/com/android/server/am/ActivityTaskManagerDebugConfig.java91
-rw-r--r--services/core/java/com/android/server/am/ActivityTaskManagerService.java1057
-rw-r--r--services/core/java/com/android/server/am/AppErrorDialog.java6
-rw-r--r--services/core/java/com/android/server/am/AppErrors.java339
-rw-r--r--services/core/java/com/android/server/am/AppNotRespondingDialog.java11
-rw-r--r--services/core/java/com/android/server/am/BroadcastQueue.java6
-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.java76
-rw-r--r--services/core/java/com/android/server/am/LockTaskController.java10
-rw-r--r--services/core/java/com/android/server/am/MemoryStatUtil.java48
-rw-r--r--services/core/java/com/android/server/am/PendingIntentRecord.java11
-rw-r--r--services/core/java/com/android/server/am/ProcessList.java1803
-rw-r--r--services/core/java/com/android/server/am/ProcessRecord.java487
-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.java884
-rw-r--r--services/core/java/com/android/server/am/TaskRecord.java24
-rw-r--r--services/core/java/com/android/server/am/UserController.java12
-rw-r--r--services/core/java/com/android/server/am/VrController.java4
-rw-r--r--services/core/java/com/android/server/am/WindowProcessController.java184
-rw-r--r--services/core/java/com/android/server/am/WindowProcessListener.java17
-rw-r--r--services/core/java/com/android/server/audio/AudioService.java48
-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/hdmi/HdmiControlService.java19
-rw-r--r--services/core/java/com/android/server/hdmi/SystemAudioAutoInitiationAction.java3
-rw-r--r--services/core/java/com/android/server/input/InputManagerService.java15
-rw-r--r--services/core/java/com/android/server/inputmethod/InputMethodManagerService.java63
-rw-r--r--services/core/java/com/android/server/location/ContextHubClientBroker.java82
-rw-r--r--services/core/java/com/android/server/location/ContextHubClientManager.java19
-rw-r--r--services/core/java/com/android/server/location/ContextHubService.java6
-rw-r--r--services/core/java/com/android/server/media/MediaUpdateService.java65
-rw-r--r--services/core/java/com/android/server/net/NetworkPolicyLogger.java1
-rw-r--r--services/core/java/com/android/server/net/NetworkPolicyManagerInternal.java24
-rw-r--r--services/core/java/com/android/server/net/NetworkPolicyManagerService.java93
-rw-r--r--services/core/java/com/android/server/notification/NotificationManagerService.java18
-rw-r--r--services/core/java/com/android/server/pm/LauncherAppsService.java93
-rwxr-xr-xservices/core/java/com/android/server/pm/PackageManagerService.java60
-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/UserRestrictionsUtils.java10
-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.java22
-rw-r--r--services/core/java/com/android/server/policy/PhoneWindowManager.java23
-rw-r--r--services/core/java/com/android/server/policy/WindowManagerPolicy.java4
-rw-r--r--services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java20
-rw-r--r--services/core/java/com/android/server/stats/StatsCompanionService.java157
-rw-r--r--services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java25
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java98
-rw-r--r--services/core/java/com/android/server/wm/AppWindowToken.java34
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java69
-rw-r--r--services/core/java/com/android/server/wm/InputManagerCallback.java4
-rw-r--r--services/core/java/com/android/server/wm/InputMonitor.java6
-rw-r--r--services/core/java/com/android/server/wm/RecentsAnimationController.java19
-rw-r--r--services/core/java/com/android/server/wm/RootWindowContainer.java15
-rw-r--r--services/core/java/com/android/server/wm/TaskPositioningController.java2
-rw-r--r--services/core/java/com/android/server/wm/TaskSnapshotPersister.java4
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java42
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java4
-rw-r--r--services/core/jni/Android.bp1
-rw-r--r--services/core/jni/com_android_server_input_InputManagerService.cpp19
-rw-r--r--services/core/jni/com_android_server_net_NetworkStatsService.cpp2
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java19
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java99
-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.java297
-rw-r--r--services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java80
-rw-r--r--services/tests/servicestests/src/com/android/server/am/ActivityLaunchParamsModifierTests.java144
-rw-r--r--services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java14
-rw-r--r--services/tests/servicestests/src/com/android/server/am/ActivityManagerTest.java49
-rw-r--r--services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java54
-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.java96
-rw-r--r--services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java8
-rw-r--r--services/tests/servicestests/src/com/android/server/am/AppErrorDialogTest.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/am/AssistDataRequesterTest.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/am/CoreSettingsObserverTest.java37
-rw-r--r--services/tests/servicestests/src/com/android/server/am/TaskLaunchParamsModifierTests.java1182
-rw-r--r--services/tests/servicestests/src/com/android/server/am/TaskPersisterTest.java52
-rw-r--r--services/tests/servicestests/src/com/android/server/am/TaskRecordTests.java6
-rw-r--r--services/tests/servicestests/src/com/android/server/am/UserControllerTest.java205
-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/DisplayContentTests.java53
-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/TaskPositioningControllerTests.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/WindowManagerServiceRule.java53
-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.java64
-rw-r--r--services/usb/java/com/android/server/usb/UsbSerialReader.java17
-rw-r--r--startop/iorap/TEST_MAPPING12
-rw-r--r--startop/iorap/tests/AndroidTest.xml41
-rw-r--r--startop/iorap/tests/src/com/google/android/startop/iorap/IIorapIntegrationTest.kt6
-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--telephony/java/android/provider/Telephony.java97
-rw-r--r--telephony/java/android/telephony/CarrierConfigManager.java41
-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/PhoneStateListener.java28
-rw-r--r--telephony/java/android/telephony/RcsManager.java52
-rw-r--r--telephony/java/android/telephony/ServiceState.java158
-rw-r--r--telephony/java/android/telephony/SubscriptionManager.java72
-rw-r--r--telephony/java/android/telephony/TelephonyManager.java268
-rw-r--r--telephony/java/android/telephony/data/ApnSetting.java26
-rw-r--r--telephony/java/android/telephony/data/DataProfile.java62
-rw-r--r--telephony/java/android/telephony/emergency/EmergencyNumber.java100
-rw-r--r--telephony/java/android/telephony/ims/ImsExternalCallState.java98
-rw-r--r--telephony/java/android/telephony/ims/ImsMmTelManager.java760
-rw-r--r--telephony/java/android/telephony/ims/aidl/IImsRegistrationCallback.aidl2
-rw-r--r--telephony/java/android/telephony/ims/feature/ImsFeature.java53
-rw-r--r--telephony/java/android/telephony/ims/feature/MmTelFeature.java53
-rw-r--r--telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java58
-rw-r--r--telephony/java/com/android/internal/telephony/DctConstants.java1
-rw-r--r--telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl1
-rw-r--r--telephony/java/com/android/internal/telephony/IRcs.aidl21
-rw-r--r--telephony/java/com/android/internal/telephony/ITelephony.aidl128
-rw-r--r--telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl1
-rw-r--r--telephony/java/com/android/internal/telephony/RILConstants.java1
-rw-r--r--telephony/java/com/android/internal/telephony/TelephonyPermissions.java60
-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/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java29
-rw-r--r--tests/NetworkSecurityConfigTest/Android.mk1
-rw-r--r--tests/net/Android.mk6
-rw-r--r--tests/net/java/android/net/ConnectivityManagerTest.java4
-rw-r--r--tests/net/java/com/android/server/ConnectivityServiceTest.java172
-rw-r--r--tools/aapt2/Android.mk15
-rw-r--r--tools/aapt2/LoadedApk.cpp74
-rw-r--r--tools/aapt2/LoadedApk.h2
-rw-r--r--tools/aapt2/cmd/Convert.cpp22
-rwxr-xr-xtools/hiddenapi/merge_csv.py40
-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
554 files changed, 22330 insertions, 12119 deletions
diff --git a/Android.bp b/Android.bp
index bc5f50fdd42f..571182b6a03f 100755
--- a/Android.bp
+++ b/Android.bp
@@ -561,6 +561,7 @@ java_defaults {
"telephony/java/com/android/internal/telephony/IOnSubscriptionsChangedListener.aidl",
"telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl",
"telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl",
+ "telephony/java/com/android/internal/telephony/IRcs.aidl",
"telephony/java/com/android/internal/telephony/ISms.aidl",
"telephony/java/com/android/internal/telephony/ISub.aidl",
"telephony/java/com/android/internal/telephony/IAns.aidl",
@@ -617,6 +618,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",
@@ -663,6 +665,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",
@@ -685,9 +688,6 @@ java_defaults {
no_framework_libs: true,
libs: [
- "conscrypt",
- "okhttp",
- "bouncycastle",
"ext",
],
@@ -709,6 +709,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
@@ -838,7 +839,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"],
@@ -876,7 +876,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: {
@@ -902,7 +901,6 @@ cc_library {
srcs: [
"core/proto/**/*.proto",
"libs/incident/**/*.proto",
- "proto/src/stats_enums.proto",
],
target: {
@@ -1099,14 +1097,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",
@@ -1186,7 +1183,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",
],
@@ -1226,11 +1224,6 @@ stubs_defaults {
srcs_lib_whitelist_dirs: frameworks_base_subdirs,
srcs_lib_whitelist_pkgs: packages_to_document,
libs: [
- "core-oj",
- "core-libart",
- "conscrypt",
- "bouncycastle",
- "okhttp",
"ext",
"framework",
"voip-common",
@@ -1583,7 +1576,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..770ec20f151e 100755
--- 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) \
@@ -111,6 +113,17 @@ $(INTERNAL_PLATFORM_HIDDENAPI_WHITELIST): \
$(call commit-change-for-toc,$(INTERNAL_PLATFORM_HIDDENAPI_DARK_GREYLIST))
$(call commit-change-for-toc,$(INTERNAL_PLATFORM_HIDDENAPI_BLACKLIST))
+$(INTERNAL_PLATFORM_HIDDENAPI_GREYLIST_METADATA): \
+ frameworks/base/tools/hiddenapi/merge_csv.py \
+ $(PRIVATE_METADATA_INPUTS)
+ frameworks/base/tools/hiddenapi/merge_csv.py $(PRIVATE_METADATA_INPUTS) > $@
+
+$(call dist-for-goals,droidcore,$(INTERNAL_PLATFORM_HIDDENAPI_WHITELIST))
+$(call dist-for-goals,droidcore,$(INTERNAL_PLATFORM_HIDDENAPI_LIGHT_GREYLIST))
+$(call dist-for-goals,droidcore,$(INTERNAL_PLATFORM_HIDDENAPI_DARK_GREYLIST))
+$(call dist-for-goals,droidcore,$(INTERNAL_PLATFORM_HIDDENAPI_BLACKLIST))
+$(call dist-for-goals,droidcore,$(INTERNAL_PLATFORM_HIDDENAPI_GREYLIST_METADATA))
+
# Include subdirectory makefiles
# ============================================================
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index ff40f7543c9d..5c212213f2d1 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -5,6 +5,7 @@ checkstyle_hook = ${REPO_ROOT}/prebuilts/checkstyle/checkstyle.py --sha ${PREUPL
packages/PrintRecommendationService/
packages/PrintSpooler/
packages/PackageInstaller/
+ packages/SystemUI/
services/print/
services/usb/
telephony/
diff --git a/api/current.txt b/api/current.txt
index 3a44d348bedc..1983fb483ecd 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";
@@ -1401,6 +1403,7 @@ package android {
field public static final int textFilterEnabled = 16843007; // 0x10100ff
field public static final int textFontWeight = 16844165; // 0x1010585
field public static final int textIsSelectable = 16843542; // 0x1010316
+ field public static final int textLocale = 16844178; // 0x1010592
field public static final int textOff = 16843045; // 0x1010125
field public static final int textOn = 16843044; // 0x1010124
field public static final int textScaleX = 16843089; // 0x1010151
@@ -6520,6 +6523,8 @@ package android.app.admin {
method public java.util.List<java.lang.String> getDelegatedScopes(android.content.ComponentName, java.lang.String);
method public java.lang.CharSequence getDeviceOwnerLockScreenInfo();
method public java.lang.CharSequence getEndUserSessionMessage(android.content.ComponentName);
+ method public java.lang.String getGlobalPrivateDnsHost(android.content.ComponentName);
+ method public int getGlobalPrivateDnsMode(android.content.ComponentName);
method public java.util.List<byte[]> getInstalledCaCerts(android.content.ComponentName);
method public java.util.List<java.lang.String> getKeepUninstalledPackages(android.content.ComponentName);
method public int getKeyguardDisabledFeatures(android.content.ComponentName);
@@ -6623,6 +6628,7 @@ package android.app.admin {
method public void setDelegatedScopes(android.content.ComponentName, java.lang.String, java.util.List<java.lang.String>);
method public void setDeviceOwnerLockScreenInfo(android.content.ComponentName, java.lang.CharSequence);
method public void setEndUserSessionMessage(android.content.ComponentName, java.lang.CharSequence);
+ method public void setGlobalPrivateDns(android.content.ComponentName, int, java.lang.String);
method public void setGlobalSetting(android.content.ComponentName, java.lang.String, java.lang.String);
method public void setKeepUninstalledPackages(android.content.ComponentName, java.util.List<java.lang.String>);
method public boolean setKeyPairCertificate(android.content.ComponentName, java.lang.String, java.util.List<java.security.cert.Certificate>, boolean);
@@ -6799,6 +6805,10 @@ package android.app.admin {
field public static final int PERMISSION_POLICY_PROMPT = 0; // 0x0
field public static final java.lang.String POLICY_DISABLE_CAMERA = "policy_disable_camera";
field public static final java.lang.String POLICY_DISABLE_SCREEN_CAPTURE = "policy_disable_screen_capture";
+ field public static final int PRIVATE_DNS_MODE_OFF = 1; // 0x1
+ field public static final int PRIVATE_DNS_MODE_OPPORTUNISTIC = 2; // 0x2
+ field public static final int PRIVATE_DNS_MODE_PROVIDER_HOSTNAME = 3; // 0x3
+ field public static final int PRIVATE_DNS_MODE_UNKNOWN = 0; // 0x0
field public static final int RESET_PASSWORD_DO_NOT_ASK_CREDENTIALS_ON_BOOT = 2; // 0x2
field public static final int RESET_PASSWORD_REQUIRE_ENTRY = 1; // 0x1
field public static final int SKIP_SETUP_WIZARD = 1; // 0x1
@@ -9158,6 +9168,7 @@ package android.content {
method public int bulkInsert(android.net.Uri, android.content.ContentValues[]);
method public android.os.Bundle call(java.lang.String, java.lang.String, android.os.Bundle);
method public android.net.Uri canonicalize(android.net.Uri);
+ method public final android.content.ContentProvider.CallingIdentity clearCallingIdentity();
method public abstract int delete(android.net.Uri, java.lang.String, java.lang.String[]);
method public void dump(java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
method public final java.lang.String getCallingPackage();
@@ -9185,6 +9196,7 @@ package android.content {
method public android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, android.os.CancellationSignal);
method public android.database.Cursor query(android.net.Uri, java.lang.String[], android.os.Bundle, android.os.CancellationSignal);
method public boolean refresh(android.net.Uri, android.os.Bundle, android.os.CancellationSignal);
+ method public final void restoreCallingIdentity(android.content.ContentProvider.CallingIdentity);
method protected final void setPathPermissions(android.content.pm.PathPermission[]);
method protected final void setReadPermission(java.lang.String);
method protected final void setWritePermission(java.lang.String);
@@ -9193,6 +9205,9 @@ package android.content {
method public abstract int update(android.net.Uri, android.content.ContentValues, java.lang.String, java.lang.String[]);
}
+ public final class ContentProvider.CallingIdentity {
+ }
+
public static abstract interface ContentProvider.PipeDataWriter<T> {
method public abstract void writeDataToPipe(android.os.ParcelFileDescriptor, android.net.Uri, java.lang.String, android.os.Bundle, T);
}
@@ -9307,6 +9322,7 @@ package android.content {
method public final android.net.Uri insert(android.net.Uri, android.content.ContentValues);
method public static boolean isSyncActive(android.accounts.Account, java.lang.String);
method public static boolean isSyncPending(android.accounts.Account, java.lang.String);
+ method public android.graphics.Bitmap loadThumbnail(android.net.Uri, android.util.Size, android.os.CancellationSignal) throws java.io.IOException;
method public void notifyChange(android.net.Uri, android.database.ContentObserver);
method public void notifyChange(android.net.Uri, android.database.ContentObserver, boolean);
method public void notifyChange(android.net.Uri, android.database.ContentObserver, int);
@@ -15405,6 +15421,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 appendReplacementRun(android.graphics.Paint, int, float);
+ method public android.graphics.text.MeasuredText.Builder appendStyleRun(android.graphics.Paint, 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 {
@@ -25101,6 +25180,7 @@ package android.media {
method public static android.net.Uri getValidRingtoneUri(android.content.Context);
method public int inferStreamType();
method public static boolean isDefault(android.net.Uri);
+ method public static android.content.res.AssetFileDescriptor openDefaultRingtoneUri(android.content.Context, android.net.Uri) throws java.io.FileNotFoundException;
method public static void setActualDefaultRingtoneUri(android.content.Context, int, android.net.Uri);
method public deprecated void setIncludeDrm(boolean);
method public void setStopPreviousRingtone(boolean);
@@ -27373,6 +27453,7 @@ package android.net {
public static class ConnectivityManager.NetworkCallback {
ctor public ConnectivityManager.NetworkCallback();
method public void onAvailable(android.net.Network);
+ method public void onBlockedStatusChanged(android.net.Network, boolean);
method public void onCapabilitiesChanged(android.net.Network, android.net.NetworkCapabilities);
method public void onLinkPropertiesChanged(android.net.Network, android.net.LinkProperties);
method public void onLosing(android.net.Network, int);
@@ -27644,16 +27725,16 @@ package android.net {
public class NetworkInfo implements android.os.Parcelable {
method public int describeContents();
- method public android.net.NetworkInfo.DetailedState getDetailedState();
+ method public deprecated android.net.NetworkInfo.DetailedState getDetailedState();
method public java.lang.String getExtraInfo();
method public deprecated java.lang.String getReason();
method public deprecated android.net.NetworkInfo.State getState();
- method public int getSubtype();
- method public java.lang.String getSubtypeName();
+ method public deprecated int getSubtype();
+ method public deprecated java.lang.String getSubtypeName();
method public deprecated int getType();
method public deprecated java.lang.String getTypeName();
method public deprecated boolean isAvailable();
- method public boolean isConnected();
+ method public deprecated boolean isConnected();
method public deprecated boolean isConnectedOrConnecting();
method public deprecated boolean isFailover();
method public deprecated boolean isRoaming();
@@ -29649,6 +29730,65 @@ package android.opengl {
field public static final int EGL_WINDOW_BIT = 4; // 0x4
}
+ public class EGL15 {
+ ctor public EGL15();
+ method public static int eglClientWaitSync(android.opengl.EGLDisplay, android.opengl.EGLSync, int, long);
+ method public static android.opengl.EGLSurface eglCreatePlatformPixmapSurface(android.opengl.EGLDisplay, android.opengl.EGLConfig, java.nio.Buffer, long[], int);
+ method public static android.opengl.EGLSurface eglCreatePlatformWindowSurface(android.opengl.EGLDisplay, android.opengl.EGLConfig, java.nio.Buffer, long[], int);
+ method public static android.opengl.EGLSync eglCreateSync(android.opengl.EGLDisplay, int, long[], int);
+ method public static boolean eglDestroySync(android.opengl.EGLDisplay, android.opengl.EGLSync);
+ method public static android.opengl.EGLDisplay eglGetPlatformDisplay(int, long, long[], int);
+ method public static boolean eglGetSyncAttrib(android.opengl.EGLDisplay, android.opengl.EGLSync, int, long[], int);
+ method public static boolean eglWaitSync(android.opengl.EGLDisplay, android.opengl.EGLSync, int);
+ field public static final int EGL_CL_EVENT_HANDLE = 12444; // 0x309c
+ field public static final int EGL_CONDITION_SATISFIED = 12534; // 0x30f6
+ field public static final int EGL_CONTEXT_MAJOR_VERSION = 12440; // 0x3098
+ field public static final int EGL_CONTEXT_MINOR_VERSION = 12539; // 0x30fb
+ field public static final int EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT = 2; // 0x2
+ field public static final int EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT = 1; // 0x1
+ field public static final int EGL_CONTEXT_OPENGL_DEBUG = 12720; // 0x31b0
+ field public static final int EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE = 12721; // 0x31b1
+ field public static final int EGL_CONTEXT_OPENGL_PROFILE_MASK = 12541; // 0x30fd
+ field public static final int EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY = 12733; // 0x31bd
+ field public static final int EGL_CONTEXT_OPENGL_ROBUST_ACCESS = 12722; // 0x31b2
+ field public static final long EGL_FOREVER = -1L; // 0xffffffffffffffffL
+ field public static final int EGL_GL_COLORSPACE = 12445; // 0x309d
+ field public static final int EGL_GL_COLORSPACE_LINEAR = 12426; // 0x308a
+ field public static final int EGL_GL_COLORSPACE_SRGB = 12425; // 0x3089
+ field public static final int EGL_GL_RENDERBUFFER = 12473; // 0x30b9
+ field public static final int EGL_GL_TEXTURE_2D = 12465; // 0x30b1
+ field public static final int EGL_GL_TEXTURE_3D = 12466; // 0x30b2
+ field public static final int EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X = 12468; // 0x30b4
+ field public static final int EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y = 12470; // 0x30b6
+ field public static final int EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z = 12472; // 0x30b8
+ field public static final int EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X = 12467; // 0x30b3
+ field public static final int EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y = 12469; // 0x30b5
+ field public static final int EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z = 12471; // 0x30b7
+ field public static final int EGL_GL_TEXTURE_LEVEL = 12476; // 0x30bc
+ field public static final int EGL_GL_TEXTURE_ZOFFSET = 12477; // 0x30bd
+ field public static final int EGL_IMAGE_PRESERVED = 12498; // 0x30d2
+ field public static final int EGL_LOSE_CONTEXT_ON_RESET = 12735; // 0x31bf
+ field public static final android.opengl.EGLContext EGL_NO_CONTEXT;
+ field public static final android.opengl.EGLDisplay EGL_NO_DISPLAY;
+ field public static final android.opengl.EGLImage EGL_NO_IMAGE;
+ field public static final int EGL_NO_RESET_NOTIFICATION = 12734; // 0x31be
+ field public static final android.opengl.EGLSurface EGL_NO_SURFACE;
+ field public static final android.opengl.EGLSync EGL_NO_SYNC;
+ field public static final int EGL_OPENGL_ES3_BIT = 64; // 0x40
+ field public static final int EGL_PLATFORM_ANDROID_KHR = 12609; // 0x3141
+ field public static final int EGL_SIGNALED = 12530; // 0x30f2
+ field public static final int EGL_SYNC_CL_EVENT = 12542; // 0x30fe
+ field public static final int EGL_SYNC_CL_EVENT_COMPLETE = 12543; // 0x30ff
+ field public static final int EGL_SYNC_CONDITION = 12536; // 0x30f8
+ field public static final int EGL_SYNC_FENCE = 12537; // 0x30f9
+ field public static final int EGL_SYNC_FLUSH_COMMANDS_BIT = 1; // 0x1
+ field public static final int EGL_SYNC_PRIOR_COMMANDS_COMPLETE = 12528; // 0x30f0
+ field public static final int EGL_SYNC_STATUS = 12529; // 0x30f1
+ field public static final int EGL_SYNC_TYPE = 12535; // 0x30f7
+ field public static final int EGL_TIMEOUT_EXPIRED = 12533; // 0x30f5
+ field public static final int EGL_UNSIGNALED = 12531; // 0x30f3
+ }
+
public class EGLConfig extends android.opengl.EGLObjectHandle {
}
@@ -29668,6 +29808,9 @@ package android.opengl {
field public static final int EGL_RECORDABLE_ANDROID = 12610; // 0x3142
}
+ public class EGLImage extends android.opengl.EGLObjectHandle {
+ }
+
public abstract class EGLObjectHandle {
ctor protected deprecated EGLObjectHandle(int);
ctor protected EGLObjectHandle(long);
@@ -29678,6 +29821,9 @@ package android.opengl {
public class EGLSurface extends android.opengl.EGLObjectHandle {
}
+ public class EGLSync extends android.opengl.EGLObjectHandle {
+ }
+
public class ETC1 {
ctor public ETC1();
method public static void decodeBlock(java.nio.Buffer, java.nio.Buffer);
@@ -32540,7 +32686,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;
@@ -32571,9 +32717,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";
}
@@ -33739,6 +33885,7 @@ package android.os {
field public static final java.lang.String DISALLOW_CONFIG_LOCALE = "no_config_locale";
field public static final java.lang.String DISALLOW_CONFIG_LOCATION = "no_config_location";
field public static final java.lang.String DISALLOW_CONFIG_MOBILE_NETWORKS = "no_config_mobile_networks";
+ field public static final java.lang.String DISALLOW_CONFIG_PRIVATE_DNS = "disallow_config_private_dns";
field public static final java.lang.String DISALLOW_CONFIG_SCREEN_TIMEOUT = "no_config_screen_timeout";
field public static final java.lang.String DISALLOW_CONFIG_TETHERING = "no_config_tethering";
field public static final java.lang.String DISALLOW_CONFIG_VPN = "no_config_vpn";
@@ -36671,7 +36818,7 @@ package android.provider {
public static abstract interface MediaStore.Audio.AlbumColumns {
field public static final java.lang.String ALBUM = "album";
- field public static final java.lang.String ALBUM_ART = "album_art";
+ field public static final deprecated java.lang.String ALBUM_ART = "album_art";
field public static final java.lang.String ALBUM_ID = "album_id";
field public static final java.lang.String ALBUM_KEY = "album_key";
field public static final java.lang.String ARTIST = "artist";
@@ -36793,7 +36940,7 @@ package android.provider {
}
public static abstract interface MediaStore.Audio.PlaylistsColumns {
- field public static final java.lang.String DATA = "_data";
+ field public static final deprecated java.lang.String DATA = "_data";
field public static final java.lang.String DATE_ADDED = "date_added";
field public static final java.lang.String DATE_MODIFIED = "date_modified";
field public static final java.lang.String NAME = "name";
@@ -36855,15 +37002,15 @@ package android.provider {
public static class MediaStore.Images.Thumbnails implements android.provider.BaseColumns {
ctor public MediaStore.Images.Thumbnails();
- method public static void cancelThumbnailRequest(android.content.ContentResolver, long);
- method public static void cancelThumbnailRequest(android.content.ContentResolver, long, long);
+ method public static deprecated void cancelThumbnailRequest(android.content.ContentResolver, long);
+ method public static deprecated void cancelThumbnailRequest(android.content.ContentResolver, long, long);
method public static android.net.Uri getContentUri(java.lang.String);
- method public static android.graphics.Bitmap getThumbnail(android.content.ContentResolver, long, int, android.graphics.BitmapFactory.Options);
- method public static android.graphics.Bitmap getThumbnail(android.content.ContentResolver, long, long, int, android.graphics.BitmapFactory.Options);
+ method public static deprecated android.graphics.Bitmap getThumbnail(android.content.ContentResolver, long, int, android.graphics.BitmapFactory.Options);
+ method public static deprecated android.graphics.Bitmap getThumbnail(android.content.ContentResolver, long, long, int, android.graphics.BitmapFactory.Options);
method public static final android.database.Cursor query(android.content.ContentResolver, android.net.Uri, java.lang.String[]);
method public static final android.database.Cursor queryMiniThumbnail(android.content.ContentResolver, long, int, java.lang.String[]);
method public static final android.database.Cursor queryMiniThumbnails(android.content.ContentResolver, android.net.Uri, int, java.lang.String[]);
- field public static final java.lang.String DATA = "_data";
+ field public static final deprecated java.lang.String DATA = "_data";
field public static final java.lang.String DEFAULT_SORT_ORDER = "image_id ASC";
field public static final android.net.Uri EXTERNAL_CONTENT_URI;
field public static final int FULL_SCREEN_KIND = 2; // 0x2
@@ -36878,7 +37025,7 @@ package android.provider {
}
public static abstract interface MediaStore.MediaColumns implements android.provider.BaseColumns {
- field public static final java.lang.String DATA = "_data";
+ field public static final deprecated java.lang.String DATA = "_data";
field public static final java.lang.String DATE_ADDED = "date_added";
field public static final java.lang.String DATE_MODIFIED = "date_modified";
field public static final java.lang.String DISPLAY_NAME = "_display_name";
@@ -36906,12 +37053,12 @@ package android.provider {
public static class MediaStore.Video.Thumbnails implements android.provider.BaseColumns {
ctor public MediaStore.Video.Thumbnails();
- method public static void cancelThumbnailRequest(android.content.ContentResolver, long);
- method public static void cancelThumbnailRequest(android.content.ContentResolver, long, long);
+ method public static deprecated void cancelThumbnailRequest(android.content.ContentResolver, long);
+ method public static deprecated void cancelThumbnailRequest(android.content.ContentResolver, long, long);
method public static android.net.Uri getContentUri(java.lang.String);
- method public static android.graphics.Bitmap getThumbnail(android.content.ContentResolver, long, int, android.graphics.BitmapFactory.Options);
- method public static android.graphics.Bitmap getThumbnail(android.content.ContentResolver, long, long, int, android.graphics.BitmapFactory.Options);
- field public static final java.lang.String DATA = "_data";
+ method public static deprecated android.graphics.Bitmap getThumbnail(android.content.ContentResolver, long, int, android.graphics.BitmapFactory.Options);
+ method public static deprecated android.graphics.Bitmap getThumbnail(android.content.ContentResolver, long, long, int, android.graphics.BitmapFactory.Options);
+ field public static final deprecated java.lang.String DATA = "_data";
field public static final java.lang.String DEFAULT_SORT_ORDER = "video_id ASC";
field public static final android.net.Uri EXTERNAL_CONTENT_URI;
field public static final int FULL_SCREEN_KIND = 2; // 0x2
@@ -42968,6 +43115,7 @@ 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,6 +43136,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 = -1; // 0xffffffff
field public static final int INVALID_SUBSCRIPTION_ID = -1; // 0xffffffff
}
@@ -43323,7 +43472,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
@@ -43362,7 +43511,8 @@ package android.telephony.data {
package android.telephony.emergency {
- public final class EmergencyNumber implements android.os.Parcelable {
+ public final class EmergencyNumber implements java.lang.Comparable android.os.Parcelable {
+ method public int compareTo(android.telephony.emergency.EmergencyNumber);
method public int describeContents();
method public java.lang.String getCountryIso();
method public int getEmergencyNumberSourceBitmask();
@@ -44319,6 +44469,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);
@@ -44330,6 +44481,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 {
@@ -44928,6 +45082,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);
}
@@ -45108,6 +45272,7 @@ package android.text.style {
method public int getSpanTypeId();
method public android.content.res.ColorStateList getTextColor();
method public int getTextFontWeight();
+ method public android.os.LocaleList getTextLocales();
method public int getTextSize();
method public int getTextStyle();
method public android.graphics.Typeface getTypeface();
@@ -48025,6 +48190,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
@@ -50007,6 +50173,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();
@@ -50097,6 +50264,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);
@@ -50223,6 +50391,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);
@@ -51246,6 +51424,7 @@ package android.view.textclassifier {
method public default android.view.textclassifier.TextClassification classifyText(android.view.textclassifier.TextClassification.Request);
method public default android.view.textclassifier.TextClassification classifyText(java.lang.CharSequence, int, int, android.os.LocaleList);
method public default void destroy();
+ method public default android.view.textclassifier.TextLanguage detectLanguage(android.view.textclassifier.TextLanguage.Request);
method public default android.view.textclassifier.TextLinks generateLinks(android.view.textclassifier.TextLinks.Request);
method public default int getMaxGenerateLinksTextLength();
method public default boolean isDestroyed();
@@ -51286,6 +51465,39 @@ package android.view.textclassifier {
field public static final android.os.Parcelable.Creator<android.view.textclassifier.TextClassifier.EntityConfig> CREATOR;
}
+ public final class TextLanguage implements android.os.Parcelable {
+ method public int describeContents();
+ method public float getConfidenceScore(android.icu.util.ULocale);
+ method public android.os.Bundle getExtras();
+ method public java.lang.String getId();
+ method public android.icu.util.ULocale getLocale(int);
+ method public int getLocaleHypothesisCount();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.view.textclassifier.TextLanguage> CREATOR;
+ }
+
+ public static final class TextLanguage.Builder {
+ ctor public TextLanguage.Builder();
+ method public android.view.textclassifier.TextLanguage build();
+ method public android.view.textclassifier.TextLanguage.Builder putLocale(android.icu.util.ULocale, float);
+ method public android.view.textclassifier.TextLanguage.Builder setExtras(android.os.Bundle);
+ method public android.view.textclassifier.TextLanguage.Builder setId(java.lang.String);
+ }
+
+ public static final class TextLanguage.Request implements android.os.Parcelable {
+ method public int describeContents();
+ method public android.os.Bundle getExtras();
+ method public java.lang.CharSequence getText();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.view.textclassifier.TextLanguage.Request> CREATOR;
+ }
+
+ public static final class TextLanguage.Request.Builder {
+ ctor public TextLanguage.Request.Builder(java.lang.CharSequence);
+ method public android.view.textclassifier.TextLanguage.Request build();
+ method public android.view.textclassifier.TextLanguage.Request.Builder setExtras(android.os.Bundle);
+ }
+
public final class TextLinks implements android.os.Parcelable {
method public int apply(android.text.Spannable, int, java.util.function.Function<android.view.textclassifier.TextLinks.TextLink, android.view.textclassifier.TextLinks.TextLinkSpan>);
method public int describeContents();
@@ -52206,6 +52418,7 @@ package android.webkit {
field public static final int ERROR_UNSAFE_RESOURCE = -16; // 0xfffffff0
field public static final int ERROR_UNSUPPORTED_AUTH_SCHEME = -3; // 0xfffffffd
field public static final int ERROR_UNSUPPORTED_SCHEME = -10; // 0xfffffff6
+ field public static final int SAFE_BROWSING_THREAT_BILLING = 4; // 0x4
field public static final int SAFE_BROWSING_THREAT_MALWARE = 1; // 0x1
field public static final int SAFE_BROWSING_THREAT_PHISHING = 2; // 0x2
field public static final int SAFE_BROWSING_THREAT_UNKNOWN = 0; // 0x0
diff --git a/api/system-current.txt b/api/system-current.txt
index a99e2567aa22..8d0b71d5d3a6 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 {
@@ -1011,7 +1012,6 @@ package android.content {
field public static final java.lang.String EXTRA_REMOTE_CALLBACK = "android.intent.extra.REMOTE_CALLBACK";
field public static final java.lang.String EXTRA_RESULT_NEEDED = "android.intent.extra.RESULT_NEEDED";
field public static final java.lang.String EXTRA_UNKNOWN_INSTANT_APP = "android.intent.extra.UNKNOWN_INSTANT_APP";
- field public static final java.lang.String EXTRA_USER_ID = "android.intent.extra.USER_ID";
field public static final java.lang.String EXTRA_VERIFICATION_BUNDLE = "android.intent.extra.VERIFICATION_BUNDLE";
}
@@ -1121,9 +1121,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 +1150,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 +1245,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 +1297,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 +3198,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);
@@ -4136,7 +4146,6 @@ package android.os {
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();
@@ -4201,8 +4210,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();
}
@@ -4462,6 +4471,23 @@ package android.provider {
field public static final java.lang.String VOLUME_HUSH_GESTURE = "volume_hush_gesture";
}
+ public static final class Telephony.Carriers implements android.provider.BaseColumns {
+ field public static final java.lang.String APN_SET_ID = "apn_set_id";
+ field public static final int CARRIER_EDITED = 4; // 0x4
+ field public static final java.lang.String EDITED = "edited";
+ field public static final java.lang.String MAX_CONNS = "max_conns";
+ field public static final java.lang.String MAX_CONNS_TIME = "max_conns_time";
+ field public static final java.lang.String MODEM_COGNITIVE = "modem_cognitive";
+ field public static final java.lang.String MTU = "mtu";
+ field public static final int NO_SET_SET = 0; // 0x0
+ field public static final int UNEDITED = 0; // 0x0
+ field public static final int USER_DELETED = 2; // 0x2
+ field public static final java.lang.String USER_EDITABLE = "user_editable";
+ field public static final int USER_EDITED = 1; // 0x1
+ field public static final java.lang.String USER_VISIBLE = "user_visible";
+ field public static final java.lang.String WAIT_TIME = "wait_time";
+ }
+
public final class TimeZoneRulesDataContract {
field public static final java.lang.String AUTHORITY = "com.android.timezone";
}
@@ -5287,6 +5313,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
@@ -5329,6 +5356,11 @@ package android.telephony {
field public static final int RESULT_SUCCESS = 0; // 0x0
}
+ public class PhoneStateListener {
+ method public void onRadioPowerStateChanged(int);
+ field public static final int LISTEN_RADIO_POWER_STATE_CHANGED = 8388608; // 0x800000
+ }
+
public class ServiceState implements android.os.Parcelable {
method public android.telephony.NetworkRegistrationState getNetworkRegistrationState(int, int);
method public java.util.List<android.telephony.NetworkRegistrationState> getNetworkRegistrationStates();
@@ -5374,6 +5406,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 {
@@ -5454,6 +5488,7 @@ package android.telephony {
method public boolean getEmergencyCallbackMode();
method public java.lang.String getIsimDomain();
method public int getPreferredNetworkType(int);
+ method public int getRadioPowerState();
method public int getSimApplicationState();
method public int getSimCardState();
method public java.util.List<android.telephony.TelephonyHistogram> getTelephonyHistograms();
@@ -5468,6 +5503,7 @@ package android.telephony {
method public deprecated boolean isVisualVoicemailEnabled(android.telecom.PhoneAccountHandle);
method public boolean needsOtaServiceProvisioning();
method public int setAllowedCarriers(int, java.util.List<android.service.carrier.CarrierIdentifier>);
+ method public void setCarrierDataEnabled(boolean);
method public void setDataActivationState(int);
method public deprecated void setDataEnabled(int, boolean);
method public void setDataRoamingEnabled(boolean);
@@ -5517,6 +5553,9 @@ package android.telephony {
field public static final int NETWORK_MODE_TDSCDMA_WCDMA = 14; // 0xe
field public static final int NETWORK_MODE_WCDMA_ONLY = 2; // 0x2
field public static final int NETWORK_MODE_WCDMA_PREF = 0; // 0x0
+ field public static final int RADIO_POWER_OFF = 0; // 0x0
+ field public static final int RADIO_POWER_ON = 1; // 0x1
+ field public static final int RADIO_POWER_UNAVAILABLE = 2; // 0x2
field public static final int SIM_ACTIVATION_STATE_ACTIVATED = 2; // 0x2
field public static final int SIM_ACTIVATION_STATE_ACTIVATING = 1; // 0x1
field public static final int SIM_ACTIVATION_STATE_DEACTIVATED = 3; // 0x3
@@ -5583,17 +5622,12 @@ package android.telephony.data {
}
public final class DataProfile implements android.os.Parcelable {
- ctor public DataProfile(int, java.lang.String, java.lang.String, int, java.lang.String, java.lang.String, int, int, int, int, boolean, int, java.lang.String, int, int, java.lang.String, java.lang.String, boolean);
- ctor public DataProfile(android.os.Parcel);
- method public int describeContents();
method public java.lang.String getApn();
method public int getAuthType();
method public int getBearerBitmap();
method public int getMaxConns();
method public int getMaxConnsTime();
method public int getMtu();
- method public java.lang.String getMvnoMatchData();
- method public java.lang.String getMvnoType();
method public java.lang.String getPassword();
method public int getProfileId();
method public java.lang.String getProtocol();
@@ -5603,9 +5637,8 @@ package android.telephony.data {
method public java.lang.String getUserName();
method public int getWaitTime();
method public boolean isEnabled();
- method public boolean isModemCognitive();
- method public void writeToParcel(android.os.Parcel, int);
- field public static final android.os.Parcelable.Creator<android.telephony.data.DataProfile> CREATOR;
+ method public boolean isPersistent();
+ method public boolean isPreferred();
field public static final int TYPE_3GPP = 1; // 0x1
field public static final int TYPE_3GPP2 = 2; // 0x2
field public static final int TYPE_COMMON = 0; // 0x0
@@ -5932,11 +5965,13 @@ package android.telephony.ims {
}
public final class ImsExternalCallState implements android.os.Parcelable {
+ ctor public ImsExternalCallState(java.lang.String, android.net.Uri, android.net.Uri, boolean, int, int, boolean);
method public int describeContents();
method public android.net.Uri getAddress();
method public int getCallId();
method public int getCallState();
method public int getCallType();
+ method public android.net.Uri getLocalAddress();
method public boolean isCallHeld();
method public boolean isCallPullable();
method public void writeToParcel(android.os.Parcel, int);
@@ -6356,7 +6391,8 @@ package android.telephony.ims.feature {
}
public static class MmTelFeature.MmTelCapabilities {
- ctor public MmTelFeature.MmTelCapabilities(android.telephony.ims.feature.ImsFeature.Capabilities);
+ ctor public MmTelFeature.MmTelCapabilities();
+ ctor public deprecated MmTelFeature.MmTelCapabilities(android.telephony.ims.feature.ImsFeature.Capabilities);
ctor public MmTelFeature.MmTelCapabilities(int);
method public final void addCapabilities(int);
method public final boolean isCapable(int);
@@ -6655,7 +6691,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 {
@@ -6665,7 +6701,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/system-removed.txt b/api/system-removed.txt
index 22465621e693..4e7a11444548 100644
--- a/api/system-removed.txt
+++ b/api/system-removed.txt
@@ -91,38 +91,6 @@ package android.os {
}
-package android.security.keystore.recovery {
-
- public final class KeyChainSnapshot implements android.os.Parcelable {
- method public deprecated byte[] getTrustedHardwarePublicKey();
- }
-
- public class RecoveryController {
- method public deprecated byte[] generateAndStoreKey(java.lang.String, byte[]) throws android.security.keystore.recovery.InternalRecoveryServiceException, android.security.keystore.recovery.LockScreenRequiredException;
- method public deprecated java.security.Key generateKey(java.lang.String, byte[]) throws android.security.keystore.recovery.InternalRecoveryServiceException, android.security.keystore.recovery.LockScreenRequiredException;
- method public deprecated java.util.List<java.lang.String> getAliases(java.lang.String) throws android.security.keystore.recovery.InternalRecoveryServiceException;
- method public deprecated android.security.keystore.recovery.KeyChainSnapshot getRecoveryData() throws android.security.keystore.recovery.InternalRecoveryServiceException;
- method public deprecated int getRecoveryStatus(java.lang.String, java.lang.String) throws android.security.keystore.recovery.InternalRecoveryServiceException;
- method public deprecated void initRecoveryService(java.lang.String, byte[]) throws java.security.cert.CertificateException, android.security.keystore.recovery.InternalRecoveryServiceException;
- method public deprecated void setRecoveryStatus(java.lang.String, java.lang.String, int) throws android.security.keystore.recovery.InternalRecoveryServiceException, android.content.pm.PackageManager.NameNotFoundException;
- }
-
- public class RecoverySession implements java.lang.AutoCloseable {
- method public deprecated java.util.Map<java.lang.String, byte[]> recoverKeys(byte[], java.util.List<android.security.keystore.recovery.WrappedApplicationKey>) throws android.security.keystore.recovery.DecryptionFailedException, android.security.keystore.recovery.InternalRecoveryServiceException, android.security.keystore.recovery.SessionExpiredException;
- method public deprecated byte[] start(byte[], byte[], byte[], java.util.List<android.security.keystore.recovery.KeyChainProtectionParams>) throws java.security.cert.CertificateException, android.security.keystore.recovery.InternalRecoveryServiceException;
- method public deprecated byte[] start(java.security.cert.CertPath, byte[], byte[], java.util.List<android.security.keystore.recovery.KeyChainProtectionParams>) throws java.security.cert.CertificateException, android.security.keystore.recovery.InternalRecoveryServiceException;
- }
-
- public final class WrappedApplicationKey implements android.os.Parcelable {
- method public deprecated byte[] getAccount();
- }
-
- public static class WrappedApplicationKey.Builder {
- method public deprecated android.security.keystore.recovery.WrappedApplicationKey.Builder setAccount(byte[]);
- }
-
-}
-
package android.service.notification {
public abstract class NotificationListenerService extends android.app.Service {
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/Android.mk b/cmds/statsd/Android.mk
index f6b0db80f3ad..5818f5d550c3 100644
--- a/cmds/statsd/Android.mk
+++ b/cmds/statsd/Android.mk
@@ -46,6 +46,7 @@ statsd_common_src := \
src/logd/LogEvent.cpp \
src/logd/LogListener.cpp \
src/matchers/CombinationLogMatchingTracker.cpp \
+ src/matchers/EventMatcherWizard.cpp \
src/matchers/matcher_util.cpp \
src/matchers/SimpleLogMatchingTracker.cpp \
src/metrics/MetricProducer.cpp \
@@ -189,6 +190,7 @@ LOCAL_SRC_FILES := \
src/atom_field_options.proto \
src/atoms.proto \
src/stats_log.proto \
+ src/shell/shell_data.proto \
tests/AlarmMonitor_test.cpp \
tests/anomaly/AlarmTracker_test.cpp \
tests/anomaly/AnomalyTracker_test.cpp \
@@ -216,6 +218,7 @@ LOCAL_SRC_FILES := \
tests/metrics/metrics_test_helper.cpp \
tests/statsd_test_util.cpp \
tests/e2e/WakelockDuration_e2e_test.cpp \
+ tests/e2e/MetricActivation_e2e_test.cpp \
tests/e2e/MetricConditionLink_e2e_test.cpp \
tests/e2e/Alarm_e2e_test.cpp \
tests/e2e/Attribution_e2e_test.cpp \
diff --git a/cmds/statsd/src/StatsLogProcessor.h b/cmds/statsd/src/StatsLogProcessor.h
index 4091d951ba06..3e8b9b8d5df5 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 {
@@ -193,7 +194,7 @@ private:
FRIEND_TEST(GaugeMetricE2eTest, TestMultipleFieldsForPushedEvent);
FRIEND_TEST(GaugeMetricE2eTest, TestRandomSamplePulledEvents);
FRIEND_TEST(GaugeMetricE2eTest, TestRandomSamplePulledEvent_LateAlarm);
- FRIEND_TEST(GaugeMetricE2eTest, TestAllConditionChangesSamplePulledEvents);
+ FRIEND_TEST(GaugeMetricE2eTest, TestConditionChangeToTrueSamplePulledEvents);
FRIEND_TEST(ValueMetricE2eTest, TestPulledEvents);
FRIEND_TEST(ValueMetricE2eTest, TestPulledEvents_LateAlarm);
@@ -218,6 +219,7 @@ private:
FRIEND_TEST(AlarmE2eTest, TestMultipleAlarms);
FRIEND_TEST(ConfigTtlE2eTest, TestCountMetric);
+ FRIEND_TEST(MetricActivationE2eTest, TestCountMetric);
};
} // namespace statsd
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index 8da2d447a163..ce2877731882 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -319,7 +319,7 @@ status_t StatsService::command(int in, int out, int err, Vector<String8>& args,
}
if (!args[0].compare(String8("data-subscribe"))) {
if (mShellSubscriber == nullptr) {
- mShellSubscriber = new ShellSubscriber(mUidMap);
+ mShellSubscriber = new ShellSubscriber(mUidMap, mPullerManager);
}
mShellSubscriber->startNewSubscription(in, out, resultReceiver);
return NO_ERROR;
@@ -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..10ad1208d20d 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,10 +141,12 @@ 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.
- // Next: 10025
+ // Next: 10037
oneof pulled {
WifiBytesTransfer wifi_bytes_transfer = 10000;
WifiBytesTransferByFgBg wifi_bytes_transfer_by_fg_bg = 10001;
@@ -182,6 +183,8 @@ message Atom {
DiskIo disk_io = 10032;
PowerProfile power_profile = 10033;
ProcStats proc_stats_pkg_proc = 10034;
+ ProcessCpuTime process_cpu_time = 10035;
+ NativeProcessMemoryState native_process_memory_state = 10036;
}
// DO NOT USE field numbers above 100,000 in AOSP.
@@ -273,7 +276,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 +287,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 +322,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 +341,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 +640,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 +1033,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 +1054,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 +1073,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 +1081,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 +1109,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 +1196,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 +1345,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 +1409,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 +1873,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 +1916,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 +1942,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 +1953,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 +2184,7 @@ message KernelWakelock {
optional int32 version = 3;
- optional int64 time = 4;
+ optional int64 time_micros = 4;
}
/**
@@ -2218,11 +2248,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 +2264,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 +2301,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 +2322,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;
@@ -2316,6 +2346,31 @@ message ProcessMemoryState {
}
/*
+ * Logs the memory stats for a native process (from procfs).
+ */
+message NativeProcessMemoryState {
+ // The uid if available. -1 means not available.
+ optional int32 uid = 1 [(is_uid) = true];
+
+ // The process name.
+ optional string process_name = 2;
+
+ // # of page-faults
+ optional int64 page_fault = 3;
+
+ // # of major page-faults
+ optional int64 page_major_fault = 4;
+
+ // RSS
+ optional int64 rss_in_bytes = 5;
+
+ // RSS high watermark.
+ // Peak RSS usage of the process. Value is read from the VmHWM field in /proc/PID/status or
+ // from memory.max_usage_in_bytes under /dev/memcg if the device uses per-app memory cgroups.
+ optional int64 rss_high_watermark_in_bytes = 6;
+}
+
+/*
* Elapsed real time from SystemClock.
*/
message SystemElapsedRealtime {
@@ -2380,7 +2435,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 +2444,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 +2454,7 @@ message FullBatteryCapacity {
*/
message BatteryVoltage {
// The voltage of the battery, in millivolts.
- optional int32 voltage_mV = 1;
+ optional int32 voltage_millivolt = 1;
}
/**
@@ -2417,7 +2472,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 +2582,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 +2598,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 +2742,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 +3031,21 @@ 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;
+}
+
+/**
+ * Pulls process user time and system time. Puller takes a snapshot of all pids
+ * in the system and returns cpu stats for those that are working at the time.
+ * Dead pids will be dropped. Kernel processes are excluded.
+ * Min cool-down is 5 sec.
+ */
+message ProcessCpuTime {
+ optional int32 uid = 1 [(is_uid) = true];
+
+ optional string process_name = 2;
+ // Process cpu time in user space, cumulative from boot/process start
+ optional int64 user_time_millis = 3;
+ // Process cpu time in system space, cumulative from boot/process start
+ optional int64 system_time_millis = 4;
+}
diff --git a/cmds/statsd/src/external/StatsPullerManager.cpp b/cmds/statsd/src/external/StatsPullerManager.cpp
index dab64cacb679..8871d4d054c5 100644
--- a/cmds/statsd/src/external/StatsPullerManager.cpp
+++ b/cmds/statsd/src/external/StatsPullerManager.cpp
@@ -170,6 +170,12 @@ const std::map<int, PullAtomInfo> StatsPullerManager::kAllPullAtomInfo = {
{2, 3},
1 * NS_PER_SEC,
new StatsCompanionServicePuller(android::util::PROCESS_MEMORY_STATE)}},
+ // native_process_memory_state
+ {android::util::NATIVE_PROCESS_MEMORY_STATE,
+ {{3, 4, 5, 6},
+ {2},
+ 1 * NS_PER_SEC,
+ new StatsCompanionServicePuller(android::util::NATIVE_PROCESS_MEMORY_STATE)}},
// temperature
{android::util::TEMPERATURE, {{}, {}, 1 * NS_PER_SEC, new ResourceThermalManagerPuller()}},
// binder_calls
@@ -223,6 +229,9 @@ const std::map<int, PullAtomInfo> StatsPullerManager::kAllPullAtomInfo = {
// PowerProfile constants for power model calculations.
{android::util::POWER_PROFILE,
{{}, {}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::POWER_PROFILE)}},
+ // Process cpu stats. Min cool-down is 5 sec, inline with what AcitivityManagerService uses.
+ {android::util::PROCESS_CPU_TIME,
+ {{}, {}, 5 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::PROCESS_CPU_TIME)}},
};
StatsPullerManager::StatsPullerManager() : mNextPullTimeNs(NO_ALARM_UPDATE) {
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/matchers/EventMatcherWizard.cpp b/cmds/statsd/src/matchers/EventMatcherWizard.cpp
new file mode 100644
index 000000000000..8418e9833509
--- /dev/null
+++ b/cmds/statsd/src/matchers/EventMatcherWizard.cpp
@@ -0,0 +1,38 @@
+/*
+ * 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 "EventMatcherWizard.h"
+#include <unordered_set>
+
+namespace android {
+namespace os {
+namespace statsd {
+
+using std::map;
+using std::string;
+using std::vector;
+
+MatchingState EventMatcherWizard::matchLogEvent(const LogEvent& event, int matcher_index) {
+ if (matcher_index < 0 || matcher_index >= (int)mAllEventMatchers.size()) {
+ return MatchingState::kNotComputed;
+ }
+ vector<MatchingState> matcherCache(mAllEventMatchers.size(), MatchingState::kNotComputed);
+ mAllEventMatchers[matcher_index]->onLogEvent(event, mAllEventMatchers, matcherCache);
+ return matcherCache[matcher_index];
+}
+
+} // namespace statsd
+} // namespace os
+} // namespace android \ No newline at end of file
diff --git a/cmds/statsd/src/matchers/EventMatcherWizard.h b/cmds/statsd/src/matchers/EventMatcherWizard.h
new file mode 100644
index 000000000000..57ec2b35ba32
--- /dev/null
+++ b/cmds/statsd/src/matchers/EventMatcherWizard.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "LogMatchingTracker.h"
+
+namespace android {
+namespace os {
+namespace statsd {
+
+class EventMatcherWizard : public virtual android::RefBase {
+public:
+ EventMatcherWizard(){}; // for testing
+ EventMatcherWizard(const std::vector<sp<LogMatchingTracker>>& eventTrackers)
+ : mAllEventMatchers(eventTrackers){};
+
+ virtual ~EventMatcherWizard(){};
+
+ MatchingState matchLogEvent(const LogEvent& event, int matcher_index);
+
+private:
+ std::vector<sp<LogMatchingTracker>> mAllEventMatchers;
+};
+
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
index 02b97734d3ff..f5a16e96fdf5 100644
--- a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
@@ -69,11 +69,16 @@ const int FIELD_ID_END_BUCKET_ELAPSED_MILLIS = 8;
GaugeMetricProducer::GaugeMetricProducer(const ConfigKey& key, const GaugeMetric& metric,
const int conditionIndex,
- const sp<ConditionWizard>& wizard, const int pullTagId,
+ const sp<ConditionWizard>& wizard,
+ const int whatMatcherIndex,
+ const sp<EventMatcherWizard>& matcherWizard,
+ const int pullTagId,
const int triggerAtomId, const int atomId,
const int64_t timeBaseNs, const int64_t startTimeNs,
const sp<StatsPullerManager>& pullerManager)
: MetricProducer(metric.id(), key, timeBaseNs, conditionIndex, wizard),
+ mWhatMatcherIndex(whatMatcherIndex),
+ mEventMatcherWizard(matcherWizard),
mPullerManager(pullerManager),
mPullTagId(pullTagId),
mTriggerAtomId(triggerAtomId),
@@ -136,7 +141,7 @@ GaugeMetricProducer::GaugeMetricProducer(const ConfigKey& key, const GaugeMetric
// Adjust start for partial bucket
mCurrentBucketStartTimeNs = startTimeNs;
if (mIsPulled) {
- pullLocked(startTimeNs);
+ pullAndMatchEventsLocked(startTimeNs);
}
VLOG("Gauge metric %lld created. bucket size %lld start_time: %lld sliced %d",
@@ -302,7 +307,7 @@ void GaugeMetricProducer::onDumpReportLocked(const int64_t dumpTimeNs,
mPastBuckets.clear();
}
-void GaugeMetricProducer::pullLocked(const int64_t timestampNs) {
+void GaugeMetricProducer::pullAndMatchEventsLocked(const int64_t timestampNs) {
bool triggerPuller = false;
switch(mSamplingType) {
// When the metric wants to do random sampling and there is already one gauge atom for the
@@ -331,7 +336,10 @@ void GaugeMetricProducer::pullLocked(const int64_t timestampNs) {
return;
}
for (const auto& data : allData) {
- onMatchedLogEventLocked(0, *data);
+ if (mEventMatcherWizard->matchLogEvent(
+ *data, mWhatMatcherIndex) == MatchingState::kMatched) {
+ onMatchedLogEventLocked(mWhatMatcherIndex, *data);
+ }
}
}
@@ -341,7 +349,7 @@ void GaugeMetricProducer::onConditionChangedLocked(const bool conditionMet,
flushIfNeededLocked(eventTimeNs);
mCondition = conditionMet;
if (mIsPulled) {
- pullLocked(eventTimeNs);
+ pullAndMatchEventsLocked(eventTimeNs);
} // else: Push mode. No need to proactively pull the gauge data.
}
@@ -354,7 +362,7 @@ void GaugeMetricProducer::onSlicedConditionMayChangeLocked(bool overallCondition
// pull for every dimension.
mCondition = overallCondition;
if (mIsPulled) {
- pullLocked(eventTimeNs);
+ pullAndMatchEventsLocked(eventTimeNs);
} // else: Push mode. No need to proactively pull the gauge data.
}
@@ -387,7 +395,10 @@ void GaugeMetricProducer::onDataPulled(const std::vector<std::shared_ptr<LogEven
return;
}
for (const auto& data : allData) {
- onMatchedLogEventLocked(0, *data);
+ if (mEventMatcherWizard->matchLogEvent(
+ *data, mWhatMatcherIndex) == MatchingState::kMatched) {
+ onMatchedLogEventLocked(mWhatMatcherIndex, *data);
+ }
}
}
@@ -426,7 +437,7 @@ void GaugeMetricProducer::onMatchedLogEventInternalLocked(
flushIfNeededLocked(eventTimeNs);
if (mTriggerAtomId == event.GetTagId()) {
- pullLocked(eventTimeNs);
+ pullAndMatchEventsLocked(eventTimeNs);
return;
}
diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.h b/cmds/statsd/src/metrics/GaugeMetricProducer.h
index 6379389218fd..99827bb2ad2d 100644
--- a/cmds/statsd/src/metrics/GaugeMetricProducer.h
+++ b/cmds/statsd/src/metrics/GaugeMetricProducer.h
@@ -24,6 +24,7 @@
#include "../external/PullDataReceiver.h"
#include "../external/StatsPullerManager.h"
#include "../matchers/matcher_util.h"
+#include "../matchers/EventMatcherWizard.h"
#include "MetricProducer.h"
#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
#include "../stats_util.h"
@@ -56,7 +57,9 @@ typedef std::unordered_map<MetricDimensionKey, std::vector<GaugeAtom>>
class GaugeMetricProducer : public virtual MetricProducer, public virtual PullDataReceiver {
public:
GaugeMetricProducer(const ConfigKey& key, const GaugeMetric& gaugeMetric,
- const int conditionIndex, const sp<ConditionWizard>& wizard,
+ const int conditionIndex, const sp<ConditionWizard>& conditionWizard,
+ const int whatMatcherIndex,
+ const sp<EventMatcherWizard>& matcherWizard,
const int pullTagId, const int triggerAtomId, const int atomId,
const int64_t timeBaseNs, const int64_t startTimeNs,
const sp<StatsPullerManager>& pullerManager);
@@ -78,7 +81,7 @@ public:
flushCurrentBucketLocked(eventTimeNs);
mCurrentBucketStartTimeNs = eventTimeNs;
if (mIsPulled) {
- pullLocked(eventTimeNs);
+ pullAndMatchEventsLocked(eventTimeNs);
}
};
@@ -113,7 +116,11 @@ private:
void flushCurrentBucketLocked(const int64_t& eventTimeNs) override;
- void pullLocked(const int64_t timestampNs);
+ void pullAndMatchEventsLocked(const int64_t timestampNs);
+
+ const int mWhatMatcherIndex;
+
+ sp<EventMatcherWizard> mEventMatcherWizard;
sp<StatsPullerManager> mPullerManager;
// tagId for pulled data. -1 if this is not pulled
diff --git a/cmds/statsd/src/metrics/MetricProducer.cpp b/cmds/statsd/src/metrics/MetricProducer.cpp
index df081817232e..f87849edae7a 100644
--- a/cmds/statsd/src/metrics/MetricProducer.cpp
+++ b/cmds/statsd/src/metrics/MetricProducer.cpp
@@ -64,8 +64,54 @@ void MetricProducer::onMatchedLogEventLocked(const size_t matcherIndex, const Lo
onMatchedLogEventInternalLocked(
matcherIndex, metricKey, conditionKey, condition, event);
}
+}
+
+bool MetricProducer::evaluateActiveStateLocked(int64_t elapsedTimestampNs) {
+ bool isActive = mEventActivationMap.empty();
+ for (auto& it : mEventActivationMap) {
+ if (it.second.state == ActivationState::kActive &&
+ elapsedTimestampNs > it.second.ttl_ns + it.second.activation_ns) {
+ it.second.state = ActivationState::kNotActive;
+ }
+ if (it.second.state == ActivationState::kActive) {
+ isActive = true;
+ }
+ }
+ return isActive;
+}
+
+void MetricProducer::flushIfExpire(int64_t elapsedTimestampNs) {
+ std::lock_guard<std::mutex> lock(mMutex);
+ if (!mIsActive) {
+ return;
+ }
+ mIsActive = evaluateActiveStateLocked(elapsedTimestampNs);
+ if (!mIsActive) {
+ flushLocked(elapsedTimestampNs);
+ }
+}
+
+void MetricProducer::addActivation(int activationTrackerIndex, int64_t ttl_seconds) {
+ std::lock_guard<std::mutex> lock(mMutex);
+ // When a metric producer does not depend on any activation, its mIsActive is true.
+ // Therefor, if this is the 1st activation, mIsActive will turn to false. Otherwise it does not
+ // change.
+ if (mEventActivationMap.empty()) {
+ mIsActive = false;
+ }
+ mEventActivationMap[activationTrackerIndex].ttl_ns = ttl_seconds * NS_PER_SEC;
+}
+
+void MetricProducer::activateLocked(int activationTrackerIndex, int64_t elapsedTimestampNs) {
+ auto it = mEventActivationMap.find(activationTrackerIndex);
+ if (it == mEventActivationMap.end()) {
+ return;
+ }
+ it->second.activation_ns = elapsedTimestampNs;
+ it->second.state = ActivationState::kActive;
+ mIsActive = true;
+}
- }
} // namespace statsd
} // namespace os
diff --git a/cmds/statsd/src/metrics/MetricProducer.h b/cmds/statsd/src/metrics/MetricProducer.h
index 6fe4bfb47a1f..b21fd501c2d0 100644
--- a/cmds/statsd/src/metrics/MetricProducer.h
+++ b/cmds/statsd/src/metrics/MetricProducer.h
@@ -34,6 +34,17 @@ namespace android {
namespace os {
namespace statsd {
+// If the metric has no activation requirement, it will be active once the metric producer is
+// created.
+// If the metric needs to be activated by atoms, the metric producer will start
+// with kNotActive state, turn to kActive when the activation event arrives, become kNotActive
+// when it reaches the duration limit (timebomb). If the activation event arrives again before
+// or after it expires, the event producer will be re-activated and ttl will be reset.
+enum ActivationState {
+ kNotActive = 0,
+ kActive = 1,
+};
+
// A MetricProducer is responsible for compute one single metrics, creating stats log report, and
// writing the report to dropbox. MetricProducers should respond to package changes as required in
// PackageInfoListener, but if none of the metrics are slicing by package name, then the update can
@@ -54,7 +65,8 @@ public:
mContainANYPositionInDimensionsInWhat(false),
mSliceByPositionALL(false),
mSameConditionDimensionsInTracker(false),
- mHasLinksToAllConditionDimensionsInTracker(false) {
+ mHasLinksToAllConditionDimensionsInTracker(false),
+ mIsActive(true) {
}
virtual ~MetricProducer(){};
@@ -93,17 +105,23 @@ public:
// Consume the parsed stats log entry that already matched the "what" of the metric.
void onMatchedLogEvent(const size_t matcherIndex, const LogEvent& event) {
std::lock_guard<std::mutex> lock(mMutex);
- onMatchedLogEventLocked(matcherIndex, event);
+ if (mIsActive) {
+ onMatchedLogEventLocked(matcherIndex, event);
+ }
}
void onConditionChanged(const bool condition, const int64_t eventTime) {
std::lock_guard<std::mutex> lock(mMutex);
- onConditionChangedLocked(condition, eventTime);
+ if (mIsActive) {
+ onConditionChangedLocked(condition, eventTime);
+ }
}
void onSlicedConditionMayChange(bool overallCondition, const int64_t eventTime) {
std::lock_guard<std::mutex> lock(mMutex);
- onSlicedConditionMayChangeLocked(overallCondition, eventTime);
+ if (mIsActive) {
+ onSlicedConditionMayChangeLocked(overallCondition, eventTime);
+ }
}
bool isConditionSliced() const {
@@ -177,6 +195,15 @@ public:
return mCurrentBucketNum;
}
+ void activate(int activationTrackerIndex, int64_t elapsedTimestampNs) {
+ std::lock_guard<std::mutex> lock(mMutex);
+ activateLocked(activationTrackerIndex, elapsedTimestampNs);
+ }
+
+ void addActivation(int activationTrackerIndex, int64_t ttl_seconds);
+
+ void flushIfExpire(int64_t elapsedTimestampNs);
+
protected:
virtual void onConditionChangedLocked(const bool condition, const int64_t eventTime) = 0;
virtual void onSlicedConditionMayChangeLocked(bool overallCondition,
@@ -189,6 +216,10 @@ protected:
virtual size_t byteSizeLocked() const = 0;
virtual void dumpStatesLocked(FILE* out, bool verbose) const = 0;
+ bool evaluateActiveStateLocked(int64_t elapsedTimestampNs);
+
+ void activateLocked(int activationTrackerIndex, int64_t elapsedTimestampNs);
+
/**
* Flushes the current bucket if the eventTime is after the current bucket's end time. This will
also flush the current partial bucket in memory.
@@ -198,9 +229,9 @@ protected:
/**
* Flushes all the data including the current partial bucket.
*/
- virtual void flushLocked(const int64_t& eventTime) {
- flushIfNeededLocked(eventTime);
- flushCurrentBucketLocked(eventTime);
+ virtual void flushLocked(const int64_t& eventTimeNs) {
+ flushIfNeededLocked(eventTimeNs);
+ flushCurrentBucketLocked(eventTimeNs);
};
/**
@@ -295,6 +326,21 @@ protected:
virtual void onMatchedLogEventLocked(const size_t matcherIndex, const LogEvent& event);
mutable std::mutex mMutex;
+
+ struct Activation {
+ Activation() : ttl_ns(0), activation_ns(0), state(ActivationState::kNotActive) {}
+
+ int64_t ttl_ns;
+ int64_t activation_ns;
+ ActivationState state;
+ };
+ // When the metric producer has multiple activations, these activations are ORed to determine
+ // whether the metric producer is ready to generate metrics.
+ std::unordered_map<int, Activation> mEventActivationMap;
+
+ bool mIsActive;
+
+ FRIEND_TEST(MetricActivationE2eTest, TestCountMetric);
};
} // namespace statsd
diff --git a/cmds/statsd/src/metrics/MetricsManager.cpp b/cmds/statsd/src/metrics/MetricsManager.cpp
index 0e5ef4d3e59a..f85ba1f93e8c 100644
--- a/cmds/statsd/src/metrics/MetricsManager.cpp
+++ b/cmds/statsd/src/metrics/MetricsManager.cpp
@@ -73,7 +73,8 @@ MetricsManager::MetricsManager(const ConfigKey& key, const StatsdConfig& config,
key, config, *uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor,
timeBaseNs, currentTimeNs, mTagIds, mAllAtomMatchers, mAllConditionTrackers,
mAllMetricProducers, mAllAnomalyTrackers, mAllPeriodicAlarmTrackers,
- mConditionToMetricMap, mTrackerToMetricMap, mTrackerToConditionMap, mNoReportMetricIds);
+ mConditionToMetricMap, mTrackerToMetricMap, mTrackerToConditionMap,
+ mActivationAtomTrackerToMetricMap, mMetricIndexesWithActivation, mNoReportMetricIds);
mHashStringsInReport = config.hash_strings_in_metric_report();
@@ -298,7 +299,12 @@ void MetricsManager::onLogEvent(const LogEvent& event) {
}
int tagId = event.GetTagId();
- int64_t eventTime = event.GetElapsedTimestampNs();
+ int64_t eventTimeNs = event.GetElapsedTimestampNs();
+
+ for (int metric : mMetricIndexesWithActivation) {
+ mAllMetricProducers[metric]->flushIfExpire(eventTimeNs);
+ }
+
if (mTagIds.find(tagId) == mTagIds.end()) {
// not interesting...
return;
@@ -310,6 +316,14 @@ void MetricsManager::onLogEvent(const LogEvent& event) {
matcher->onLogEvent(event, mAllAtomMatchers, matcherCache);
}
+ for (const auto& it : mActivationAtomTrackerToMetricMap) {
+ if (matcherCache[it.first] == MatchingState::kMatched) {
+ for (int metricIndex : it.second) {
+ mAllMetricProducers[metricIndex]->activate(it.first, eventTimeNs);
+ }
+ }
+ }
+
// A bitmap to see which ConditionTracker needs to be re-evaluated.
vector<bool> conditionToBeEvaluated(mAllConditionTrackers.size(), false);
@@ -347,13 +361,13 @@ void MetricsManager::onLogEvent(const LogEvent& event) {
// Push the new condition to it directly.
if (!mAllMetricProducers[metricIndex]->isConditionSliced()) {
mAllMetricProducers[metricIndex]->onConditionChanged(conditionCache[i],
- eventTime);
+ eventTimeNs);
// metric cares about sliced conditions, and it may have changed. Send
// notification, and the metric can query the sliced conditions that are
// interesting to it.
} else {
mAllMetricProducers[metricIndex]->onSlicedConditionMayChange(conditionCache[i],
- eventTime);
+ eventTimeNs);
}
}
}
diff --git a/cmds/statsd/src/metrics/MetricsManager.h b/cmds/statsd/src/metrics/MetricsManager.h
index dfbb69f1ab7c..649222ffef9d 100644
--- a/cmds/statsd/src/metrics/MetricsManager.h
+++ b/cmds/statsd/src/metrics/MetricsManager.h
@@ -195,6 +195,11 @@ private:
// maps from ConditionTracker to MetricProducer
std::unordered_map<int, std::vector<int>> mConditionToMetricMap;
+ // maps from life span triggering event to MetricProducers.
+ std::unordered_map<int, std::vector<int>> mActivationAtomTrackerToMetricMap;
+
+ std::vector<int> mMetricIndexesWithActivation;
+
void initLogSourceWhiteList();
// The metrics that don't need to be uploaded or even reported.
@@ -207,7 +212,7 @@ private:
FRIEND_TEST(GaugeMetricE2eTest, TestMultipleFieldsForPushedEvent);
FRIEND_TEST(GaugeMetricE2eTest, TestRandomSamplePulledEvents);
FRIEND_TEST(GaugeMetricE2eTest, TestRandomSamplePulledEvent_LateAlarm);
- FRIEND_TEST(GaugeMetricE2eTest, TestAllConditionChangesSamplePulledEvents);
+ FRIEND_TEST(GaugeMetricE2eTest, TestConditionChangeToTrueSamplePulledEvents);
FRIEND_TEST(ValueMetricE2eTest, TestPulledEvents);
FRIEND_TEST(ValueMetricE2eTest, TestPulledEvents_LateAlarm);
FRIEND_TEST(DimensionInConditionE2eTest, TestCreateCountMetric_NoLink_OR_CombinationCondition);
@@ -230,6 +235,7 @@ private:
FRIEND_TEST(AlarmE2eTest, TestMultipleAlarms);
FRIEND_TEST(ConfigTtlE2eTest, TestCountMetric);
+ FRIEND_TEST(MetricActivationE2eTest, TestCountMetric);
};
} // namespace statsd
diff --git a/cmds/statsd/src/metrics/metrics_manager_util.cpp b/cmds/statsd/src/metrics/metrics_manager_util.cpp
index 75d6df95852d..136ba074d589 100644
--- a/cmds/statsd/src/metrics/metrics_manager_util.cpp
+++ b/cmds/statsd/src/metrics/metrics_manager_util.cpp
@@ -25,6 +25,7 @@
#include "../external/StatsPullerManager.h"
#include "../matchers/CombinationLogMatchingTracker.h"
#include "../matchers/SimpleLogMatchingTracker.h"
+#include "../matchers/EventMatcherWizard.h"
#include "../metrics/CountMetricProducer.h"
#include "../metrics/DurationMetricProducer.h"
#include "../metrics/EventMetricProducer.h"
@@ -294,6 +295,7 @@ bool initMetrics(const ConfigKey& key, const StatsdConfig& config, const int64_t
unordered_map<int, std::vector<int>>& trackerToMetricMap,
unordered_map<int64_t, int>& metricMap, std::set<int64_t>& noReportMetricIds) {
sp<ConditionWizard> wizard = new ConditionWizard(allConditionTrackers);
+ sp<EventMatcherWizard> matcherWizard = new EventMatcherWizard(allAtomMatchers);
const int allMetricsCount = config.count_metric_size() + config.duration_metric_size() +
config.event_metric_size() + config.value_metric_size();
allMetricProducers.reserve(allMetricsCount);
@@ -563,7 +565,8 @@ bool initMetrics(const ConfigKey& key, const StatsdConfig& config, const int64_t
}
sp<MetricProducer> gaugeProducer = new GaugeMetricProducer(
- key, metric, conditionIndex, wizard, pullTagId, triggerAtomId, atomTagId,
+ key, metric, conditionIndex, wizard,
+ trackerIndex, matcherWizard, pullTagId, triggerAtomId, atomTagId,
timeBaseTimeNs, currentTimeNs, pullerManager);
allMetricProducers.push_back(gaugeProducer);
}
@@ -682,6 +685,44 @@ bool initAlarms(const StatsdConfig& config, const ConfigKey& key,
return true;
}
+bool initMetricActivations(const ConfigKey& key, const StatsdConfig& config,
+ const int64_t currentTimeNs,
+ const unordered_map<int64_t, int> &logEventTrackerMap,
+ const unordered_map<int64_t, int> &metricProducerMap,
+ vector<sp<MetricProducer>>& allMetricProducers,
+ unordered_map<int, std::vector<int>>& activationAtomTrackerToMetricMap,
+ vector<int>& metricsWithActivation) {
+ for (int i = 0; i < config.metric_activation_size(); ++i) {
+ const MetricActivation& metric_activation = config.metric_activation(i);
+ auto itr = metricProducerMap.find(metric_activation.metric_id());
+ if (itr == metricProducerMap.end()) {
+ ALOGE("Metric id not found in metric activation: %lld",
+ (long long)metric_activation.metric_id());
+ return false;
+ }
+ const int metricTrackerIndex = itr->second;
+ if (metricTrackerIndex < 0 || metricTrackerIndex >= (int)allMetricProducers.size()) {
+ ALOGE("Invalid metric tracker index.");
+ return false;
+ }
+ metricsWithActivation.push_back(metricTrackerIndex);
+ for (int j = 0; j < metric_activation.event_activation_size(); ++j) {
+ const EventActivation& activation = metric_activation.event_activation(j);
+ auto logTrackerIt = logEventTrackerMap.find(activation.atom_matcher_id());
+ if (logTrackerIt == logEventTrackerMap.end()) {
+ ALOGE("Atom matcher not found for event activation.");
+ return false;
+ }
+ const int atomMatcherIndex = logTrackerIt->second;
+ activationAtomTrackerToMetricMap[atomMatcherIndex].push_back(
+ metricTrackerIndex);
+ allMetricProducers[metricTrackerIndex]->addActivation(
+ atomMatcherIndex, activation.ttl_seconds());
+ }
+ }
+ return true;
+}
+
bool initStatsdConfig(const ConfigKey& key, const StatsdConfig& config, UidMap& uidMap,
const sp<StatsPullerManager>& pullerManager,
const sp<AlarmMonitor>& anomalyAlarmMonitor,
@@ -695,6 +736,8 @@ bool initStatsdConfig(const ConfigKey& key, const StatsdConfig& config, UidMap&
unordered_map<int, std::vector<int>>& conditionToMetricMap,
unordered_map<int, std::vector<int>>& trackerToMetricMap,
unordered_map<int, std::vector<int>>& trackerToConditionMap,
+ unordered_map<int, std::vector<int>>& activationAtomTrackerToMetricMap,
+ vector<int>& metricsWithActivation,
std::set<int64_t>& noReportMetricIds) {
unordered_map<int64_t, int> logTrackerMap;
unordered_map<int64_t, int> conditionTrackerMap;
@@ -729,6 +772,11 @@ bool initStatsdConfig(const ConfigKey& key, const StatsdConfig& config, UidMap&
ALOGE("initAlarms failed");
return false;
}
+ if (!initMetricActivations(key, config, currentTimeNs, logTrackerMap, metricProducerMap,
+ allMetricProducers, activationAtomTrackerToMetricMap, metricsWithActivation)) {
+ ALOGE("initMetricActivations failed");
+ return false;
+ }
return true;
}
diff --git a/cmds/statsd/src/metrics/metrics_manager_util.h b/cmds/statsd/src/metrics/metrics_manager_util.h
index c6601493135f..9ffcedae4962 100644
--- a/cmds/statsd/src/metrics/metrics_manager_util.h
+++ b/cmds/statsd/src/metrics/metrics_manager_util.h
@@ -108,6 +108,8 @@ bool initStatsdConfig(const ConfigKey& key, const StatsdConfig& config, UidMap&
std::unordered_map<int, std::vector<int>>& conditionToMetricMap,
std::unordered_map<int, std::vector<int>>& trackerToMetricMap,
std::unordered_map<int, std::vector<int>>& trackerToConditionMap,
+ unordered_map<int, std::vector<int>>& lifeSpanEventTrackerToMetricMap,
+ vector<int>& metricsWithLifeSpan,
std::set<int64_t>& noReportMetricIds);
bool isStateTracker(const SimplePredicate& simplePredicate, std::vector<Matcher>* primaryKeys);
diff --git a/cmds/statsd/src/shell/ShellSubscriber.cpp b/cmds/statsd/src/shell/ShellSubscriber.cpp
index 1306a467e5c4..dffff7a96269 100644
--- a/cmds/statsd/src/shell/ShellSubscriber.cpp
+++ b/cmds/statsd/src/shell/ShellSubscriber.cpp
@@ -18,9 +18,9 @@
#include "ShellSubscriber.h"
-#include "matchers/matcher_util.h"
-
#include <android-base/file.h>
+#include "matchers/matcher_util.h"
+#include "stats_log_util.h"
using android::util::ProtoOutputStream;
@@ -28,6 +28,8 @@ namespace android {
namespace os {
namespace statsd {
+const static int FIELD_ID_ATOM = 1;
+
void ShellSubscriber::startNewSubscription(int in, int out, sp<IResultReceiver> resultReceiver) {
VLOG("start new shell subscription");
{
@@ -42,25 +44,106 @@ void ShellSubscriber::startNewSubscription(int in, int out, sp<IResultReceiver>
IInterface::asBinder(mResultReceiver)->linkToDeath(this);
}
- // Spawn another thread to read the config updates from the input file descriptor
- std::thread reader([in, this] { readConfig(in); });
- reader.detach();
+ // Note that the following is blocking, and it's intended as we cannot return until the shell
+ // cmd exits, otherwise all resources & FDs will be automatically closed.
- std::unique_lock<std::mutex> lk(mMutex);
+ // Read config forever until EOF is reached. Clients may send multiple configs -- each new
+ // config replace the previous one.
+ readConfig(in);
+ // Now we have read an EOF we now wait for the semaphore until the client exits.
+ VLOG("Now wait for client to exit");
+ std::unique_lock<std::mutex> lk(mMutex);
mShellDied.wait(lk, [this, resultReceiver] { return mResultReceiver != resultReceiver; });
- if (reader.joinable()) {
- reader.join();
- }
}
void ShellSubscriber::updateConfig(const ShellSubscription& config) {
std::lock_guard<std::mutex> lock(mMutex);
mPushedMatchers.clear();
+ mPulledInfo.clear();
+
for (const auto& pushed : config.pushed()) {
mPushedMatchers.push_back(pushed);
VLOG("adding matcher for atom %d", pushed.atom_id());
}
+
+ int64_t token = getElapsedRealtimeNs();
+ mPullToken = token;
+
+ int64_t minInterval = -1;
+ for (const auto& pulled : config.pulled()) {
+ // All intervals need to be multiples of the min interval.
+ if (minInterval < 0 || pulled.freq_millis() < minInterval) {
+ minInterval = pulled.freq_millis();
+ }
+
+ mPulledInfo.emplace_back(pulled.matcher(), pulled.freq_millis());
+ VLOG("adding matcher for pulled atom %d", pulled.matcher().atom_id());
+ }
+
+ if (mPulledInfo.size() > 0 && minInterval > 0) {
+ // This thread is guaranteed to terminate after it detects the token is different or
+ // cleaned up.
+ std::thread puller([token, minInterval, this] { startPull(token, minInterval); });
+ puller.detach();
+ }
+}
+
+void ShellSubscriber::writeToOutputLocked(const vector<std::shared_ptr<LogEvent>>& data,
+ const SimpleAtomMatcher& matcher) {
+ if (mOutput == 0) return;
+ int count = 0;
+ mProto.clear();
+ for (const auto& event : data) {
+ VLOG("%s", event->ToString().c_str());
+ if (matchesSimple(*mUidMap, matcher, *event)) {
+ VLOG("matched");
+ count++;
+ uint64_t atomToken = mProto.start(util::FIELD_TYPE_MESSAGE |
+ util::FIELD_COUNT_REPEATED | FIELD_ID_ATOM);
+ event->ToProto(mProto);
+ mProto.end(atomToken);
+ }
+ }
+
+ if (count > 0) {
+ // First write the payload size.
+ size_t bufferSize = mProto.size();
+ write(mOutput, &bufferSize, sizeof(bufferSize));
+ VLOG("%d atoms, proto size: %zu", count, bufferSize);
+ // Then write the payload.
+ mProto.flush(mOutput);
+ }
+ mProto.clear();
+}
+
+void ShellSubscriber::startPull(int64_t token, int64_t intervalMillis) {
+ while (1) {
+ int64_t nowMillis = getElapsedRealtimeMillis();
+ {
+ std::lock_guard<std::mutex> lock(mMutex);
+ if (mPulledInfo.size() == 0 || mPullToken != token) {
+ VLOG("Pulling thread %lld done!", (long long)token);
+ return;
+ }
+ for (auto& pullInfo : mPulledInfo) {
+ if (pullInfo.mPrevPullElapsedRealtimeMs + pullInfo.mInterval < nowMillis) {
+ VLOG("pull atom %d now", pullInfo.mPullerMatcher.atom_id());
+
+ vector<std::shared_ptr<LogEvent>> data;
+ mPullerMgr->Pull(pullInfo.mPullerMatcher.atom_id(), nowMillis * 1000000L,
+ &data);
+ VLOG("pulled %zu atoms", data.size());
+ if (data.size() > 0) {
+ writeToOutputLocked(data, pullInfo.mPullerMatcher);
+ }
+ pullInfo.mPrevPullElapsedRealtimeMs = nowMillis;
+ }
+ }
+ }
+ VLOG("Pulling thread %lld sleep....", (long long)token);
+ std::this_thread::sleep_for(std::chrono::milliseconds(intervalMillis));
+ }
}
void ShellSubscriber::readConfig(int in) {
@@ -101,6 +184,8 @@ void ShellSubscriber::cleanUpLocked() {
mOutput = 0;
mResultReceiver = nullptr;
mPushedMatchers.clear();
+ mPulledInfo.clear();
+ mPullToken = 0;
VLOG("done clean up");
}
@@ -110,10 +195,13 @@ void ShellSubscriber::onLogEvent(const LogEvent& event) {
if (mOutput <= 0) {
return;
}
-
for (const auto& matcher : mPushedMatchers) {
if (matchesSimple(*mUidMap, matcher, event)) {
+ VLOG("%s", event.ToString().c_str());
+ uint64_t atomToken = mProto.start(util::FIELD_TYPE_MESSAGE |
+ util::FIELD_COUNT_REPEATED | FIELD_ID_ATOM);
event.ToProto(mProto);
+ mProto.end(atomToken);
// First write the payload size.
size_t bufferSize = mProto.size();
write(mOutput, &bufferSize, sizeof(bufferSize));
diff --git a/cmds/statsd/src/shell/ShellSubscriber.h b/cmds/statsd/src/shell/ShellSubscriber.h
index 0ace35fab850..5401f31ce68c 100644
--- a/cmds/statsd/src/shell/ShellSubscriber.h
+++ b/cmds/statsd/src/shell/ShellSubscriber.h
@@ -24,6 +24,7 @@
#include <mutex>
#include <string>
#include <thread>
+#include "external/StatsPullerManager.h"
#include "frameworks/base/cmds/statsd/src/shell/shell_config.pb.h"
#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
#include "packages/UidMap.h"
@@ -51,14 +52,15 @@ namespace statsd {
* with sizeof(size_t) bytes indicating the size of the proto message payload.
*
* The stream would be in the following format:
- * |size_t|atom1 proto|size_t|atom2 proto|....
+ * |size_t|shellData proto|size_t|shellData proto|....
*
* Only one shell subscriber allowed at a time, because each shell subscriber blocks one thread
* until it exits.
*/
class ShellSubscriber : public virtual IBinder::DeathRecipient {
public:
- ShellSubscriber(sp<UidMap> uidMap) : mUidMap(uidMap){};
+ ShellSubscriber(sp<UidMap> uidMap, sp<StatsPullerManager> pullerMgr)
+ : mUidMap(uidMap), mPullerMgr(pullerMgr){};
/**
* Start a new subscription.
@@ -70,15 +72,28 @@ public:
void onLogEvent(const LogEvent& event);
private:
+ struct PullInfo {
+ PullInfo(const SimpleAtomMatcher& matcher, int64_t interval)
+ : mPullerMatcher(matcher), mInterval(interval), mPrevPullElapsedRealtimeMs(0) {
+ }
+ SimpleAtomMatcher mPullerMatcher;
+ int64_t mInterval;
+ int64_t mPrevPullElapsedRealtimeMs;
+ };
void readConfig(int in);
void updateConfig(const ShellSubscription& config);
+ void startPull(int64_t token, int64_t intervalMillis);
+
void cleanUpLocked();
+ void writeToOutputLocked(const vector<std::shared_ptr<LogEvent>>& data,
+ const SimpleAtomMatcher& matcher);
+
sp<UidMap> mUidMap;
- // bool mWritten = false;
+ sp<StatsPullerManager> mPullerMgr;
android::util::ProtoOutputStream mProto;
@@ -93,6 +108,10 @@ private:
sp<IResultReceiver> mResultReceiver;
std::vector<SimpleAtomMatcher> mPushedMatchers;
+
+ std::vector<PullInfo> mPulledInfo;
+
+ int64_t mPullToken = 0; // A unique token to identify a puller thread.
};
} // namespace statsd
diff --git a/cmds/statsd/src/shell/shell_config.proto b/cmds/statsd/src/shell/shell_config.proto
index 516693d4e7f7..73cb49a61821 100644
--- a/cmds/statsd/src/shell/shell_config.proto
+++ b/cmds/statsd/src/shell/shell_config.proto
@@ -24,7 +24,7 @@ option java_outer_classname = "ShellConfig";
import "frameworks/base/cmds/statsd/src/statsd_config.proto";
message PulledAtomSubscription {
- optional int32 atom_id = 1;
+ optional SimpleAtomMatcher matcher = 1;
/* gap between two pulls in milliseconds */
optional int32 freq_millis = 2;
diff --git a/cmds/statsd/src/shell/shell_data.proto b/cmds/statsd/src/shell/shell_data.proto
new file mode 100644
index 000000000000..236bdbdd31f6
--- /dev/null
+++ b/cmds/statsd/src/shell/shell_data.proto
@@ -0,0 +1,29 @@
+/*
+ * 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.
+ */
+
+syntax = "proto2";
+
+package android.os.statsd;
+
+option java_package = "com.android.os.statsd";
+option java_outer_classname = "ShellDataProto";
+
+import "frameworks/base/cmds/statsd/src/atoms.proto";
+
+// The output of shell subscription, including both pulled and pushed subscriptions.
+message ShellData {
+ repeated Atom atom = 1;
+}
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/src/statsd_config.proto b/cmds/statsd/src/statsd_config.proto
index d19e247ae6c7..d5f81a593082 100644
--- a/cmds/statsd/src/statsd_config.proto
+++ b/cmds/statsd/src/statsd_config.proto
@@ -347,6 +347,17 @@ message Subscription {
optional float probability_of_informing = 7 [default = 1.1];
}
+message EventActivation {
+ optional int64 atom_matcher_id = 1;
+ optional int64 ttl_seconds = 2;
+}
+
+message MetricActivation {
+ optional int64 metric_id = 1;
+
+ repeated EventActivation event_activation = 2;
+}
+
message StatsdConfig {
optional int64 id = 1;
@@ -384,6 +395,8 @@ message StatsdConfig {
optional bool hash_strings_in_metric_report = 16 [default = true];
+ repeated MetricActivation metric_activation = 17;
+
// Field number 1000 is reserved for later use.
reserved 1000;
}
diff --git a/cmds/statsd/tests/MetricsManager_test.cpp b/cmds/statsd/tests/MetricsManager_test.cpp
index 8fbb58a956d5..f8184d8aa14c 100644
--- a/cmds/statsd/tests/MetricsManager_test.cpp
+++ b/cmds/statsd/tests/MetricsManager_test.cpp
@@ -282,13 +282,17 @@ TEST(MetricsManagerTest, TestGoodConfig) {
unordered_map<int, std::vector<int>> conditionToMetricMap;
unordered_map<int, std::vector<int>> trackerToMetricMap;
unordered_map<int, std::vector<int>> trackerToConditionMap;
+ unordered_map<int, std::vector<int>> lifeSpanEventTrackerToMetricMap;
+ vector<int> metricsWithLifeSpan;
std::set<int64_t> noReportMetricIds;
EXPECT_TRUE(initStatsdConfig(kConfigKey, config, uidMap, pullerManager, anomalyAlarmMonitor,
periodicAlarmMonitor, timeBaseSec, timeBaseSec, allTagIds,
allAtomMatchers, allConditionTrackers, allMetricProducers,
allAnomalyTrackers, allAlarmTrackers, conditionToMetricMap,
- trackerToMetricMap, trackerToConditionMap, noReportMetricIds));
+ trackerToMetricMap, trackerToConditionMap,
+ lifeSpanEventTrackerToMetricMap, metricsWithLifeSpan,
+ noReportMetricIds));
EXPECT_EQ(1u, allMetricProducers.size());
EXPECT_EQ(1u, allAnomalyTrackers.size());
EXPECT_EQ(1u, noReportMetricIds.size());
@@ -309,13 +313,17 @@ TEST(MetricsManagerTest, TestDimensionMetricsWithMultiTags) {
unordered_map<int, std::vector<int>> conditionToMetricMap;
unordered_map<int, std::vector<int>> trackerToMetricMap;
unordered_map<int, std::vector<int>> trackerToConditionMap;
+ unordered_map<int, std::vector<int>> lifeSpanEventTrackerToMetricMap;
+ vector<int> metricsWithLifeSpan;
std::set<int64_t> noReportMetricIds;
EXPECT_FALSE(initStatsdConfig(kConfigKey, config, uidMap, pullerManager, anomalyAlarmMonitor,
periodicAlarmMonitor, timeBaseSec, timeBaseSec, allTagIds,
allAtomMatchers, allConditionTrackers, allMetricProducers,
allAnomalyTrackers, allAlarmTrackers, conditionToMetricMap,
- trackerToMetricMap, trackerToConditionMap, noReportMetricIds));
+ trackerToMetricMap, trackerToConditionMap,
+ lifeSpanEventTrackerToMetricMap, metricsWithLifeSpan,
+ noReportMetricIds));
}
TEST(MetricsManagerTest, TestCircleLogMatcherDependency) {
@@ -333,13 +341,17 @@ TEST(MetricsManagerTest, TestCircleLogMatcherDependency) {
unordered_map<int, std::vector<int>> conditionToMetricMap;
unordered_map<int, std::vector<int>> trackerToMetricMap;
unordered_map<int, std::vector<int>> trackerToConditionMap;
+ unordered_map<int, std::vector<int>> lifeSpanEventTrackerToMetricMap;
+ vector<int> metricsWithLifeSpan;
std::set<int64_t> noReportMetricIds;
EXPECT_FALSE(initStatsdConfig(kConfigKey, config, uidMap, pullerManager, anomalyAlarmMonitor,
periodicAlarmMonitor, timeBaseSec, timeBaseSec, allTagIds,
allAtomMatchers, allConditionTrackers, allMetricProducers,
allAnomalyTrackers, allAlarmTrackers, conditionToMetricMap,
- trackerToMetricMap, trackerToConditionMap, noReportMetricIds));
+ trackerToMetricMap, trackerToConditionMap,
+ lifeSpanEventTrackerToMetricMap, metricsWithLifeSpan,
+ noReportMetricIds));
}
TEST(MetricsManagerTest, TestMissingMatchers) {
@@ -357,12 +369,16 @@ TEST(MetricsManagerTest, TestMissingMatchers) {
unordered_map<int, std::vector<int>> conditionToMetricMap;
unordered_map<int, std::vector<int>> trackerToMetricMap;
unordered_map<int, std::vector<int>> trackerToConditionMap;
+ unordered_map<int, std::vector<int>> lifeSpanEventTrackerToMetricMap;
+ vector<int> metricsWithLifeSpan;
std::set<int64_t> noReportMetricIds;
EXPECT_FALSE(initStatsdConfig(kConfigKey, config, uidMap, pullerManager, anomalyAlarmMonitor,
periodicAlarmMonitor, timeBaseSec, timeBaseSec, allTagIds,
allAtomMatchers, allConditionTrackers, allMetricProducers,
allAnomalyTrackers, allAlarmTrackers, conditionToMetricMap,
- trackerToMetricMap, trackerToConditionMap, noReportMetricIds));
+ trackerToMetricMap, trackerToConditionMap,
+ lifeSpanEventTrackerToMetricMap, metricsWithLifeSpan,
+ noReportMetricIds));
}
TEST(MetricsManagerTest, TestMissingPredicate) {
@@ -380,12 +396,16 @@ TEST(MetricsManagerTest, TestMissingPredicate) {
unordered_map<int, std::vector<int>> conditionToMetricMap;
unordered_map<int, std::vector<int>> trackerToMetricMap;
unordered_map<int, std::vector<int>> trackerToConditionMap;
+ unordered_map<int, std::vector<int>> lifeSpanEventTrackerToMetricMap;
+ vector<int> metricsWithLifeSpan;
std::set<int64_t> noReportMetricIds;
EXPECT_FALSE(initStatsdConfig(kConfigKey, config, uidMap, pullerManager, anomalyAlarmMonitor,
periodicAlarmMonitor, timeBaseSec, timeBaseSec, allTagIds,
allAtomMatchers, allConditionTrackers, allMetricProducers,
allAnomalyTrackers, allAlarmTrackers, conditionToMetricMap,
- trackerToMetricMap, trackerToConditionMap, noReportMetricIds));
+ trackerToMetricMap, trackerToConditionMap,
+ lifeSpanEventTrackerToMetricMap, metricsWithLifeSpan,
+ noReportMetricIds));
}
TEST(MetricsManagerTest, TestCirclePredicateDependency) {
@@ -403,13 +423,17 @@ TEST(MetricsManagerTest, TestCirclePredicateDependency) {
unordered_map<int, std::vector<int>> conditionToMetricMap;
unordered_map<int, std::vector<int>> trackerToMetricMap;
unordered_map<int, std::vector<int>> trackerToConditionMap;
+ unordered_map<int, std::vector<int>> lifeSpanEventTrackerToMetricMap;
+ vector<int> metricsWithLifeSpan;
std::set<int64_t> noReportMetricIds;
EXPECT_FALSE(initStatsdConfig(kConfigKey, config, uidMap, pullerManager, anomalyAlarmMonitor,
periodicAlarmMonitor, timeBaseSec, timeBaseSec, allTagIds,
allAtomMatchers, allConditionTrackers, allMetricProducers,
allAnomalyTrackers, allAlarmTrackers, conditionToMetricMap,
- trackerToMetricMap, trackerToConditionMap, noReportMetricIds));
+ trackerToMetricMap, trackerToConditionMap,
+ lifeSpanEventTrackerToMetricMap, metricsWithLifeSpan,
+ noReportMetricIds));
}
TEST(MetricsManagerTest, testAlertWithUnknownMetric) {
@@ -427,13 +451,17 @@ TEST(MetricsManagerTest, testAlertWithUnknownMetric) {
unordered_map<int, std::vector<int>> conditionToMetricMap;
unordered_map<int, std::vector<int>> trackerToMetricMap;
unordered_map<int, std::vector<int>> trackerToConditionMap;
+ unordered_map<int, std::vector<int>> lifeSpanEventTrackerToMetricMap;
+ vector<int> metricsWithLifeSpan;
std::set<int64_t> noReportMetricIds;
EXPECT_FALSE(initStatsdConfig(kConfigKey, config, uidMap, pullerManager, anomalyAlarmMonitor,
periodicAlarmMonitor, timeBaseSec, timeBaseSec, allTagIds,
allAtomMatchers, allConditionTrackers, allMetricProducers,
allAnomalyTrackers, allAlarmTrackers, conditionToMetricMap,
- trackerToMetricMap, trackerToConditionMap, noReportMetricIds));
+ trackerToMetricMap, trackerToConditionMap,
+ lifeSpanEventTrackerToMetricMap, metricsWithLifeSpan,
+ noReportMetricIds));
}
#else
diff --git a/cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp b/cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp
index 5b6f167984dc..d7b9c119b71b 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,11 +197,11 @@ 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) {
- auto config = CreateStatsdConfig(GaugeMetric::ALL_CONDITION_CHANGES);
+TEST(GaugeMetricE2eTest, TestConditionChangeToTrueSamplePulledEvents) {
+ auto config = CreateStatsdConfig(GaugeMetric::CONDITION_CHANGE_TO_TRUE);
int64_t baseTimeNs = 10 * NS_PER_SEC;
int64_t configAddedTimeNs = 10 * 60 * NS_PER_SEC + baseTimeNs;
int64_t bucketSizeNs =
@@ -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/tests/e2e/MetricActivation_e2e_test.cpp b/cmds/statsd/tests/e2e/MetricActivation_e2e_test.cpp
new file mode 100644
index 000000000000..0f13a4ac1254
--- /dev/null
+++ b/cmds/statsd/tests/e2e/MetricActivation_e2e_test.cpp
@@ -0,0 +1,242 @@
+// 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 <gtest/gtest.h>
+
+#include "src/StatsLogProcessor.h"
+#include "src/stats_log_util.h"
+#include "tests/statsd_test_util.h"
+
+#include <vector>
+
+namespace android {
+namespace os {
+namespace statsd {
+
+#ifdef __ANDROID__
+
+namespace {
+
+StatsdConfig CreateStatsdConfig() {
+ StatsdConfig config;
+ config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
+ auto crashMatcher = CreateProcessCrashAtomMatcher();
+ auto screenOnMatcher = CreateScreenTurnedOnAtomMatcher();
+ auto saverModeMatcher = CreateBatterySaverModeStartAtomMatcher();
+
+ *config.add_atom_matcher() = saverModeMatcher;
+ *config.add_atom_matcher() = crashMatcher;
+ *config.add_atom_matcher() = screenOnMatcher;
+
+ int64_t metricId = 123456;
+ auto countMetric = config.add_count_metric();
+ countMetric->set_id(metricId);
+ countMetric->set_what(crashMatcher.id());
+ countMetric->set_bucket(FIVE_MINUTES);
+ countMetric->mutable_dimensions_in_what()->set_field(
+ android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED);
+ countMetric->mutable_dimensions_in_what()->add_child()->set_field(1); // uid field
+
+ auto metric_activation1 = config.add_metric_activation();
+ metric_activation1->set_metric_id(metricId);
+ auto event_activation1 = metric_activation1->add_event_activation();
+ event_activation1->set_atom_matcher_id(saverModeMatcher.id());
+ event_activation1->set_ttl_seconds(60 * 6); // 6 minutes
+ auto event_activation2 = metric_activation1->add_event_activation();
+ event_activation2->set_atom_matcher_id(screenOnMatcher.id());
+ event_activation2->set_ttl_seconds(60 * 2); // 2 minutes
+
+ return config;
+}
+
+} // namespace
+
+TEST(MetricActivationE2eTest, TestCountMetric) {
+ auto config = CreateStatsdConfig();
+
+ int64_t bucketStartTimeNs = 10000000000;
+ int64_t bucketSizeNs =
+ TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000;
+
+ ConfigKey cfgKey;
+ auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
+ EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+ sp<MetricProducer> metricProducer =
+ processor->mMetricsManagers.begin()->second->mAllMetricProducers[0];
+ auto& eventActivationMap = metricProducer->mEventActivationMap;
+
+ EXPECT_FALSE(metricProducer->mIsActive);
+ // Two activations: one is triggered by battery saver mode (tracker index 0), the other is
+ // triggered by screen on event (tracker index 2).
+ EXPECT_EQ(eventActivationMap.size(), 2u);
+ EXPECT_TRUE(eventActivationMap.find(0) != eventActivationMap.end());
+ EXPECT_TRUE(eventActivationMap.find(2) != eventActivationMap.end());
+ EXPECT_EQ(eventActivationMap[0].state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[0].activation_ns, 0);
+ EXPECT_EQ(eventActivationMap[0].ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap[2].state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[2].activation_ns, 0);
+ EXPECT_EQ(eventActivationMap[2].ttl_ns, 60 * 2 * NS_PER_SEC);
+
+ std::unique_ptr<LogEvent> event;
+
+ event = CreateAppCrashEvent(111, bucketStartTimeNs + 5);
+ processor->OnLogEvent(event.get());
+ EXPECT_FALSE(metricProducer->mIsActive);
+
+ // Activated by battery save mode.
+ event = CreateBatterySaverOnEvent(bucketStartTimeNs + 10);
+ processor->OnLogEvent(event.get());
+ EXPECT_TRUE(metricProducer->mIsActive);
+ EXPECT_EQ(eventActivationMap[0].state, ActivationState::kActive);
+ EXPECT_EQ(eventActivationMap[0].activation_ns, bucketStartTimeNs + 10);
+ EXPECT_EQ(eventActivationMap[0].ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap[2].state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[2].activation_ns, 0);
+ EXPECT_EQ(eventActivationMap[2].ttl_ns, 60 * 2 * NS_PER_SEC);
+
+ // First processed event.
+ event = CreateAppCrashEvent(222, bucketStartTimeNs + 15);
+ processor->OnLogEvent(event.get());
+
+ // Activated by screen on event.
+ event = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
+ bucketStartTimeNs + 20);
+ processor->OnLogEvent(event.get());
+ EXPECT_TRUE(metricProducer->mIsActive);
+ EXPECT_EQ(eventActivationMap[0].state, ActivationState::kActive);
+ EXPECT_EQ(eventActivationMap[0].activation_ns, bucketStartTimeNs + 10);
+ EXPECT_EQ(eventActivationMap[0].ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap[2].state, ActivationState::kActive);
+ EXPECT_EQ(eventActivationMap[2].activation_ns, bucketStartTimeNs + 20);
+ EXPECT_EQ(eventActivationMap[2].ttl_ns, 60 * 2 * NS_PER_SEC);
+
+ // 2nd processed event.
+ // The activation by screen_on event expires, but the one by battery save mode is still active.
+ event = CreateAppCrashEvent(333, bucketStartTimeNs + NS_PER_SEC * 60 * 2 + 25);
+ processor->OnLogEvent(event.get());
+ EXPECT_TRUE(metricProducer->mIsActive);
+ EXPECT_EQ(eventActivationMap[0].state, ActivationState::kActive);
+ EXPECT_EQ(eventActivationMap[0].activation_ns, bucketStartTimeNs + 10);
+ EXPECT_EQ(eventActivationMap[0].ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap[2].state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[2].activation_ns, bucketStartTimeNs + 20);
+ EXPECT_EQ(eventActivationMap[2].ttl_ns, 60 * 2 * NS_PER_SEC);
+
+ // 3rd processed event.
+ event = CreateAppCrashEvent(444, bucketStartTimeNs + NS_PER_SEC * 60 * 5 + 25);
+ processor->OnLogEvent(event.get());
+
+ // All activations expired.
+ event = CreateAppCrashEvent(555, bucketStartTimeNs + NS_PER_SEC * 60 * 8);
+ processor->OnLogEvent(event.get());
+ EXPECT_FALSE(metricProducer->mIsActive);
+ EXPECT_EQ(eventActivationMap[0].state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[0].activation_ns, bucketStartTimeNs + 10);
+ EXPECT_EQ(eventActivationMap[0].ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap[2].state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[2].activation_ns, bucketStartTimeNs + 20);
+ EXPECT_EQ(eventActivationMap[2].ttl_ns, 60 * 2 * NS_PER_SEC);
+
+ // Re-activate.
+ event = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
+ bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+ processor->OnLogEvent(event.get());
+ EXPECT_TRUE(metricProducer->mIsActive);
+ EXPECT_EQ(eventActivationMap[0].state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[0].activation_ns, bucketStartTimeNs + 10);
+ EXPECT_EQ(eventActivationMap[0].ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap[2].state, ActivationState::kActive);
+ EXPECT_EQ(eventActivationMap[2].activation_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+ EXPECT_EQ(eventActivationMap[2].ttl_ns, 60 * 2 * NS_PER_SEC);
+
+ event = CreateAppCrashEvent(666, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 1);
+ processor->OnLogEvent(event.get());
+
+ ConfigMetricsReportList reports;
+ vector<uint8_t> buffer;
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 1, false, ADB_DUMP,
+ &buffer);
+ EXPECT_TRUE(buffer.size() > 0);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ backfillDimensionPath(&reports);
+ backfillStartEndTimestamp(&reports);
+ EXPECT_EQ(1, reports.reports_size());
+ EXPECT_EQ(1, reports.reports(0).metrics_size());
+ EXPECT_EQ(4, reports.reports(0).metrics(0).count_metrics().data_size());
+
+ StatsLogReport::CountMetricDataWrapper countMetrics;
+ sortMetricDataByDimensionsValue(
+ reports.reports(0).metrics(0).count_metrics(), &countMetrics);
+ EXPECT_EQ(4, countMetrics.data_size());
+
+ auto data = countMetrics.data(0);
+ EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
+ EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ EXPECT_EQ(1 /* uid field */,
+ data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+ EXPECT_EQ(222, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
+ EXPECT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(1, data.bucket_info(0).count());
+ EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
+ EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
+
+ data = countMetrics.data(1);
+ EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
+ EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ EXPECT_EQ(1 /* uid field */,
+ data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+ EXPECT_EQ(333, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
+ EXPECT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(1, data.bucket_info(0).count());
+ EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
+ EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
+
+ data = countMetrics.data(2);
+ EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
+ EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ EXPECT_EQ(1 /* uid field */,
+ data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+ EXPECT_EQ(444, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
+ EXPECT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(1, data.bucket_info(0).count());
+ // Partial bucket as metric is deactivated.
+ EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
+ EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 8,
+ data.bucket_info(0).end_bucket_elapsed_nanos());
+
+ data = countMetrics.data(3);
+ EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
+ EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ EXPECT_EQ(1 /* uid field */,
+ data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+ EXPECT_EQ(666, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
+ EXPECT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(1, data.bucket_info(0).count());
+ EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
+ data.bucket_info(0).start_bucket_elapsed_nanos());
+ EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs,
+ data.bucket_info(0).end_bucket_elapsed_nanos());
+
+}
+
+
+#else
+GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
+
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp b/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
index bf58b9c7e4d4..60bd4a7e07d9 100644
--- a/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
@@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#include "src/matchers/SimpleLogMatchingTracker.h"
#include "src/metrics/GaugeMetricProducer.h"
#include "src/stats_log_util.h"
#include "logd/LogEvent.h"
@@ -40,6 +41,8 @@ namespace statsd {
const ConfigKey kConfigKey(0, 12345);
const int tagId = 1;
const int64_t metricId = 123;
+const int64_t atomMatcherId = 678;
+const int logEventMatcherIndex = 0;
const int64_t bucketStartTimeNs = 10 * NS_PER_SEC;
const int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
const int64_t bucket2StartTimeNs = bucketStartTimeNs + bucketSizeNs;
@@ -61,11 +64,19 @@ TEST(GaugeMetricProducerTest, TestFirstBucket) {
gaugeFieldMatcher->add_child()->set_field(3);
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+
+ UidMap uidMap;
+ SimpleAtomMatcher atomMatcher;
+ atomMatcher.set_atom_id(tagId);
+ sp<EventMatcherWizard> eventMatcherWizard = new EventMatcherWizard({
+ new SimpleLogMatchingTracker(atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
// statsd started long ago.
// The metric starts in the middle of the bucket
GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
+ logEventMatcherIndex, eventMatcherWizard,
-1, -1, tagId, 5, 600 * NS_PER_SEC + NS_PER_SEC / 2,
pullerManager);
@@ -86,6 +97,12 @@ TEST(GaugeMetricProducerTest, TestPulledEventsNoCondition) {
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+ UidMap uidMap;
+ SimpleAtomMatcher atomMatcher;
+ atomMatcher.set_atom_id(tagId);
+ sp<EventMatcherWizard> eventMatcherWizard = new EventMatcherWizard({
+ new SimpleLogMatchingTracker(atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
@@ -103,6 +120,7 @@ TEST(GaugeMetricProducerTest, TestPulledEventsNoCondition) {
}));
GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
+ logEventMatcherIndex, eventMatcherWizard,
tagId, -1, tagId, bucketStartTimeNs, bucketStartTimeNs,
pullerManager);
@@ -178,7 +196,15 @@ TEST(GaugeMetricProducerTest, TestPushedEventsWithUpgrade) {
alert.set_num_buckets(100);
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+
+ UidMap uidMap;
+ SimpleAtomMatcher atomMatcher;
+ atomMatcher.set_atom_id(tagId);
+ sp<EventMatcherWizard> eventMatcherWizard = new EventMatcherWizard({
+ new SimpleLogMatchingTracker(atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+
GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
+ logEventMatcherIndex, eventMatcherWizard,
-1 /* -1 means no pulling */, -1, tagId, bucketStartTimeNs,
bucketStartTimeNs, pullerManager);
@@ -246,6 +272,12 @@ TEST(GaugeMetricProducerTest, TestPulledWithUpgrade) {
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+ UidMap uidMap;
+ SimpleAtomMatcher atomMatcher;
+ atomMatcher.set_atom_id(tagId);
+ sp<EventMatcherWizard> eventMatcherWizard = new EventMatcherWizard({
+ new SimpleLogMatchingTracker(atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
@@ -263,6 +295,7 @@ TEST(GaugeMetricProducerTest, TestPulledWithUpgrade) {
}));
GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
+ logEventMatcherIndex, eventMatcherWizard,
tagId, -1, tagId, bucketStartTimeNs, bucketStartTimeNs,
pullerManager);
@@ -315,6 +348,12 @@ TEST(GaugeMetricProducerTest, TestPulledEventsWithCondition) {
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+ UidMap uidMap;
+ SimpleAtomMatcher atomMatcher;
+ atomMatcher.set_atom_id(tagId);
+ sp<EventMatcherWizard> eventMatcherWizard = new EventMatcherWizard({
+ new SimpleLogMatchingTracker(atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
@@ -330,7 +369,8 @@ TEST(GaugeMetricProducerTest, TestPulledEventsWithCondition) {
return true;
}));
- GaugeMetricProducer gaugeProducer(kConfigKey, metric, 1, wizard, tagId, -1, tagId,
+ GaugeMetricProducer gaugeProducer(kConfigKey, metric, 1, wizard,
+ logEventMatcherIndex, eventMatcherWizard, tagId, -1, tagId,
bucketStartTimeNs, bucketStartTimeNs, pullerManager);
gaugeProducer.onConditionChanged(true, bucketStartTimeNs + 8);
@@ -388,6 +428,12 @@ TEST(GaugeMetricProducerTest, TestPulledEventsWithSlicedCondition) {
dim->set_field(conditionTag);
dim->add_child()->set_field(1);
+ UidMap uidMap;
+ SimpleAtomMatcher atomMatcher;
+ atomMatcher.set_atom_id(tagId);
+ sp<EventMatcherWizard> eventMatcherWizard = new EventMatcherWizard({
+ new SimpleLogMatchingTracker(atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
EXPECT_CALL(*wizard, query(_, _, _, _, _, _))
.WillRepeatedly(
@@ -420,7 +466,8 @@ TEST(GaugeMetricProducerTest, TestPulledEventsWithSlicedCondition) {
return true;
}));
- GaugeMetricProducer gaugeProducer(kConfigKey, metric, 1, wizard, tagId, -1, tagId,
+ GaugeMetricProducer gaugeProducer(kConfigKey, metric, 1, wizard,
+ logEventMatcherIndex, eventMatcherWizard, tagId, -1, tagId,
bucketStartTimeNs, bucketStartTimeNs, pullerManager);
gaugeProducer.onSlicedConditionMayChange(true, bucketStartTimeNs + 8);
@@ -463,7 +510,15 @@ TEST(GaugeMetricProducerTest, TestPulledEventsAnomalyDetection) {
auto gaugeFieldMatcher = metric.mutable_gauge_fields_filter()->mutable_fields();
gaugeFieldMatcher->set_field(tagId);
gaugeFieldMatcher->add_child()->set_field(2);
+
+ UidMap uidMap;
+ SimpleAtomMatcher atomMatcher;
+ atomMatcher.set_atom_id(tagId);
+ sp<EventMatcherWizard> eventMatcherWizard = new EventMatcherWizard({
+ new SimpleLogMatchingTracker(atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+
GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
+ logEventMatcherIndex, eventMatcherWizard,
tagId, -1, tagId, bucketStartTimeNs, bucketStartTimeNs,
pullerManager);
@@ -542,6 +597,12 @@ TEST(GaugeMetricProducerTest, TestPullOnTrigger) {
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+ UidMap uidMap;
+ SimpleAtomMatcher atomMatcher;
+ atomMatcher.set_atom_id(tagId);
+ sp<EventMatcherWizard> eventMatcherWizard = new EventMatcherWizard({
+ new SimpleLogMatchingTracker(atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
EXPECT_CALL(*pullerManager, Pull(tagId, _, _))
.WillOnce(Invoke([](int tagId, int64_t timeNs,
@@ -574,6 +635,7 @@ TEST(GaugeMetricProducerTest, TestPullOnTrigger) {
int triggerId = 5;
GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
+ logEventMatcherIndex, eventMatcherWizard,
tagId, triggerId, tagId, bucketStartTimeNs, bucketStartTimeNs,
pullerManager);
@@ -632,6 +694,12 @@ TEST(GaugeMetricProducerTest, TestRemoveDimensionInOutput) {
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+ UidMap uidMap;
+ SimpleAtomMatcher atomMatcher;
+ atomMatcher.set_atom_id(tagId);
+ sp<EventMatcherWizard> eventMatcherWizard = new EventMatcherWizard({
+ new SimpleLogMatchingTracker(atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
EXPECT_CALL(*pullerManager, Pull(tagId, _, _))
.WillOnce(Invoke([](int tagId, int64_t timeNs,
@@ -667,6 +735,7 @@ TEST(GaugeMetricProducerTest, TestRemoveDimensionInOutput) {
int triggerId = 5;
GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
+ logEventMatcherIndex, eventMatcherWizard,
tagId, triggerId, tagId, bucketStartTimeNs, bucketStartTimeNs,
pullerManager);
diff --git a/cmds/statsd/tests/shell/ShellSubscriber_test.cpp b/cmds/statsd/tests/shell/ShellSubscriber_test.cpp
index b380b03e28d0..dd00561854fb 100644
--- a/cmds/statsd/tests/shell/ShellSubscriber_test.cpp
+++ b/cmds/statsd/tests/shell/ShellSubscriber_test.cpp
@@ -17,6 +17,7 @@
#include <unistd.h>
#include "frameworks/base/cmds/statsd/src/atoms.pb.h"
#include "frameworks/base/cmds/statsd/src/shell/shell_config.pb.h"
+#include "frameworks/base/cmds/statsd/src/shell/shell_data.pb.h"
#include "src/shell/ShellSubscriber.h"
#include "tests/metrics/metrics_test_helper.h"
@@ -26,7 +27,10 @@
using namespace android::os::statsd;
using android::sp;
using std::vector;
+using testing::_;
+using testing::Invoke;
using testing::NaggyMock;
+using testing::StrictMock;
#ifdef __ANDROID__
@@ -51,7 +55,10 @@ public:
}
};
-TEST(ShellSubscriberTest, testPushedSubscription) {
+void runShellTest(ShellSubscription config, sp<MockUidMap> uidMap,
+ sp<MockStatsPullerManager> pullerManager,
+ const vector<std::shared_ptr<LogEvent>>& pushedEvents,
+ const ShellData& expectedData) {
// set up 2 pipes for read/write config and data
int fds_config[2];
ASSERT_EQ(0, pipe(fds_config));
@@ -59,10 +66,6 @@ TEST(ShellSubscriberTest, testPushedSubscription) {
int fds_data[2];
ASSERT_EQ(0, pipe(fds_data));
- // create a simple config to get screen events
- ShellSubscription config;
- config.add_pushed()->set_atom_id(29);
-
size_t bufferSize = config.ByteSize();
// write the config to pipe, first write size of the config
@@ -75,15 +78,9 @@ TEST(ShellSubscriberTest, testPushedSubscription) {
write(fds_config[1], buffer.data(), bufferSize);
close(fds_config[1]);
- // create a shell subscriber.
- sp<MockUidMap> uidMap = new NaggyMock<MockUidMap>();
- sp<ShellSubscriber> shellClient = new ShellSubscriber(uidMap);
+ sp<ShellSubscriber> shellClient = new ShellSubscriber(uidMap, pullerManager);
sp<MyResultReceiver> resultReceiver = new MyResultReceiver();
- LogEvent event1(29, 1000);
- event1.write(2);
- event1.init();
-
// mimic a binder thread that a shell subscriber runs on. it would block.
std::thread reader([&resultReceiver, &fds_config, &fds_data, &shellClient] {
shellClient->startNewSubscription(fds_config[0], fds_data[1], resultReceiver);
@@ -93,44 +90,127 @@ TEST(ShellSubscriberTest, testPushedSubscription) {
// let the shell subscriber to receive the config from pipe.
std::this_thread::sleep_for(100ms);
- // send a log event that matches the config.
- std::thread log_reader([&shellClient, &event1] { shellClient->onLogEvent(event1); });
- log_reader.detach();
+ if (pushedEvents.size() > 0) {
+ // send a log event that matches the config.
+ std::thread log_reader([&shellClient, &pushedEvents] {
+ for (const auto& event : pushedEvents) {
+ shellClient->onLogEvent(*event);
+ }
+ });
+
+ log_reader.detach();
- if (log_reader.joinable()) {
- log_reader.join();
+ if (log_reader.joinable()) {
+ log_reader.join();
+ }
}
// wait for the data to be written.
std::this_thread::sleep_for(100ms);
- // this is the expected screen event atom.
- Atom atom;
- atom.mutable_screen_state_changed()->set_state(
- ::android::view::DisplayStateEnum::DISPLAY_STATE_ON);
-
- int atom_size = atom.ByteSize();
+ int expected_data_size = expectedData.ByteSize();
// now read from the pipe. firstly read the atom size.
size_t dataSize = 0;
EXPECT_EQ((int)sizeof(dataSize), read(fds_data[0], &dataSize, sizeof(dataSize)));
- EXPECT_EQ(atom_size, (int)dataSize);
+ EXPECT_EQ(expected_data_size, (int)dataSize);
// then read that much data which is the atom in proto binary format
vector<uint8_t> dataBuffer(dataSize);
EXPECT_EQ((int)dataSize, read(fds_data[0], dataBuffer.data(), dataSize));
// make sure the received bytes can be parsed to an atom
- Atom receivedAtom;
+ ShellData receivedAtom;
EXPECT_TRUE(receivedAtom.ParseFromArray(dataBuffer.data(), dataSize) != 0);
// serialze the expected atom to bytes. and compare. to make sure they are the same.
- vector<uint8_t> atomBuffer(atom_size);
- atom.SerializeToArray(&atomBuffer[0], atom_size);
+ vector<uint8_t> atomBuffer(expected_data_size);
+ expectedData.SerializeToArray(&atomBuffer[0], expected_data_size);
EXPECT_EQ(atomBuffer, dataBuffer);
close(fds_data[0]);
}
+TEST(ShellSubscriberTest, testPushedSubscription) {
+ sp<MockUidMap> uidMap = new NaggyMock<MockUidMap>();
+
+ sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+ vector<std::shared_ptr<LogEvent>> pushedList;
+
+ std::shared_ptr<LogEvent> event1 =
+ std::make_shared<LogEvent>(29 /*screen_state_atom_id*/, 1000 /*timestamp*/);
+ event1->write(::android::view::DisplayStateEnum::DISPLAY_STATE_ON);
+ event1->init();
+ pushedList.push_back(event1);
+
+ // create a simple config to get screen events
+ ShellSubscription config;
+ config.add_pushed()->set_atom_id(29);
+
+ // this is the expected screen event atom.
+ ShellData shellData;
+ shellData.add_atom()->mutable_screen_state_changed()->set_state(
+ ::android::view::DisplayStateEnum::DISPLAY_STATE_ON);
+
+ runShellTest(config, uidMap, pullerManager, pushedList, shellData);
+}
+
+namespace {
+
+int kUid1 = 1000;
+int kUid2 = 2000;
+
+int kCpuTime1 = 100;
+int kCpuTime2 = 200;
+
+ShellData getExpectedShellData() {
+ ShellData shellData;
+ auto* atom1 = shellData.add_atom()->mutable_cpu_active_time();
+ atom1->set_uid(kUid1);
+ atom1->set_time_millis(kCpuTime1);
+
+ auto* atom2 = shellData.add_atom()->mutable_cpu_active_time();
+ atom2->set_uid(kUid2);
+ atom2->set_time_millis(kCpuTime2);
+
+ return shellData;
+}
+
+ShellSubscription getPulledConfig() {
+ ShellSubscription config;
+ auto* pull_config = config.add_pulled();
+ pull_config->mutable_matcher()->set_atom_id(10016);
+ pull_config->set_freq_millis(2000);
+ return config;
+}
+
+} // namespace
+
+TEST(ShellSubscriberTest, testPulledSubscription) {
+ sp<MockUidMap> uidMap = new NaggyMock<MockUidMap>();
+
+ sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+ EXPECT_CALL(*pullerManager, Pull(10016, _, _))
+ .WillRepeatedly(
+ Invoke([](int tagId, int64_t timeNs, vector<std::shared_ptr<LogEvent>>* data) {
+ data->clear();
+ shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, timeNs);
+ event->write(kUid1);
+ event->write(kCpuTime1);
+ event->init();
+ data->push_back(event);
+ // another event
+ event = make_shared<LogEvent>(tagId, timeNs);
+ event->write(kUid2);
+ event->write(kCpuTime2);
+ event->init();
+ data->push_back(event);
+ return true;
+ }));
+
+ runShellTest(getPulledConfig(), uidMap, pullerManager, vector<std::shared_ptr<LogEvent>>(),
+ getExpectedShellData());
+}
+
#else
GTEST_LOG_(INFO) << "This test does nothing.\n";
#endif
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/config/preloaded-classes b/config/preloaded-classes
index 56ca98ff9888..1a8a32ec574f 100644
--- a/config/preloaded-classes
+++ b/config/preloaded-classes
@@ -2354,6 +2354,7 @@ android.nfc.NfcAdapter$1
android.nfc.NfcAdapter$CreateNdefMessageCallback
android.nfc.NfcManager
android.opengl.EGL14
+android.opengl.EGL15
android.opengl.EGLConfig
android.opengl.EGLContext
android.opengl.EGLDisplay
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index aca80b494b78..3cc5e370bc83 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -4678,7 +4678,7 @@ public class Activity extends ContextThemeWrapper
if (decor != null) {
decor.cancelPendingInputEvents();
}
- if (options != null && !isTopOfTask()) {
+ if (options != null) {
mActivityTransitionState.startExitOutTransition(this, options);
}
}
@@ -4882,6 +4882,7 @@ public class Activity extends ContextThemeWrapper
Bundle options)
throws IntentSender.SendIntentException {
try {
+ options = transferSpringboardActivityOptions(options);
String resolvedType = null;
if (fillInIntent != null) {
fillInIntent.migrateExtraStreamToClipData();
@@ -4898,6 +4899,12 @@ public class Activity extends ContextThemeWrapper
throw new IntentSender.SendIntentException();
}
Instrumentation.checkStartActivityResult(result, null);
+
+ if (options != null) {
+ // Only when the options are not null, as the intent can point to something other
+ // than an Activity.
+ cancelInputsAndStartExitTransition(options);
+ }
} catch (RemoteException e) {
}
if (requestCode >= 0) {
@@ -6471,7 +6478,7 @@ public class Activity extends ContextThemeWrapper
*
* @return true if this is the topmost, non-finishing activity in its task.
*/
- private boolean isTopOfTask() {
+ final boolean isTopOfTask() {
if (mToken == null || mWindow == null) {
return false;
}
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index 784ce04908fe..069effd3ef19 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;
@@ -123,17 +124,6 @@ public abstract class ActivityManagerInternal {
public abstract void notifyNetworkPolicyRulesUpdated(int uid, long procStateSeq);
/**
- * Saves the current activity manager state and includes the saved state in the next dump of
- * activity manager.
- */
- public abstract void saveANRState(String reason);
-
- /**
- * Clears the previously saved activity manager ANR state.
- */
- public abstract void clearSavedANRState();
-
- /**
* @return true if runtime was restarted, false if it's normal boot
*/
public abstract boolean isRuntimeRestarted();
@@ -165,10 +155,19 @@ public abstract class ActivityManagerInternal {
/**
* Returns a list that contains the memory stats for currently running processes.
+ *
+ * Only processes managed by ActivityManagerService are included.
*/
public abstract List<ProcessMemoryState> getMemoryStateForProcesses();
/**
+ * Returns a list that contains the memory stats for monitored native processes.
+ *
+ * The list of the monitored processes is defined in MemoryStatUtil class.
+ */
+ public abstract List<ProcessMemoryState> getMemoryStateForNativeProcesses();
+
+ /**
* Checks to see if the calling pid is allowed to handle the user. Returns adjusted user id as
* needed.
*/
@@ -187,9 +186,6 @@ public abstract class ActivityManagerInternal {
/** Trims memory usage in the system by removing/stopping unused application processes. */
public abstract void trimApplications();
- /** Closes all system dialogs. */
- public abstract void closeSystemDialogs(String reason);
-
/** Kill the processes in the list due to their tasks been removed. */
public abstract void killProcessesForRemovedTask(ArrayList<Object> procsToKill);
@@ -242,4 +238,46 @@ 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);
+
+ /** Input dispatch timeout to a window, start the ANR process. */
+ public abstract long inputDispatchingTimedOut(int pid, boolean aboveSystem, String reason);
+ public abstract boolean inputDispatchingTimedOut(Object proc, String activityShortComponentName,
+ ApplicationInfo aInfo, String parentShortComponentName, Object parentProc,
+ boolean aboveSystem, String reason);
+
+ /**
+ * Sends {@link android.content.Intent#ACTION_CONFIGURATION_CHANGED} with all the appropriate
+ * flags.
+ */
+ public abstract void broadcastGlobalConfigurationChanged(int changes, boolean initLocale);
+
+ /**
+ * Sends {@link android.content.Intent#ACTION_CLOSE_SYSTEM_DIALOGS} with all the appropriate
+ * flags.
+ */
+ public abstract void broadcastCloseSystemDialogs(String reason);
+
+ /**
+ * Kills all background processes, except those matching any of the specified properties.
+ *
+ * @param minTargetSdk the target SDK version at or above which to preserve processes,
+ * or {@code -1} to ignore the target SDK
+ * @param maxProcState the process state at or below which to preserve processes,
+ * or {@code -1} to ignore the process state
+ */
+ public abstract void killAllBackgroundProcessesExcept(int minTargetSdk, int maxProcState);
+
+ /** Starts a given process. */
+ public abstract void startProcess(String processName, ApplicationInfo info,
+ boolean knownToBeDead, String hostingType, ComponentName hostingName);
+
+ /** Starts up the starting activity process for debugging if needed. */
+ public abstract void setDebugFlagsForStartingActivity(ActivityInfo aInfo, int startFlags,
+ ProfilerInfo profilerInfo);
}
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index 3c9a2d4ab7e3..94b42ff960de 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -195,6 +195,13 @@ public class ActivityOptions {
private static final String KEY_LAUNCH_TASK_ID = "android.activity.launchTaskId";
/**
+ * See {@link #setPendingIntentLaunchFlags(int)}
+ * @hide
+ */
+ private static final String KEY_PENDING_INTENT_LAUNCH_FLAGS =
+ "android.activity.pendingIntentLaunchFlags";
+
+ /**
* See {@link #setTaskOverlay}.
* @hide
*/
@@ -309,6 +316,7 @@ public class ActivityOptions {
@WindowConfiguration.ActivityType
private int mLaunchActivityType = ACTIVITY_TYPE_UNDEFINED;
private int mLaunchTaskId = -1;
+ private int mPendingIntentLaunchFlags;
private int mSplitScreenCreateMode = SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT;
private boolean mLockTaskMode = false;
private boolean mDisallowEnterPictureInPictureWhileLaunching;
@@ -932,6 +940,7 @@ public class ActivityOptions {
mLaunchWindowingMode = opts.getInt(KEY_LAUNCH_WINDOWING_MODE, WINDOWING_MODE_UNDEFINED);
mLaunchActivityType = opts.getInt(KEY_LAUNCH_ACTIVITY_TYPE, ACTIVITY_TYPE_UNDEFINED);
mLaunchTaskId = opts.getInt(KEY_LAUNCH_TASK_ID, -1);
+ mPendingIntentLaunchFlags = opts.getInt(KEY_PENDING_INTENT_LAUNCH_FLAGS, 0);
mTaskOverlay = opts.getBoolean(KEY_TASK_OVERLAY, false);
mTaskOverlayCanResume = opts.getBoolean(KEY_TASK_OVERLAY_CAN_RESUME, false);
mAvoidMoveToFront = opts.getBoolean(KEY_AVOID_MOVE_TO_FRONT, false);
@@ -1233,6 +1242,22 @@ public class ActivityOptions {
}
/**
+ * Specifies intent flags to be applied for any activity started from a PendingIntent.
+ *
+ * @hide
+ */
+ public void setPendingIntentLaunchFlags(@android.content.Intent.Flags int flags) {
+ mPendingIntentLaunchFlags = flags;
+ }
+
+ /**
+ * @hide
+ */
+ public int getPendingIntentLaunchFlags() {
+ return mPendingIntentLaunchFlags;
+ }
+
+ /**
* Set's whether the activity launched with this option should be a task overlay. That is the
* activity will always be the top activity of the task. If {@param canResume} is true, then
* the task will also not be moved to the front of the stack.
@@ -1463,6 +1488,9 @@ public class ActivityOptions {
if (mLaunchTaskId != -1) {
b.putInt(KEY_LAUNCH_TASK_ID, mLaunchTaskId);
}
+ if (mPendingIntentLaunchFlags != 0) {
+ b.putInt(KEY_PENDING_INTENT_LAUNCH_FLAGS, mPendingIntentLaunchFlags);
+ }
if (mTaskOverlay) {
b.putBoolean(KEY_TASK_OVERLAY, mTaskOverlay);
}
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 990ffd6d5c0f..6090938066a4 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -5055,7 +5055,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 */);
}
/**
@@ -5407,7 +5407,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;
diff --git a/core/java/android/app/ActivityTransitionCoordinator.java b/core/java/android/app/ActivityTransitionCoordinator.java
index 9b2bfc5702cb..4b87a647a80b 100644
--- a/core/java/android/app/ActivityTransitionCoordinator.java
+++ b/core/java/android/app/ActivityTransitionCoordinator.java
@@ -193,6 +193,13 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver {
*/
public static final int MSG_SHARED_ELEMENT_DESTINATION = 107;
+ /**
+ * Sent by Activity#startActivity to notify the entering activity that enter animation for
+ * back is allowed. If this message is not received, the default exit animation will run when
+ * backing out of an activity (instead of the 'reverse' shared element transition).
+ */
+ public static final int MSG_ALLOW_RETURN_TRANSITION = 108;
+
private Window mWindow;
final protected ArrayList<String> mAllSharedElementNames;
final protected ArrayList<View> mSharedElements = new ArrayList<View>();
@@ -346,8 +353,6 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver {
return new ArrayList<View>(mSharedElements);
}
- public ArrayList<String> getAllSharedElementNames() { return mAllSharedElementNames; }
-
protected Transition setTargets(Transition transition, boolean add) {
if (transition == null || (add &&
(mTransitioningViews == null || mTransitioningViews.isEmpty()))) {
diff --git a/core/java/android/app/ActivityTransitionState.java b/core/java/android/app/ActivityTransitionState.java
index b8f5a8e94283..3201febec8da 100644
--- a/core/java/android/app/ActivityTransitionState.java
+++ b/core/java/android/app/ActivityTransitionState.java
@@ -35,7 +35,7 @@ import java.util.ArrayList;
*/
class ActivityTransitionState {
- private static final String ENTERING_SHARED_ELEMENTS = "android:enteringSharedElements";
+ private static final String PENDING_EXIT_SHARED_ELEMENTS = "android:pendingExitSharedElements";
private static final String EXITING_MAPPED_FROM = "android:exitingMappedFrom";
@@ -43,9 +43,9 @@ class ActivityTransitionState {
/**
* The shared elements that the calling Activity has said that they transferred to this
- * Activity.
+ * Activity and will be transferred back during exit animation.
*/
- private ArrayList<String> mEnteringNames;
+ private ArrayList<String> mPendingExitNames;
/**
* The names of shared elements that were shared to the called Activity.
@@ -112,8 +112,7 @@ class ActivityTransitionState {
public int addExitTransitionCoordinator(ExitTransitionCoordinator exitTransitionCoordinator) {
if (mExitTransitionCoordinators == null) {
- mExitTransitionCoordinators =
- new SparseArray<WeakReference<ExitTransitionCoordinator>>();
+ mExitTransitionCoordinators = new SparseArray<>();
}
WeakReference<ExitTransitionCoordinator> ref = new WeakReference(exitTransitionCoordinator);
// clean up old references:
@@ -132,7 +131,7 @@ class ActivityTransitionState {
public void readState(Bundle bundle) {
if (bundle != null) {
if (mEnterTransitionCoordinator == null || mEnterTransitionCoordinator.isReturning()) {
- mEnteringNames = bundle.getStringArrayList(ENTERING_SHARED_ELEMENTS);
+ mPendingExitNames = bundle.getStringArrayList(PENDING_EXIT_SHARED_ELEMENTS);
}
if (mEnterTransitionCoordinator == null) {
mExitingFrom = bundle.getStringArrayList(EXITING_MAPPED_FROM);
@@ -141,9 +140,21 @@ class ActivityTransitionState {
}
}
+ /**
+ * Returns the element names to be used for exit animation. It caches the list internally so
+ * that it is preserved through activty destroy and restore.
+ */
+ private ArrayList<String> getPendingExitNames() {
+ if (mPendingExitNames == null && mEnterTransitionCoordinator != null) {
+ mPendingExitNames = mEnterTransitionCoordinator.getPendingExitSharedElementNames();
+ }
+ return mPendingExitNames;
+ }
+
public void saveState(Bundle bundle) {
- if (mEnteringNames != null) {
- bundle.putStringArrayList(ENTERING_SHARED_ELEMENTS, mEnteringNames);
+ ArrayList<String> pendingExitNames = getPendingExitNames();
+ if (pendingExitNames != null) {
+ bundle.putStringArrayList(PENDING_EXIT_SHARED_ELEMENTS, pendingExitNames);
}
if (mExitingFrom != null) {
bundle.putStringArrayList(EXITING_MAPPED_FROM, mExitingFrom);
@@ -226,7 +237,7 @@ class ActivityTransitionState {
}
} else {
mEnterTransitionCoordinator.namedViewsReady(null, null);
- mEnteringNames = mEnterTransitionCoordinator.getAllSharedElementNames();
+ mPendingExitNames = null;
}
mExitingFrom = null;
@@ -268,7 +279,7 @@ class ActivityTransitionState {
}
public void clear() {
- mEnteringNames = null;
+ mPendingExitNames = null;
mExitingFrom = null;
mExitingTo = null;
mExitingToView = null;
@@ -296,7 +307,8 @@ class ActivityTransitionState {
}
public boolean startExitBackTransition(final Activity activity) {
- if (mEnteringNames == null || mCalledExitCoordinator != null) {
+ ArrayList<String> pendingExitNames = getPendingExitNames();
+ if (pendingExitNames == null || mCalledExitCoordinator != null) {
return false;
} else {
if (!mHasExited) {
@@ -315,7 +327,7 @@ class ActivityTransitionState {
}
mReturnExitCoordinator = new ExitTransitionCoordinator(activity,
- activity.getWindow(), activity.mEnterTransitionListener, mEnteringNames,
+ activity.getWindow(), activity.mEnterTransitionListener, pendingExitNames,
null, null, true);
if (enterViewsTransition != null && decor != null) {
enterViewsTransition.resume(decor);
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/EnterTransitionCoordinator.java b/core/java/android/app/EnterTransitionCoordinator.java
index ab847fd562a4..bce243cc6108 100644
--- a/core/java/android/app/EnterTransitionCoordinator.java
+++ b/core/java/android/app/EnterTransitionCoordinator.java
@@ -65,6 +65,7 @@ class EnterTransitionCoordinator extends ActivityTransitionCoordinator {
private OneShotPreDrawListener mViewsReadyListener;
private final boolean mIsCrossTask;
private Drawable mReplacedBackground;
+ private ArrayList<String> mPendingExitNames;
public EnterTransitionCoordinator(Activity activity, ResultReceiver resultReceiver,
ArrayList<String> sharedElementNames, boolean isReturning, boolean isCrossTask) {
@@ -249,6 +250,11 @@ class EnterTransitionCoordinator extends ActivityTransitionCoordinator {
case MSG_CANCEL:
cancel();
break;
+ case MSG_ALLOW_RETURN_TRANSITION:
+ if (!mIsCanceled) {
+ mPendingExitNames = mAllSharedElementNames;
+ }
+ break;
}
}
@@ -256,6 +262,10 @@ class EnterTransitionCoordinator extends ActivityTransitionCoordinator {
return mIsReturning && mResultReceiver != null;
}
+ public ArrayList<String> getPendingExitSharedElementNames() {
+ return mPendingExitNames;
+ }
+
/**
* This is called onResume. If an Activity is resuming and the transitions
* haven't started yet, force the views to appear. This is likely to be
diff --git a/core/java/android/app/ExitTransitionCoordinator.java b/core/java/android/app/ExitTransitionCoordinator.java
index df31da9183f1..48a711e79c39 100644
--- a/core/java/android/app/ExitTransitionCoordinator.java
+++ b/core/java/android/app/ExitTransitionCoordinator.java
@@ -433,6 +433,11 @@ class ExitTransitionCoordinator extends ActivityTransitionCoordinator {
if (!mSharedElementNotified) {
mSharedElementNotified = true;
delayCancel();
+
+ if (!mActivity.isTopOfTask()) {
+ mResultReceiver.send(MSG_ALLOW_RETURN_TRANSITION, null);
+ }
+
if (mListener == null) {
mResultReceiver.send(MSG_TAKE_SHARED_ELEMENTS, mSharedElementBundle);
notifyExitComplete();
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index b57a7d982960..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;
@@ -7759,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;
@@ -7874,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()
@@ -7890,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() {
@@ -7905,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);
@@ -7949,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/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 74fb4df112b8..92daf08dc59b 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -51,6 +51,7 @@ import android.content.pm.UserInfo;
import android.graphics.Bitmap;
import android.net.ProxyInfo;
import android.net.Uri;
+import android.os.Binder;
import android.os.Bundle;
import android.os.Parcelable;
import android.os.PersistableBundle;
@@ -1898,6 +1899,36 @@ public class DevicePolicyManager {
public static final String ACTION_PROFILE_OWNER_CHANGED =
"android.app.action.PROFILE_OWNER_CHANGED";
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(flag = true, prefix = {"PRIVATE_DNS_MODE_"}, value = {
+ PRIVATE_DNS_MODE_UNKNOWN,
+ PRIVATE_DNS_MODE_OFF,
+ PRIVATE_DNS_MODE_OPPORTUNISTIC,
+ PRIVATE_DNS_MODE_PROVIDER_HOSTNAME
+ })
+ public @interface PrivateDnsMode {}
+
+ /**
+ * Specifies that the Private DNS setting is in an unknown state.
+ */
+ public static final int PRIVATE_DNS_MODE_UNKNOWN = 0;
+
+ /**
+ * Specifies that Private DNS was turned off completely.
+ */
+ public static final int PRIVATE_DNS_MODE_OFF = 1;
+
+ /**
+ * Specifies that the device owner requested opportunistic DNS over TLS
+ */
+ public static final int PRIVATE_DNS_MODE_OPPORTUNISTIC = 2;
+
+ /**
+ * Specifies that the device owner configured a specific host to use for Private DNS.
+ */
+ public static final int PRIVATE_DNS_MODE_PROVIDER_HOSTNAME = 3;
+
/**
* Return true if the given administrator component is currently active (enabled) in the system.
*
@@ -5756,7 +5787,8 @@ public class DevicePolicyManager {
}
if (mService != null) {
try {
- return mService.checkDeviceIdentifierAccess(packageName, userId);
+ return mService.checkDeviceIdentifierAccess(packageName, userId,
+ Binder.getCallingPid(), Binder.getCallingUid());
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
}
@@ -9754,4 +9786,80 @@ public class DevicePolicyManager {
throw re.rethrowFromSystemServer();
}
}
+
+
+ /**
+ * Sets the global Private DNS mode and host to be used.
+ * May only be called by the device owner.
+ *
+ * @param admin which {@link DeviceAdminReceiver} this request is associated with.
+ * @param mode Which mode to set - either {@code PRIVATE_DNS_MODE_OPPORTUNISTIC} or
+ * {@code PRIVATE_DNS_MODE_PROVIDER_HOSTNAME}.
+ * Since the opportunistic mode defaults to ordinary DNS lookups, the
+ * option to turn it completely off is not available, so this method
+ * may not be called with {@code PRIVATE_DNS_MODE_OFF}.
+ * @param privateDnsHost The hostname of a server that implements DNS over TLS (RFC7858), if
+ * {@code PRIVATE_DNS_MODE_PROVIDER_HOSTNAME} was specified as the mode,
+ * null otherwise.
+ * @throws IllegalArgumentException in the following cases: if a {@code privateDnsHost} was
+ * provided but the mode was not {@code PRIVATE_DNS_MODE_PROVIDER_HOSTNAME}, if the mode
+ * specified was {@code PRIVATE_DNS_MODE_PROVIDER_HOSTNAME} but {@code privateDnsHost} does
+ * not look like a valid hostname, or if the mode specified is not one of the two valid modes.
+ *
+ * @throws SecurityException if the caller is not the device owner.
+ */
+ public void setGlobalPrivateDns(@NonNull ComponentName admin,
+ @PrivateDnsMode int mode, @Nullable String privateDnsHost) {
+ throwIfParentInstance("setGlobalPrivateDns");
+ if (mService == null) {
+ return;
+ }
+
+ try {
+ mService.setGlobalPrivateDns(admin, mode, privateDnsHost);
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Returns the system-wide Private DNS mode.
+ *
+ * @param admin which {@link DeviceAdminReceiver} this request is associated with.
+ * @return one of {@code PRIVATE_DNS_MODE_OFF}, {@code PRIVATE_DNS_MODE_OPPORTUNISTIC},
+ * {@code PRIVATE_DNS_MODE_PROVIDER_HOSTNAME} or {@code PRIVATE_DNS_MODE_UNKNOWN}.
+ * @throws SecurityException if the caller is not the device owner.
+ */
+ public int getGlobalPrivateDnsMode(@NonNull ComponentName admin) {
+ throwIfParentInstance("setGlobalPrivateDns");
+ if (mService == null) {
+ return PRIVATE_DNS_MODE_UNKNOWN;
+ }
+
+ try {
+ return mService.getGlobalPrivateDnsMode(admin);
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Returns the system-wide Private DNS host.
+ *
+ * @param admin which {@link DeviceAdminReceiver} this request is associated with.
+ * @return The hostname used for Private DNS queries.
+ * @throws SecurityException if the caller is not the device owner.
+ */
+ public String getGlobalPrivateDnsHost(@NonNull ComponentName admin) {
+ throwIfParentInstance("setGlobalPrivateDns");
+ if (mService == null) {
+ return null;
+ }
+
+ try {
+ return mService.getGlobalPrivateDnsHost(admin);
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
}
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 5e454506e9eb..ce1f4ef9e2e4 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -153,7 +153,7 @@ interface IDevicePolicyManager {
void clearProfileOwner(in ComponentName who);
boolean hasUserSetupCompleted();
- boolean checkDeviceIdentifierAccess(in String packageName, int userHandle);
+ boolean checkDeviceIdentifierAccess(in String packageName, int userHandle, int pid, int uid);
void setDeviceOwnerLockScreenInfo(in ComponentName who, CharSequence deviceOwnerInfo);
CharSequence getDeviceOwnerLockScreenInfo();
@@ -413,4 +413,8 @@ interface IDevicePolicyManager {
boolean isOverrideApnEnabled(in ComponentName admin);
boolean isMeteredDataDisabledPackageForUser(in ComponentName admin, String packageName, int userId);
+
+ void setGlobalPrivateDns(in ComponentName admin, int mode, in String privateDnsHost);
+ int getGlobalPrivateDnsMode(in ComponentName admin);
+ String getGlobalPrivateDnsHost(in ComponentName admin);
}
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/BluetoothA2dpSink.java b/core/java/android/bluetooth/BluetoothA2dpSink.java
index fda2f8927535..cb996f3381b7 100755
--- a/core/java/android/bluetooth/BluetoothA2dpSink.java
+++ b/core/java/android/bluetooth/BluetoothA2dpSink.java
@@ -24,6 +24,7 @@ import android.content.ServiceConnection;
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
+import android.os.UserHandle;
import android.util.Log;
import java.util.ArrayList;
@@ -183,7 +184,7 @@ public final class BluetoothA2dpSink implements BluetoothProfile {
ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
intent.setComponent(comp);
if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0,
- mContext.getUser())) {
+ UserHandle.CURRENT_OR_SELF)) {
Log.e(TAG, "Could not bind to Bluetooth A2DP Service with " + intent);
return false;
}
diff --git a/core/java/android/bluetooth/BluetoothAvrcpController.java b/core/java/android/bluetooth/BluetoothAvrcpController.java
index e7c8944788fd..c447868d6f0c 100644
--- a/core/java/android/bluetooth/BluetoothAvrcpController.java
+++ b/core/java/android/bluetooth/BluetoothAvrcpController.java
@@ -23,6 +23,7 @@ import android.content.ServiceConnection;
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
+import android.os.UserHandle;
import android.util.Log;
import java.util.ArrayList;
@@ -138,7 +139,7 @@ public final class BluetoothAvrcpController implements BluetoothProfile {
ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
intent.setComponent(comp);
if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0,
- mContext.getUser())) {
+ UserHandle.CURRENT_OR_SELF)) {
Log.e(TAG, "Could not bind to Bluetooth AVRCP Controller Service with " + intent);
return false;
}
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index c926cf7650e2..95e83019c2ee 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -142,20 +142,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}.
@@ -793,7 +779,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;
@@ -2146,9 +2132,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..d616b8f92d3a 100644
--- a/core/java/android/bluetooth/BluetoothGatt.java
+++ b/core/java/android/bluetooth/BluetoothGatt.java
@@ -57,6 +57,7 @@ public final class BluetoothGatt implements BluetoothProfile {
private int mAuthRetryState;
private int mConnState;
private final Object mStateLock = new Object();
+ private final Object mDeviceBusyLock = new Object();
@UnsupportedAppUsage
private Boolean mDeviceBusy = false;
@UnsupportedAppUsage
@@ -282,7 +283,7 @@ public final class BluetoothGatt implements BluetoothProfile {
}
}
- synchronized (mDeviceBusy) {
+ synchronized (mDeviceBusyLock) {
mDeviceBusy = false;
}
}
@@ -357,7 +358,7 @@ public final class BluetoothGatt implements BluetoothProfile {
return;
}
- synchronized (mDeviceBusy) {
+ synchronized (mDeviceBusyLock) {
mDeviceBusy = false;
}
@@ -413,7 +414,7 @@ public final class BluetoothGatt implements BluetoothProfile {
return;
}
- synchronized (mDeviceBusy) {
+ synchronized (mDeviceBusyLock) {
mDeviceBusy = false;
}
@@ -496,7 +497,7 @@ public final class BluetoothGatt implements BluetoothProfile {
return;
}
- synchronized (mDeviceBusy) {
+ synchronized (mDeviceBusyLock) {
mDeviceBusy = false;
}
@@ -547,7 +548,7 @@ public final class BluetoothGatt implements BluetoothProfile {
return;
}
- synchronized (mDeviceBusy) {
+ synchronized (mDeviceBusyLock) {
mDeviceBusy = false;
}
@@ -596,7 +597,7 @@ public final class BluetoothGatt implements BluetoothProfile {
return;
}
- synchronized (mDeviceBusy) {
+ synchronized (mDeviceBusyLock) {
mDeviceBusy = false;
}
@@ -1098,7 +1099,7 @@ public final class BluetoothGatt implements BluetoothProfile {
BluetoothDevice device = service.getDevice();
if (device == null) return false;
- synchronized (mDeviceBusy) {
+ synchronized (mDeviceBusyLock) {
if (mDeviceBusy) return false;
mDeviceBusy = true;
}
@@ -1132,7 +1133,7 @@ public final class BluetoothGatt implements BluetoothProfile {
if (VDBG) Log.d(TAG, "readUsingCharacteristicUuid() - uuid: " + uuid);
if (mService == null || mClientIf == 0) return false;
- synchronized (mDeviceBusy) {
+ synchronized (mDeviceBusyLock) {
if (mDeviceBusy) return false;
mDeviceBusy = true;
}
@@ -1178,7 +1179,7 @@ public final class BluetoothGatt implements BluetoothProfile {
BluetoothDevice device = service.getDevice();
if (device == null) return false;
- synchronized (mDeviceBusy) {
+ synchronized (mDeviceBusyLock) {
if (mDeviceBusy) return false;
mDeviceBusy = true;
}
@@ -1221,7 +1222,7 @@ public final class BluetoothGatt implements BluetoothProfile {
BluetoothDevice device = service.getDevice();
if (device == null) return false;
- synchronized (mDeviceBusy) {
+ synchronized (mDeviceBusyLock) {
if (mDeviceBusy) return false;
mDeviceBusy = true;
}
@@ -1262,7 +1263,7 @@ public final class BluetoothGatt implements BluetoothProfile {
BluetoothDevice device = service.getDevice();
if (device == null) return false;
- synchronized (mDeviceBusy) {
+ synchronized (mDeviceBusyLock) {
if (mDeviceBusy) return false;
mDeviceBusy = true;
}
@@ -1292,7 +1293,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.
@@ -1330,7 +1331,7 @@ public final class BluetoothGatt implements BluetoothProfile {
if (VDBG) Log.d(TAG, "executeReliableWrite() - device: " + mDevice.getAddress());
if (mService == null || mClientIf == 0) return false;
- synchronized (mDeviceBusy) {
+ synchronized (mDeviceBusyLock) {
if (mDeviceBusy) return false;
mDeviceBusy = true;
}
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/BluetoothHeadsetClient.java b/core/java/android/bluetooth/BluetoothHeadsetClient.java
index ec18d42698c1..549c1faddd90 100644
--- a/core/java/android/bluetooth/BluetoothHeadsetClient.java
+++ b/core/java/android/bluetooth/BluetoothHeadsetClient.java
@@ -25,6 +25,7 @@ import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
+import android.os.UserHandle;
import android.util.Log;
import java.util.ArrayList;
@@ -428,7 +429,7 @@ public final class BluetoothHeadsetClient implements BluetoothProfile {
ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
intent.setComponent(comp);
if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0,
- mContext.getUser())) {
+ UserHandle.CURRENT_OR_SELF)) {
Log.e(TAG, "Could not bind to Bluetooth Headset Client Service with " + intent);
return false;
}
diff --git a/core/java/android/bluetooth/BluetoothHealth.java b/core/java/android/bluetooth/BluetoothHealth.java
index b967fb20f023..22d41d9c896e 100644
--- a/core/java/android/bluetooth/BluetoothHealth.java
+++ b/core/java/android/bluetooth/BluetoothHealth.java
@@ -24,6 +24,7 @@ import android.os.Binder;
import android.os.IBinder;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
+import android.os.UserHandle;
import android.util.Log;
import java.util.ArrayList;
@@ -491,7 +492,7 @@ public final class BluetoothHealth implements BluetoothProfile {
ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
intent.setComponent(comp);
if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0,
- mContext.getUser())) {
+ UserHandle.CURRENT_OR_SELF)) {
Log.e(TAG, "Could not bind to Bluetooth Health Service with " + intent);
return false;
}
diff --git a/core/java/android/bluetooth/BluetoothHearingAid.java b/core/java/android/bluetooth/BluetoothHearingAid.java
index 69be7d4d3956..3fab791f5230 100644
--- a/core/java/android/bluetooth/BluetoothHearingAid.java
+++ b/core/java/android/bluetooth/BluetoothHearingAid.java
@@ -29,6 +29,7 @@ import android.content.ServiceConnection;
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
+import android.os.UserHandle;
import android.util.Log;
import com.android.internal.annotations.GuardedBy;
@@ -207,7 +208,7 @@ public final class BluetoothHearingAid implements BluetoothProfile {
ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
intent.setComponent(comp);
if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0,
- android.os.Process.myUserHandle())) {
+ UserHandle.CURRENT_OR_SELF)) {
Log.e(TAG, "Could not bind to Bluetooth Hearing Aid Service with " + intent);
return;
}
diff --git a/core/java/android/bluetooth/BluetoothHidDevice.java b/core/java/android/bluetooth/BluetoothHidDevice.java
index 3bc8544ebf87..e44f36e90c75 100644
--- a/core/java/android/bluetooth/BluetoothHidDevice.java
+++ b/core/java/android/bluetooth/BluetoothHidDevice.java
@@ -24,6 +24,7 @@ import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.os.RemoteException;
+import android.os.UserHandle;
import android.util.Log;
import java.util.ArrayList;
@@ -454,7 +455,7 @@ public final class BluetoothHidDevice implements BluetoothProfile {
ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
intent.setComponent(comp);
if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0,
- mContext.getUser())) {
+ UserHandle.CURRENT_OR_SELF)) {
Log.e(TAG, "Could not bind to Bluetooth HID Device Service with " + intent);
return false;
}
diff --git a/core/java/android/bluetooth/BluetoothHidHost.java b/core/java/android/bluetooth/BluetoothHidHost.java
index 0ca39f169a72..58a25221552a 100644
--- a/core/java/android/bluetooth/BluetoothHidHost.java
+++ b/core/java/android/bluetooth/BluetoothHidHost.java
@@ -25,6 +25,7 @@ import android.content.ServiceConnection;
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
+import android.os.UserHandle;
import android.util.Log;
import java.util.ArrayList;
@@ -279,7 +280,7 @@ public final class BluetoothHidHost implements BluetoothProfile {
ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
intent.setComponent(comp);
if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0,
- mContext.getUser())) {
+ UserHandle.CURRENT_OR_SELF)) {
Log.e(TAG, "Could not bind to Bluetooth HID Service with " + intent);
return false;
}
diff --git a/core/java/android/bluetooth/BluetoothMap.java b/core/java/android/bluetooth/BluetoothMap.java
index 98c23c600f14..fc5f830a8940 100644
--- a/core/java/android/bluetooth/BluetoothMap.java
+++ b/core/java/android/bluetooth/BluetoothMap.java
@@ -24,6 +24,7 @@ import android.content.ServiceConnection;
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
+import android.os.UserHandle;
import android.util.Log;
import java.util.ArrayList;
@@ -110,7 +111,7 @@ public final class BluetoothMap implements BluetoothProfile {
ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
intent.setComponent(comp);
if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0,
- mContext.getUser())) {
+ UserHandle.CURRENT_OR_SELF)) {
Log.e(TAG, "Could not bind to Bluetooth MAP Service with " + intent);
return false;
}
diff --git a/core/java/android/bluetooth/BluetoothMapClient.java b/core/java/android/bluetooth/BluetoothMapClient.java
index 559a59b68b4e..1c82e1984b66 100644
--- a/core/java/android/bluetooth/BluetoothMapClient.java
+++ b/core/java/android/bluetooth/BluetoothMapClient.java
@@ -25,6 +25,7 @@ import android.content.ServiceConnection;
import android.net.Uri;
import android.os.IBinder;
import android.os.RemoteException;
+import android.os.UserHandle;
import android.util.Log;
import java.util.ArrayList;
@@ -128,7 +129,7 @@ public final class BluetoothMapClient implements BluetoothProfile {
ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
intent.setComponent(comp);
if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0,
- mContext.getUser())) {
+ UserHandle.CURRENT_OR_SELF)) {
Log.e(TAG, "Could not bind to Bluetooth MAP MCE Service with " + intent);
return false;
}
diff --git a/core/java/android/bluetooth/BluetoothPan.java b/core/java/android/bluetooth/BluetoothPan.java
index 58be73296027..8923d734c844 100644
--- a/core/java/android/bluetooth/BluetoothPan.java
+++ b/core/java/android/bluetooth/BluetoothPan.java
@@ -26,6 +26,7 @@ import android.content.ServiceConnection;
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
+import android.os.UserHandle;
import android.util.Log;
import java.util.ArrayList;
@@ -150,7 +151,7 @@ public final class BluetoothPan implements BluetoothProfile {
ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
intent.setComponent(comp);
if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0,
- mContext.getUser())) {
+ UserHandle.CURRENT_OR_SELF)) {
Log.e(TAG, "Could not bind to Bluetooth Pan Service with " + intent);
return false;
}
diff --git a/core/java/android/bluetooth/BluetoothPbap.java b/core/java/android/bluetooth/BluetoothPbap.java
index ae264e19bb7c..a601df02d032 100644
--- a/core/java/android/bluetooth/BluetoothPbap.java
+++ b/core/java/android/bluetooth/BluetoothPbap.java
@@ -24,6 +24,7 @@ import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.os.RemoteException;
+import android.os.UserHandle;
import android.util.Log;
import java.util.ArrayList;
@@ -164,7 +165,7 @@ public class BluetoothPbap implements BluetoothProfile {
ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
intent.setComponent(comp);
if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0,
- mContext.getUser())) {
+ UserHandle.CURRENT_OR_SELF)) {
Log.e(TAG, "Could not bind to Bluetooth Pbap Service with " + intent);
return false;
}
diff --git a/core/java/android/bluetooth/BluetoothPbapClient.java b/core/java/android/bluetooth/BluetoothPbapClient.java
index 1446adc8b9c3..cbc96c073338 100644
--- a/core/java/android/bluetooth/BluetoothPbapClient.java
+++ b/core/java/android/bluetooth/BluetoothPbapClient.java
@@ -23,6 +23,7 @@ import android.content.ServiceConnection;
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
+import android.os.UserHandle;
import android.util.Log;
import java.util.ArrayList;
@@ -116,7 +117,7 @@ public final class BluetoothPbapClient implements BluetoothProfile {
ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
intent.setComponent(comp);
if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0,
- mContext.getUser())) {
+ UserHandle.CURRENT_OR_SELF)) {
Log.e(TAG, "Could not bind to Bluetooth PBAP Client Service with " + intent);
return false;
}
diff --git a/core/java/android/bluetooth/BluetoothSap.java b/core/java/android/bluetooth/BluetoothSap.java
index 1b732062f614..ebf6bed54475 100644
--- a/core/java/android/bluetooth/BluetoothSap.java
+++ b/core/java/android/bluetooth/BluetoothSap.java
@@ -24,6 +24,7 @@ import android.content.ServiceConnection;
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
+import android.os.UserHandle;
import android.util.Log;
import java.util.ArrayList;
@@ -148,7 +149,7 @@ public final class BluetoothSap implements BluetoothProfile {
ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
intent.setComponent(comp);
if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0,
- mContext.getUser())) {
+ UserHandle.CURRENT_OR_SELF)) {
Log.e(TAG, "Could not bind to Bluetooth SAP Service with " + intent);
return false;
}
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/ContentProvider.java b/core/java/android/content/ContentProvider.java
index 2a03787f134c..145c92731458 100644
--- a/core/java/android/content/ContentProvider.java
+++ b/core/java/android/content/ContentProvider.java
@@ -822,6 +822,48 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
}
/**
+ * Opaque token representing the identity of an incoming IPC.
+ */
+ public final class CallingIdentity {
+ /** {@hide} */
+ public final long binderToken;
+ /** {@hide} */
+ public final String callingPackage;
+
+ /** {@hide} */
+ public CallingIdentity(long binderToken, String callingPackage) {
+ this.binderToken = binderToken;
+ this.callingPackage = callingPackage;
+ }
+ }
+
+ /**
+ * Reset the identity of the incoming IPC on the current thread.
+ * <p>
+ * Internally this calls {@link Binder#clearCallingIdentity()} and also
+ * clears any value stored in {@link #getCallingPackage()}.
+ *
+ * @return Returns an opaque token that can be used to restore the original
+ * calling identity by passing it to
+ * {@link #restoreCallingIdentity}.
+ */
+ public final @NonNull CallingIdentity clearCallingIdentity() {
+ return new CallingIdentity(Binder.clearCallingIdentity(), setCallingPackage(null));
+ }
+
+ /**
+ * Restore the identity of the incoming IPC on the current thread back to a
+ * previously identity that was returned by {@link #clearCallingIdentity}.
+ * <p>
+ * Internally this calls {@link Binder#restoreCallingIdentity(long)} and
+ * also restores any value stored in {@link #getCallingPackage()}.
+ */
+ public final void restoreCallingIdentity(@NonNull CallingIdentity identity) {
+ Binder.restoreCallingIdentity(identity.binderToken);
+ mCallingPackage.set(identity.callingPackage);
+ }
+
+ /**
* Change the authorities of the ContentProvider.
* This is normally set for you from its manifest information when the provider is first
* created.
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 a2f14aa321bc..c233a0c37645 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -35,6 +35,12 @@ import android.database.ContentObserver;
import android.database.CrossProcessCursorWrapper;
import android.database.Cursor;
import android.database.IContentObserver;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.ImageDecoder;
+import android.graphics.ImageDecoder.ImageInfo;
+import android.graphics.ImageDecoder.Source;
+import android.graphics.PixelFormat;
import android.graphics.Point;
import android.graphics.drawable.Drawable;
import android.net.Uri;
@@ -49,9 +55,11 @@ import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.UserHandle;
+import android.provider.DocumentsContract;
import android.text.TextUtils;
import android.util.EventLog;
import android.util.Log;
+import android.util.Size;
import com.android.internal.util.MimeIconUtils;
import com.android.internal.util.Preconditions;
@@ -68,6 +76,7 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.List;
+import java.util.Objects;
import java.util.Random;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -1880,7 +1889,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}
@@ -1900,7 +1909,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}
@@ -3191,4 +3200,62 @@ public abstract class ContentResolver {
}
return query;
}
+
+ /**
+ * Convenience method that efficiently loads a visual thumbnail for the
+ * given {@link Uri}. Internally calls
+ * {@link ContentProvider#openTypedAssetFile} on the remote provider, but
+ * also defensively resizes any returned content to match the requested
+ * target size.
+ *
+ * @param uri The item that should be visualized as a thumbnail.
+ * @param size The target area on the screen where this thumbnail will be
+ * shown. This is passed to the provider as {@link #EXTRA_SIZE}
+ * to help it avoid downloading or generating heavy resources.
+ * @param signal A signal to cancel the operation in progress.
+ * @return Valid {@link Bitmap} which is a visual thumbnail.
+ * @throws IOException If any trouble was encountered while generating or
+ * loading the thumbnail, or if
+ * {@link CancellationSignal#cancel()} was invoked.
+ */
+ public @NonNull Bitmap loadThumbnail(@NonNull Uri uri, @NonNull Size size,
+ @Nullable CancellationSignal signal) throws IOException {
+ Objects.requireNonNull(uri);
+ Objects.requireNonNull(size);
+
+ try (ContentProviderClient client = acquireContentProviderClient(uri)) {
+ return loadThumbnail(client, uri, size, signal, ImageDecoder.ALLOCATOR_DEFAULT);
+ }
+ }
+
+ /** {@hide} */
+ public static Bitmap loadThumbnail(@NonNull ContentProviderClient client, @NonNull Uri uri,
+ @NonNull Size size, @Nullable CancellationSignal signal, int allocator)
+ throws IOException {
+ Objects.requireNonNull(client);
+ Objects.requireNonNull(uri);
+ Objects.requireNonNull(size);
+
+ // Convert to Point, since that's what the API is defined as
+ final Bundle opts = new Bundle();
+ opts.putParcelable(EXTRA_SIZE, Point.convert(size));
+
+ return ImageDecoder.decodeBitmap(ImageDecoder.createSource(() -> {
+ return client.openTypedAssetFileDescriptor(uri, "image/*", opts, signal);
+ }), (ImageDecoder decoder, ImageInfo info, Source source) -> {
+ decoder.setAllocator(allocator);
+
+ // One last-ditch check to see if we've been canceled.
+ if (signal != null) signal.throwIfCanceled();
+
+ // We requested a rough thumbnail size, but the remote size may have
+ // returned something giant, so defensively scale down as needed.
+ final int widthSample = info.getSize().getWidth() / size.getWidth();
+ final int heightSample = info.getSize().getHeight() / size.getHeight();
+ final int sample = Math.min(widthSample, heightSample);
+ if (sample > 1) {
+ decoder.setTargetSampleSize(sample);
+ }
+ });
+ }
}
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 687fe606f100..5bad27c813b1 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -3967,6 +3967,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.
@@ -4459,7 +4465,6 @@ public class Intent implements Parcelable, Cloneable {
*
* @hide
*/
- @SystemApi
public static final String EXTRA_USER_ID = "android.intent.extra.USER_ID";
/**
@@ -5015,8 +5020,7 @@ public class Intent implements Parcelable, Cloneable {
"android.intent.extra.user_handle";
/**
- * The UserHandle carried with broadcasts intents related to addition and removal of managed
- * profiles - {@link #ACTION_MANAGED_PROFILE_ADDED} and {@link #ACTION_MANAGED_PROFILE_REMOVED}.
+ * The UserHandle carried with intents.
*/
public static final String EXTRA_USER =
"android.intent.extra.USER";
@@ -5535,7 +5539,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 e73fffa64eff..75df4945fbdd 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -238,7 +238,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/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/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/location/ContextHubClient.java b/core/java/android/hardware/location/ContextHubClient.java
index 917644db4202..5de89e3422ab 100644
--- a/core/java/android/hardware/location/ContextHubClient.java
+++ b/core/java/android/hardware/location/ContextHubClient.java
@@ -105,12 +105,15 @@ public class ContextHubClient implements Closeable {
*
* This method should be used if the caller wants to receive notifications even after the
* process exits. The client must have an open connection with the Context Hub Service (i.e. it
- * cannot have been closed through the {@link #close()} method). If registered successfully,
- * intents will be delivered regarding events for the specified nanoapp from the attached
- * Context Hub. Any unicast messages for this client will also be delivered. The intent will
- * have an extra {@link #EXTRA_EVENT_TYPE} of type {@link ContextHubManager.Event}, which will
- * contain the type of the event. See {@link ContextHubManager.Event} for description of each
- * event type.
+ * cannot have been closed through the {@link #close()} method). Only one PendingIntent can be
+ * registered at a time for a single ContextHubClient. If registered successfully, intents will
+ * be delivered regarding events for the specified nanoapp from the attached Context Hub. Any
+ * unicast messages for this client will also be delivered. The intent will have an extra
+ * {@link ContextHubManager.EXTRA_CONTEXT_HUB_INFO} of type {@link ContextHubInfo}, which
+ * describes the Context Hub the intent event was for. The intent will also have an extra
+ * {@link ContextHubManager.EXTRA_EVENT_TYPE} of type {@link ContextHubManager.Event}, which
+ * will contain the type of the event. See {@link ContextHubManager.Event} for description of
+ * each event type, along with event-specific extra fields.
*
* When the intent is received, this client can be recreated through
* {@link ContextHubManager.createClient(PendingIntent, ContextHubInfo,
@@ -133,6 +136,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 +150,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 69f649bad106..947f3fad142e 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
@@ -2500,6 +2501,7 @@ public class ConnectivityManager {
* {@hide}
*/
public void reportInetCondition(int networkType, int percentage) {
+ printStackTrace();
try {
mService.reportInetCondition(networkType, percentage);
} catch (RemoteException e) {
@@ -2520,6 +2522,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.
@@ -2542,6 +2545,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) {
@@ -2734,8 +2738,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);
@@ -2816,10 +2823,11 @@ public class ConnectivityManager {
* @param network The {@link Network} of the satisfying network.
* @param networkCapabilities The {@link NetworkCapabilities} of the satisfying network.
* @param linkProperties The {@link LinkProperties} of the satisfying network.
+ * @param blocked Whether access to the {@link Network} is blocked due to system policy.
* @hide
*/
public void onAvailable(Network network, NetworkCapabilities networkCapabilities,
- LinkProperties linkProperties) {
+ LinkProperties linkProperties, boolean blocked) {
// Internally only this method is called when a new network is available, and
// it calls the callback in the same way and order that older versions used
// to call so as not to change the behavior.
@@ -2830,6 +2838,7 @@ public class ConnectivityManager {
}
onCapabilitiesChanged(network, networkCapabilities);
onLinkPropertiesChanged(network, linkProperties);
+ onBlockedStatusChanged(network, blocked);
}
/**
@@ -2837,7 +2846,8 @@ public class ConnectivityManager {
* This callback may be called more than once if the {@link Network} that is
* satisfying the request changes. This will always immediately be followed by a
* call to {@link #onCapabilitiesChanged(Network, NetworkCapabilities)} then by a
- * call to {@link #onLinkPropertiesChanged(Network, LinkProperties)}.
+ * call to {@link #onLinkPropertiesChanged(Network, LinkProperties)}, and a call to
+ * {@link #onBlockedStatusChanged(Network, boolean)}.
*
* @param network The {@link Network} of the satisfying network.
*/
@@ -2916,6 +2926,14 @@ public class ConnectivityManager {
*/
public void onNetworkResumed(Network network) {}
+ /**
+ * Called when access to the specified network is blocked or unblocked.
+ *
+ * @param network The {@link Network} whose blocked status has changed.
+ * @param blocked The blocked status of this {@link Network}.
+ */
+ public void onBlockedStatusChanged(Network network, boolean blocked) {}
+
private NetworkRequest networkRequest;
}
@@ -2962,6 +2980,8 @@ public class ConnectivityManager {
public static final int CALLBACK_SUSPENDED = BASE + 9;
/** @hide */
public static final int CALLBACK_RESUMED = BASE + 10;
+ /** @hide */
+ public static final int CALLBACK_BLK_CHANGED = BASE + 11;
/** @hide */
public static String getCallbackName(int whichCallback) {
@@ -2976,6 +2996,7 @@ public class ConnectivityManager {
case EXPIRE_LEGACY_REQUEST: return "EXPIRE_LEGACY_REQUEST";
case CALLBACK_SUSPENDED: return "CALLBACK_SUSPENDED";
case CALLBACK_RESUMED: return "CALLBACK_RESUMED";
+ case CALLBACK_BLK_CHANGED: return "CALLBACK_BLK_CHANGED";
default:
return Integer.toString(whichCallback);
}
@@ -3022,7 +3043,7 @@ public class ConnectivityManager {
case CALLBACK_AVAILABLE: {
NetworkCapabilities cap = getObject(message, NetworkCapabilities.class);
LinkProperties lp = getObject(message, LinkProperties.class);
- callback.onAvailable(network, cap, lp);
+ callback.onAvailable(network, cap, lp, message.arg1 != 0);
break;
}
case CALLBACK_LOSING: {
@@ -3055,6 +3076,10 @@ public class ConnectivityManager {
callback.onNetworkResumed(network);
break;
}
+ case CALLBACK_BLK_CHANGED: {
+ boolean blocked = message.arg1 != 0;
+ callback.onBlockedStatusChanged(network, blocked);
+ }
}
}
@@ -3080,6 +3105,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;
@@ -3339,6 +3365,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);
@@ -3362,6 +3389,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);
@@ -3446,6 +3474,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);
@@ -3527,6 +3556,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.
@@ -3955,4 +3985,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/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
index 12b6f9e1b370..0bdfca7f5025 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -1590,4 +1590,14 @@ public final class NetworkCapabilities implements Parcelable {
Preconditions.checkArgument(isValidCapability(capability),
"NetworkCapability " + capability + "out of range");
}
+
+ /**
+ * Check if this {@code NetworkCapability} instance is metered.
+ *
+ * @return {@code true} if {@code NET_CAPABILITY_NOT_METERED} is not set on this instance.
+ * @hide
+ */
+ public boolean isMetered() {
+ return !hasCapability(NET_CAPABILITY_NOT_METERED);
+ }
}
diff --git a/core/java/android/net/NetworkInfo.java b/core/java/android/net/NetworkInfo.java
index d912dd105fe9..1a1d2d33424c 100644
--- a/core/java/android/net/NetworkInfo.java
+++ b/core/java/android/net/NetworkInfo.java
@@ -202,7 +202,9 @@ public class NetworkInfo implements Parcelable {
* Return a network-type-specific integer describing the subtype
* of the network.
* @return the network subtype
+ * @deprecated Use {@link android.telephony.TelephonyManager#getDataNetworkType} instead.
*/
+ @Deprecated
public int getSubtype() {
synchronized (this) {
return mSubtype;
@@ -243,7 +245,9 @@ public class NetworkInfo implements Parcelable {
/**
* Return a human-readable name describing the subtype of the network.
* @return the name of the network subtype
+ * @deprecated Use {@link android.telephony.TelephonyManager#getDataNetworkType} instead.
*/
+ @Deprecated
public String getSubtypeName() {
synchronized (this) {
return mSubtypeName;
@@ -278,7 +282,15 @@ public class NetworkInfo implements Parcelable {
* connections and pass data.
* <p>Always call this before attempting to perform data transactions.
* @return {@code true} if network connectivity exists, {@code false} otherwise.
+ * @deprecated Apps should instead use the
+ * {@link android.net.ConnectivityManager.NetworkCallback} API to
+ * learn about connectivity changes. See
+ * {@link ConnectivityManager#registerDefaultNetworkCallback} and
+ * {@link ConnectivityManager#registerNetworkCallback}. These will
+ * give a more accurate picture of the connectivity state of
+ * the device and let apps react more easily and quickly to changes.
*/
+ @Deprecated
public boolean isConnected() {
synchronized (this) {
return mState == State.CONNECTED;
@@ -411,7 +423,15 @@ public class NetworkInfo implements Parcelable {
/**
* Reports the current fine-grained state of the network.
* @return the fine-grained state
+ * @deprecated Apps should instead use the
+ * {@link android.net.ConnectivityManager.NetworkCallback} API to
+ * learn about connectivity changes. See
+ * {@link ConnectivityManager#registerDefaultNetworkCallback} and
+ * {@link ConnectivityManager#registerNetworkCallback}. These will
+ * give a more accurate picture of the connectivity state of
+ * the device and let apps react more easily and quickly to changes.
*/
+ @Deprecated
public DetailedState getDetailedState() {
synchronized (this) {
return mDetailedState;
diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java
index 34e9476b3e08..c431e40ede2f 100644
--- a/core/java/android/net/NetworkUtils.java
+++ b/core/java/android/net/NetworkUtils.java
@@ -16,8 +16,13 @@
package android.net;
+import static android.system.OsConstants.AF_INET;
+import static android.system.OsConstants.AF_INET6;
+
+import android.annotation.NonNull;
import android.annotation.UnsupportedAppUsage;
import android.os.Parcel;
+import android.system.Os;
import android.util.Log;
import android.util.Pair;
@@ -570,4 +575,30 @@ public class NetworkUtils {
}
return routedIPCount;
}
+
+ private static final int[] ADDRESS_FAMILIES = new int[] {AF_INET, AF_INET6};
+
+ /**
+ * Returns true if the hostname is weakly validated.
+ * @param hostname Name of host to validate.
+ * @return True if it's a valid-ish hostname.
+ *
+ * @hide
+ */
+ public static boolean isWeaklyValidatedHostname(@NonNull String hostname) {
+ // TODO(b/34953048): Use a validation method that permits more accurate,
+ // but still inexpensive, checking of likely valid DNS hostnames.
+ final String weakHostnameRegex = "^[a-zA-Z0-9_.-]+$";
+ if (!hostname.matches(weakHostnameRegex)) {
+ return false;
+ }
+
+ for (int address_family : ADDRESS_FAMILIES) {
+ if (Os.inet_pton(address_family, hostname) != null) {
+ return false;
+ }
+ }
+
+ return true;
+ }
}
diff --git a/core/java/android/net/Uri.java b/core/java/android/net/Uri.java
index 40465ceafcb8..d09f33bcb755 100644
--- a/core/java/android/net/Uri.java
+++ b/core/java/android/net/Uri.java
@@ -1102,19 +1102,18 @@ public abstract class Uri implements Parcelable, Comparable<Uri> {
public String getHost() {
@SuppressWarnings("StringEquality")
boolean cached = (host != NOT_CACHED);
- return cached ? host
- : (host = parseHost());
+ return cached ? host : (host = parseHost());
}
private String parseHost() {
- String authority = getEncodedAuthority();
+ final String authority = getEncodedAuthority();
if (authority == null) {
return null;
}
// Parse out user info and then port.
int userInfoSeparator = authority.lastIndexOf('@');
- int portSeparator = authority.indexOf(':', userInfoSeparator);
+ int portSeparator = findPortSeparator(authority);
String encodedHost = portSeparator == NOT_FOUND
? authority.substring(userInfoSeparator + 1)
@@ -1132,16 +1131,8 @@ public abstract class Uri implements Parcelable, Comparable<Uri> {
}
private int parsePort() {
- String authority = getEncodedAuthority();
- if (authority == null) {
- return -1;
- }
-
- // Make sure we look for the port separtor *after* the user info
- // separator. We have URLs with a ':' in the user info.
- int userInfoSeparator = authority.lastIndexOf('@');
- int portSeparator = authority.indexOf(':', userInfoSeparator);
-
+ final String authority = getEncodedAuthority();
+ int portSeparator = findPortSeparator(authority);
if (portSeparator == NOT_FOUND) {
return -1;
}
@@ -1154,6 +1145,24 @@ public abstract class Uri implements Parcelable, Comparable<Uri> {
return -1;
}
}
+
+ private int findPortSeparator(String authority) {
+ if (authority == null) {
+ return NOT_FOUND;
+ }
+
+ // Reverse search for the ':' character that breaks as soon as a char that is neither
+ // a colon nor an ascii digit is encountered. Thanks to the goodness of UTF-16 encoding,
+ // it's not possible that a surrogate matches one of these, so this loop can just
+ // look for characters rather than care about code points.
+ for (int i = authority.length() - 1; i >= 0; --i) {
+ final int character = authority.charAt(i);
+ if (':' == character) return i;
+ // Character.isDigit would include non-ascii digits
+ if (character < '0' || character > '9') return NOT_FOUND;
+ }
+ return NOT_FOUND;
+ }
}
/**
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index 26c2033eac51..292543c4a19a 100644
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -17,6 +17,7 @@
package android.os;
import android.Manifest;
+import android.annotation.NonNull;
import android.annotation.RequiresPermission;
import android.annotation.SuppressAutoDoc;
import android.annotation.SystemApi;
@@ -129,9 +130,9 @@ 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.
+ * <p>Requires Permission: READ_PRIVILEGED_PHONE_STATE, or for the calling package to be the
+ * device or profile owner and have the READ_PHONE_STATE permission. Profile owner access is
+ * deprecated and will be removed in a future release.
*
* @return The serial number if specified.
*/
@@ -1112,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);
+ }
}
/**
@@ -1133,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/FileUtils.java b/core/java/android/os/FileUtils.java
index a9cb0d9579c9..f71fdd7fdac1 100644
--- a/core/java/android/os/FileUtils.java
+++ b/core/java/android/os/FileUtils.java
@@ -1198,6 +1198,19 @@ public class FileUtils {
/** {@hide} */
public static int translateModeStringToPosix(String mode) {
+ // Sanity check for invalid chars
+ for (int i = 0; i < mode.length(); i++) {
+ switch (mode.charAt(i)) {
+ case 'r':
+ case 'w':
+ case 't':
+ case 'a':
+ break;
+ default:
+ throw new IllegalArgumentException("Bad mode: " + mode);
+ }
+ }
+
int res = 0;
if (mode.startsWith("rw")) {
res |= O_RDWR | O_CREAT;
diff --git a/core/java/android/os/GraphicsEnvironment.java b/core/java/android/os/GraphicsEnvironment.java
index 5f656207255a..0c56d4884105 100644
--- a/core/java/android/os/GraphicsEnvironment.java
+++ b/core/java/android/os/GraphicsEnvironment.java
@@ -19,6 +19,8 @@ package android.os;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
+import android.content.res.AssetFileDescriptor;
+import android.content.res.AssetManager;
import android.opengl.EGL14;
import android.os.Build;
import android.os.SystemProperties;
@@ -27,7 +29,14 @@ import android.util.Log;
import dalvik.system.VMRuntime;
+import java.io.BufferedReader;
import java.io.File;
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.HashSet;
+import java.util.Set;
/** @hide */
public class GraphicsEnvironment {
@@ -44,8 +53,10 @@ public class GraphicsEnvironment {
private static final boolean DEBUG = false;
private static final String TAG = "GraphicsEnvironment";
private static final String PROPERTY_GFX_DRIVER = "ro.gfx.driver.0";
+ private static final String PROPERTY_GFX_DRIVER_WHITELIST = "ro.gfx.driver.whitelist.0";
private static final String ANGLE_PACKAGE_NAME = "com.android.angle";
private static final String GLES_MODE_METADATA_KEY = "com.android.angle.GLES_MODE";
+ private static final String ANGLE_RULES_FILE = "a4a_rules.json";
private ClassLoader mClassLoader;
private String mLayerPath;
@@ -55,7 +66,7 @@ public class GraphicsEnvironment {
* Set up GraphicsEnvironment
*/
public void setup(Context context, Bundle coreSettings) {
- setupGpuLayers(context);
+ setupGpuLayers(context, coreSettings);
setupAngle(context, coreSettings);
chooseDriver(context);
}
@@ -81,27 +92,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 +153,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()) {
@@ -201,8 +253,40 @@ public class GraphicsEnvironment {
if (DEBUG) Log.v(TAG, "ANGLE package libs: " + paths);
+ // Pass the rules file to loader for ANGLE decisions
+ AssetManager angleAssets = null;
+ try {
+ angleAssets =
+ context.getPackageManager().getResourcesForApplication(angleInfo).getAssets();
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.w(TAG, "Failed to get AssetManager for '" + ANGLE_PACKAGE_NAME + "'");
+ return;
+ }
+
+ AssetFileDescriptor assetsFd = null;
+ try {
+ assetsFd = angleAssets.openFd(ANGLE_RULES_FILE);
+ } catch (IOException e) {
+ Log.w(TAG, "Failed to get AssetFileDescriptor for " + ANGLE_RULES_FILE + " from "
+ + "'" + ANGLE_PACKAGE_NAME + "'");
+ return;
+ }
+
+ FileDescriptor rulesFd = null;
+ long rulesOffset = 0;
+ long rulesLength = 0;
+ if (assetsFd != null) {
+ rulesFd = assetsFd.getFileDescriptor();
+ rulesOffset = assetsFd.getStartOffset();
+ rulesLength = assetsFd.getLength();
+ } else {
+ Log.w(TAG, "Failed to get file descriptor for " + ANGLE_RULES_FILE);
+ return;
+ }
+
// Further opt-in logic is handled in native, so pass relevant info down
- setAngleInfo(paths, packageName, appPref, devOptIn);
+ setAngleInfo(paths, packageName, appPref, devOptIn,
+ rulesFd, rulesOffset, rulesLength);
}
/**
@@ -221,6 +305,15 @@ public class GraphicsEnvironment {
if (DEBUG) Log.v(TAG, "ignoring driver package for privileged/non-updated system app");
return;
}
+ Set<String> whitelist = loadWhitelist(context, driverPackageName);
+
+ // Empty whitelist implies no updatable graphics driver. Typically, the pre-installed
+ // updatable graphics driver is supposed to be a place holder and contains no graphics
+ // driver and whitelist.
+ if (whitelist == null || whitelist.isEmpty()) {
+ return;
+ }
+
ApplicationInfo driverInfo;
try {
driverInfo = context.getPackageManager().getApplicationInfo(driverPackageName,
@@ -229,6 +322,22 @@ public class GraphicsEnvironment {
Log.w(TAG, "driver package '" + driverPackageName + "' not installed");
return;
}
+ if (!whitelist.contains(context.getPackageName())) {
+ if (DEBUG) {
+ Log.w(TAG, context.getPackageName() + " is not on the whitelist.");
+ }
+ return;
+ }
+
+ // O drivers are restricted to the sphal linker namespace, so don't try to use
+ // packages unless they declare they're compatible with that restriction.
+ if (driverInfo.targetSdkVersion < Build.VERSION_CODES.O) {
+ if (DEBUG) {
+ Log.w(TAG, "updated driver package is not known to be compatible with O");
+ }
+ return;
+ }
+
String abi = chooseAbi(driverInfo);
if (abi == null) {
if (DEBUG) {
@@ -239,12 +348,6 @@ public class GraphicsEnvironment {
}
return;
}
- if (driverInfo.targetSdkVersion < Build.VERSION_CODES.O) {
- // O drivers are restricted to the sphal linker namespace, so don't try to use
- // packages unless they declare they're compatible with that restriction.
- Log.w(TAG, "updated driver package is not known to be compatible with O");
- return;
- }
StringBuilder sb = new StringBuilder();
sb.append(driverInfo.nativeLibraryDir)
@@ -290,9 +393,39 @@ public class GraphicsEnvironment {
return null;
}
+ private static Set<String> loadWhitelist(Context context, String driverPackageName) {
+ String whitelistName = SystemProperties.get(PROPERTY_GFX_DRIVER_WHITELIST);
+ if (whitelistName == null || whitelistName.isEmpty()) {
+ return null;
+ }
+ try {
+ Context driverContext = context.createPackageContext(driverPackageName,
+ Context.CONTEXT_RESTRICTED);
+ AssetManager assets = driverContext.getAssets();
+ InputStream stream = assets.open(whitelistName);
+ BufferedReader reader = new BufferedReader(new InputStreamReader(stream));
+ Set<String> whitelist = new HashSet<>();
+ for (String line; (line = reader.readLine()) != null; ) {
+ whitelist.add(line);
+ }
+ return whitelist;
+ } catch (PackageManager.NameNotFoundException e) {
+ if (DEBUG) {
+ Log.w(TAG, "driver package '" + driverPackageName + "' not installed");
+ }
+ } catch (IOException e) {
+ if (DEBUG) {
+ Log.w(TAG, "Failed to load whitelist driver package, abort.");
+ }
+ }
+ 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);
private static native void setAngleInfo(String path, String appPackage, String appPref,
- boolean devOptIn);
+ boolean devOptIn, FileDescriptor rulesFd,
+ long rulesOffset, long rulesLength);
}
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/UserManager.java b/core/java/android/os/UserManager.java
index 8123744281f4..0d5d54704c4f 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -983,6 +983,21 @@ public class UserManager {
public static final String DISALLOW_PRINTING = "no_printing";
/**
+ * Specifies whether the user is allowed to modify private DNS settings.
+ *
+ * <p>The default value is <code>false</code>.
+ *
+ * <p>This user restriction can only be applied by the Device Owner.
+ * <p>Key for user restrictions.
+ * <p>Type: Boolean
+ * @see DevicePolicyManager#addUserRestriction(ComponentName, String)
+ * @see DevicePolicyManager#clearUserRestriction(ComponentName, String)
+ * @see #getUserRestrictions()
+ */
+ public static final String DISALLOW_CONFIG_PRIVATE_DNS =
+ "disallow_config_private_dns";
+
+ /**
* Application restriction key that is used to indicate the pending arrival
* of real restrictions for the app.
*
@@ -2363,7 +2378,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/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 50ca4abd6713..df771df5de0d 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -1538,6 +1538,9 @@ public class StorageManager {
* @hide
*/
public File translateAppToSystem(File file, String packageName) {
+ // We can only translate absolute paths
+ if (!file.isAbsolute()) return file;
+
try {
return new File(mStorageManager.translateAppToSystem(file.getAbsolutePath(),
packageName, mContext.getUserId()));
@@ -1553,6 +1556,9 @@ public class StorageManager {
* @hide
*/
public File translateSystemToApp(File file, String packageName) {
+ // We can only translate absolute paths
+ if (!file.isAbsolute()) return file;
+
try {
return new File(mStorageManager.translateSystemToApp(file.getAbsolutePath(),
packageName, mContext.getUserId()));
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/DocumentsContract.java b/core/java/android/provider/DocumentsContract.java
index 8c40e0e6cb8c..954d18abc6e1 100644
--- a/core/java/android/provider/DocumentsContract.java
+++ b/core/java/android/provider/DocumentsContract.java
@@ -34,6 +34,7 @@ import android.content.res.AssetFileDescriptor;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
+import android.graphics.ImageDecoder;
import android.graphics.Matrix;
import android.graphics.Point;
import android.media.ExifInterface;
@@ -53,6 +54,7 @@ import android.system.ErrnoException;
import android.system.Os;
import android.util.DataUnit;
import android.util.Log;
+import android.util.Size;
import libcore.io.IoUtils;
@@ -136,10 +138,11 @@ public final class DocumentsContract {
public static final String EXTRA_EXCLUDE_SELF = "android.provider.extra.EXCLUDE_SELF";
/**
- * Included in {@link AssetFileDescriptor#getExtras()} when returned
- * thumbnail should be rotated.
+ * An extra number of degrees that an image should be rotated during the
+ * decode process to be presented correctly.
*
- * @see MediaStore.Images.ImageColumns#ORIENTATION
+ * @see AssetFileDescriptor#getExtras()
+ * @see android.provider.MediaStore.Images.ImageColumns#ORIENTATION
*/
public static final String EXTRA_ORIENTATION = "android.provider.extra.ORIENTATION";
@@ -1093,75 +1096,10 @@ public final class DocumentsContract {
/** {@hide} */
@UnsupportedAppUsage
- public static Bitmap getDocumentThumbnail(
- ContentProviderClient client, Uri documentUri, Point size, CancellationSignal signal)
- throws RemoteException, IOException {
- final Bundle openOpts = new Bundle();
- openOpts.putParcelable(ContentResolver.EXTRA_SIZE, size);
-
- AssetFileDescriptor afd = null;
- Bitmap bitmap = null;
- try {
- afd = client.openTypedAssetFileDescriptor(documentUri, "image/*", openOpts, signal);
-
- final FileDescriptor fd = afd.getFileDescriptor();
- final long offset = afd.getStartOffset();
-
- // Try seeking on the returned FD, since it gives us the most
- // optimal decode path; otherwise fall back to buffering.
- BufferedInputStream is = null;
- try {
- Os.lseek(fd, offset, SEEK_SET);
- } catch (ErrnoException e) {
- is = new BufferedInputStream(new FileInputStream(fd), THUMBNAIL_BUFFER_SIZE);
- is.mark(THUMBNAIL_BUFFER_SIZE);
- }
-
- // We requested a rough thumbnail size, but the remote size may have
- // returned something giant, so defensively scale down as needed.
- final BitmapFactory.Options opts = new BitmapFactory.Options();
- opts.inJustDecodeBounds = true;
- if (is != null) {
- BitmapFactory.decodeStream(is, null, opts);
- } else {
- BitmapFactory.decodeFileDescriptor(fd, null, opts);
- }
-
- final int widthSample = opts.outWidth / size.x;
- final int heightSample = opts.outHeight / size.y;
-
- opts.inJustDecodeBounds = false;
- opts.inSampleSize = Math.min(widthSample, heightSample);
- if (is != null) {
- is.reset();
- bitmap = BitmapFactory.decodeStream(is, null, opts);
- } else {
- try {
- Os.lseek(fd, offset, SEEK_SET);
- } catch (ErrnoException e) {
- e.rethrowAsIOException();
- }
- bitmap = BitmapFactory.decodeFileDescriptor(fd, null, opts);
- }
-
- // Transform the bitmap if requested. We use a side-channel to
- // communicate the orientation, since EXIF thumbnails don't contain
- // the rotation flags of the original image.
- final Bundle extras = afd.getExtras();
- final int orientation = (extras != null) ? extras.getInt(EXTRA_ORIENTATION, 0) : 0;
- if (orientation != 0) {
- final int width = bitmap.getWidth();
- final int height = bitmap.getHeight();
-
- final Matrix m = new Matrix();
- m.setRotate(orientation, width / 2, height / 2);
- bitmap = Bitmap.createBitmap(bitmap, 0, 0, width, height, m, false);
- }
- } finally {
- IoUtils.closeQuietly(afd);
- }
-
- return bitmap;
+ public static Bitmap getDocumentThumbnail(ContentProviderClient client, Uri documentUri,
+ Point size, CancellationSignal signal) throws IOException {
+ return ContentResolver.loadThumbnail(client, documentUri, Point.convert(size), signal,
+ ImageDecoder.ALLOCATOR_DEFAULT);
}
/**
diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java
index 828fd7386d80..f5660b950c0a 100644
--- a/core/java/android/provider/MediaStore.java
+++ b/core/java/android/provider/MediaStore.java
@@ -29,7 +29,6 @@ import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.UriPermission;
-import android.content.res.AssetFileDescriptor;
import android.database.Cursor;
import android.database.DatabaseUtils;
import android.graphics.Bitmap;
@@ -39,6 +38,7 @@ import android.net.Uri;
import android.os.Bundle;
import android.os.CancellationSignal;
import android.os.Environment;
+import android.os.OperationCanceledException;
import android.os.RemoteException;
import android.service.media.CameraPrewarmService;
import android.util.ArrayMap;
@@ -402,7 +402,16 @@ public final class MediaStore {
* access.
* <p>
* Type: TEXT
+ *
+ * @deprecated Apps may not have filesystem permissions to directly
+ * access this path. Instead of trying to open this path
+ * directly, apps should use
+ * {@link ContentResolver#openFileDescriptor(Uri, String)}
+ * to gain access. This value will always be {@code NULL}
+ * for apps targeting
+ * {@link android.os.Build.VERSION_CODES#Q} or higher.
*/
+ @Deprecated
public static final String DATA = "_data";
/**
@@ -641,6 +650,7 @@ public final class MediaStore {
* This class is used internally by Images.Thumbnails and Video.Thumbnails, it's not intended
* to be accessed elsewhere.
*/
+ @Deprecated
private static class InternalThumbnails implements BaseColumns {
/**
* Currently outstanding thumbnail requests that can be cancelled.
@@ -654,13 +664,14 @@ public final class MediaStore {
*
* @see #cancelThumbnail(ContentResolver, Uri)
*/
+ @Deprecated
static @Nullable Bitmap getThumbnail(@NonNull ContentResolver cr, @NonNull Uri uri,
int kind, @Nullable BitmapFactory.Options opts) {
- final Bundle openOpts = new Bundle();
+ final Point size;
if (kind == ThumbnailConstants.MICRO_KIND) {
- openOpts.putParcelable(ContentResolver.EXTRA_SIZE, ThumbnailConstants.MICRO_SIZE);
+ size = ThumbnailConstants.MICRO_SIZE;
} else if (kind == ThumbnailConstants.MINI_KIND) {
- openOpts.putParcelable(ContentResolver.EXTRA_SIZE, ThumbnailConstants.MINI_SIZE);
+ size = ThumbnailConstants.MINI_SIZE;
} else {
throw new IllegalArgumentException("Unsupported kind: " + kind);
}
@@ -674,9 +685,8 @@ public final class MediaStore {
}
}
- try (AssetFileDescriptor afd = cr.openTypedAssetFileDescriptor(uri,
- "image/*", openOpts, signal)) {
- return BitmapFactory.decodeFileDescriptor(afd.getFileDescriptor(), null, opts);
+ try {
+ return cr.loadThumbnail(uri, Point.convert(size), signal);
} catch (IOException e) {
Log.w(TAG, "Failed to obtain thumbnail for " + uri, e);
return null;
@@ -693,6 +703,7 @@ public final class MediaStore {
* Only the original process which made the request can cancel their own
* requests.
*/
+ @Deprecated
static void cancelThumbnail(@NonNull ContentResolver cr, @NonNull Uri uri) {
synchronized (sPending) {
final CancellationSignal signal = sPending.get(uri);
@@ -936,9 +947,8 @@ public final class MediaStore {
}
/**
- * This class allows developers to query and get two kinds of thumbnails:
- * MINI_KIND: 512 x 384 thumbnail
- * MICRO_KIND: 96 x 96 thumbnail
+ * This class provides utility methods to obtain thumbnails for various
+ * {@link Images} items.
*/
public static class Thumbnails implements BaseColumns {
public static final Cursor query(ContentResolver cr, Uri uri, String[] projection) {
@@ -958,13 +968,19 @@ public final class MediaStore {
}
/**
- * This method cancels the thumbnail request so clients waiting for getThumbnail will be
- * interrupted and return immediately. Only the original process which made the getThumbnail
- * requests can cancel their own requests.
+ * Cancel any outstanding {@link #getThumbnail} requests, causing
+ * them to return by throwing a {@link OperationCanceledException}.
+ * <p>
+ * This method has no effect on
+ * {@link ContentResolver#loadThumbnail} calls, since they provide
+ * their own {@link CancellationSignal}.
*
- * @param cr ContentResolver
- * @param origId original image id
+ * @deprecated Callers should migrate to using
+ * {@link ContentResolver#loadThumbnail}, since it
+ * offers richer control over requested thumbnail sizes
+ * and cancellation behavior.
*/
+ @Deprecated
public static void cancelThumbnailRequest(ContentResolver cr, long origId) {
final Uri uri = ContentUris.withAppendedId(
Images.Media.EXTERNAL_CONTENT_URI, origId);
@@ -972,51 +988,66 @@ public final class MediaStore {
}
/**
- * This method checks if the thumbnails of the specified image (origId) has been created.
- * It will be blocked until the thumbnails are generated.
+ * Return thumbnail representing a specific image item. If a
+ * thumbnail doesn't exist, this method will block until it's
+ * generated. Callers are responsible for their own in-memory
+ * caching of returned values.
*
- * @param cr ContentResolver used to dispatch queries to MediaProvider.
- * @param origId Original image id associated with thumbnail of interest.
- * @param kind The type of thumbnail to fetch. Should be either MINI_KIND or MICRO_KIND.
- * @param options this is only used for MINI_KIND when decoding the Bitmap
- * @return A Bitmap instance. It could be null if the original image
- * associated with origId doesn't exist or memory is not enough.
- */
- public static Bitmap getThumbnail(ContentResolver cr, long origId, int kind,
+ * @param imageId the image item to obtain a thumbnail for.
+ * @param kind optimal thumbnail size desired.
+ * @return decoded thumbnail, or {@code null} if problem was
+ * encountered.
+ * @deprecated Callers should migrate to using
+ * {@link ContentResolver#loadThumbnail}, since it
+ * offers richer control over requested thumbnail sizes
+ * and cancellation behavior.
+ */
+ @Deprecated
+ public static Bitmap getThumbnail(ContentResolver cr, long imageId, int kind,
BitmapFactory.Options options) {
final Uri uri = ContentUris.withAppendedId(
- Images.Media.EXTERNAL_CONTENT_URI, origId);
+ Images.Media.EXTERNAL_CONTENT_URI, imageId);
return InternalThumbnails.getThumbnail(cr, uri, kind, options);
}
/**
- * This method cancels the thumbnail request so clients waiting for getThumbnail will be
- * interrupted and return immediately. Only the original process which made the getThumbnail
- * requests can cancel their own requests.
+ * Cancel any outstanding {@link #getThumbnail} requests, causing
+ * them to return by throwing a {@link OperationCanceledException}.
+ * <p>
+ * This method has no effect on
+ * {@link ContentResolver#loadThumbnail} calls, since they provide
+ * their own {@link CancellationSignal}.
*
- * @param cr ContentResolver
- * @param origId original image id
- * @param groupId the same groupId used in getThumbnail.
+ * @deprecated Callers should migrate to using
+ * {@link ContentResolver#loadThumbnail}, since it
+ * offers richer control over requested thumbnail sizes
+ * and cancellation behavior.
*/
- public static void cancelThumbnailRequest(ContentResolver cr, long origId, long groupId) {
+ @Deprecated
+ public static void cancelThumbnailRequest(ContentResolver cr, long origId,
+ long groupId) {
cancelThumbnailRequest(cr, origId);
}
/**
- * This method checks if the thumbnails of the specified image (origId) has been created.
- * It will be blocked until the thumbnails are generated.
+ * Return thumbnail representing a specific image item. If a
+ * thumbnail doesn't exist, this method will block until it's
+ * generated. Callers are responsible for their own in-memory
+ * caching of returned values.
*
- * @param cr ContentResolver used to dispatch queries to MediaProvider.
- * @param origId Original image id associated with thumbnail of interest.
- * @param groupId the id of group to which this request belongs
- * @param kind The type of thumbnail to fetch. Should be either MINI_KIND or MICRO_KIND.
- * @param options this is only used for MINI_KIND when decoding the Bitmap
- * @return A Bitmap instance. It could be null if the original image
- * associated with origId doesn't exist or memory is not enough.
- */
- public static Bitmap getThumbnail(ContentResolver cr, long origId, long groupId,
+ * @param imageId the image item to obtain a thumbnail for.
+ * @param kind optimal thumbnail size desired.
+ * @return decoded thumbnail, or {@code null} if problem was
+ * encountered.
+ * @deprecated Callers should migrate to using
+ * {@link ContentResolver#loadThumbnail}, since it
+ * offers richer control over requested thumbnail sizes
+ * and cancellation behavior.
+ */
+ @Deprecated
+ public static Bitmap getThumbnail(ContentResolver cr, long imageId, long groupId,
int kind, BitmapFactory.Options options) {
- return getThumbnail(cr, origId, kind, options);
+ return getThumbnail(cr, imageId, kind, options);
}
/**
@@ -1059,7 +1090,16 @@ public final class MediaStore {
* access.
* <p>
* Type: TEXT
+ *
+ * @deprecated Apps may not have filesystem permissions to directly
+ * access this path. Instead of trying to open this path
+ * directly, apps should use
+ * {@link ContentResolver#loadThumbnail}
+ * to gain access. This value will always be
+ * {@code NULL} for apps targeting
+ * {@link android.os.Build.VERSION_CODES#Q} or higher.
*/
+ @Deprecated
public static final String DATA = "_data";
/**
@@ -1509,7 +1549,16 @@ public final class MediaStore {
* access.
* <p>
* Type: TEXT
+ *
+ * @deprecated Apps may not have filesystem permissions to directly
+ * access this path. Instead of trying to open this path
+ * directly, apps should use
+ * {@link ContentResolver#openFileDescriptor(Uri, String)}
+ * to gain access. This value will always be
+ * {@code NULL} for apps targeting
+ * {@link android.os.Build.VERSION_CODES#Q} or higher.
*/
+ @Deprecated
public static final String DATA = "_data";
/**
@@ -1790,7 +1839,16 @@ public final class MediaStore {
/**
* Cached album art.
* <P>Type: TEXT</P>
+ *
+ * @deprecated Apps may not have filesystem permissions to directly
+ * access this path. Instead of trying to open this path
+ * directly, apps should use
+ * {@link ContentResolver#loadThumbnail}
+ * to gain access. This value will always be
+ * {@code NULL} for apps targeting
+ * {@link android.os.Build.VERSION_CODES#Q} or higher.
*/
+ @Deprecated
public static final String ALBUM_ART = "album_art";
}
@@ -2009,20 +2067,24 @@ public final class MediaStore {
}
/**
- * This class allows developers to query and get two kinds of thumbnails:
- * MINI_KIND: 512 x 384 thumbnail
- * MICRO_KIND: 96 x 96 thumbnail
- *
+ * This class provides utility methods to obtain thumbnails for various
+ * {@link Video} items.
*/
public static class Thumbnails implements BaseColumns {
/**
- * This method cancels the thumbnail request so clients waiting for getThumbnail will be
- * interrupted and return immediately. Only the original process which made the getThumbnail
- * requests can cancel their own requests.
+ * Cancel any outstanding {@link #getThumbnail} requests, causing
+ * them to return by throwing a {@link OperationCanceledException}.
+ * <p>
+ * This method has no effect on
+ * {@link ContentResolver#loadThumbnail} calls, since they provide
+ * their own {@link CancellationSignal}.
*
- * @param cr ContentResolver
- * @param origId original video id
+ * @deprecated Callers should migrate to using
+ * {@link ContentResolver#loadThumbnail}, since it
+ * offers richer control over requested thumbnail sizes
+ * and cancellation behavior.
*/
+ @Deprecated
public static void cancelThumbnailRequest(ContentResolver cr, long origId) {
final Uri uri = ContentUris.withAppendedId(
Video.Media.EXTERNAL_CONTENT_URI, origId);
@@ -2030,51 +2092,66 @@ public final class MediaStore {
}
/**
- * This method checks if the thumbnails of the specified image (origId) has been created.
- * It will be blocked until the thumbnails are generated.
+ * Return thumbnail representing a specific video item. If a
+ * thumbnail doesn't exist, this method will block until it's
+ * generated. Callers are responsible for their own in-memory
+ * caching of returned values.
*
- * @param cr ContentResolver used to dispatch queries to MediaProvider.
- * @param origId Original image id associated with thumbnail of interest.
- * @param kind The type of thumbnail to fetch. Should be either MINI_KIND or MICRO_KIND.
- * @param options this is only used for MINI_KIND when decoding the Bitmap
- * @return A Bitmap instance. It could be null if the original image
- * associated with origId doesn't exist or memory is not enough.
- */
- public static Bitmap getThumbnail(ContentResolver cr, long origId, int kind,
+ * @param videoId the video item to obtain a thumbnail for.
+ * @param kind optimal thumbnail size desired.
+ * @return decoded thumbnail, or {@code null} if problem was
+ * encountered.
+ * @deprecated Callers should migrate to using
+ * {@link ContentResolver#loadThumbnail}, since it
+ * offers richer control over requested thumbnail sizes
+ * and cancellation behavior.
+ */
+ @Deprecated
+ public static Bitmap getThumbnail(ContentResolver cr, long videoId, int kind,
BitmapFactory.Options options) {
final Uri uri = ContentUris.withAppendedId(
- Video.Media.EXTERNAL_CONTENT_URI, origId);
+ Video.Media.EXTERNAL_CONTENT_URI, videoId);
return InternalThumbnails.getThumbnail(cr, uri, kind, options);
}
/**
- * This method checks if the thumbnails of the specified image (origId) has been created.
- * It will be blocked until the thumbnails are generated.
+ * Cancel any outstanding {@link #getThumbnail} requests, causing
+ * them to return by throwing a {@link OperationCanceledException}.
+ * <p>
+ * This method has no effect on
+ * {@link ContentResolver#loadThumbnail} calls, since they provide
+ * their own {@link CancellationSignal}.
*
- * @param cr ContentResolver used to dispatch queries to MediaProvider.
- * @param origId Original image id associated with thumbnail of interest.
- * @param groupId the id of group to which this request belongs
- * @param kind The type of thumbnail to fetch. Should be either MINI_KIND or MICRO_KIND
- * @param options this is only used for MINI_KIND when decoding the Bitmap
- * @return A Bitmap instance. It could be null if the original image associated with
- * origId doesn't exist or memory is not enough.
- */
- public static Bitmap getThumbnail(ContentResolver cr, long origId, long groupId,
- int kind, BitmapFactory.Options options) {
- return getThumbnail(cr, origId, kind, options);
+ * @deprecated Callers should migrate to using
+ * {@link ContentResolver#loadThumbnail}, since it
+ * offers richer control over requested thumbnail sizes
+ * and cancellation behavior.
+ */
+ @Deprecated
+ public static void cancelThumbnailRequest(ContentResolver cr, long videoId,
+ long groupId) {
+ cancelThumbnailRequest(cr, videoId);
}
/**
- * This method cancels the thumbnail request so clients waiting for getThumbnail will be
- * interrupted and return immediately. Only the original process which made the getThumbnail
- * requests can cancel their own requests.
+ * Return thumbnail representing a specific video item. If a
+ * thumbnail doesn't exist, this method will block until it's
+ * generated. Callers are responsible for their own in-memory
+ * caching of returned values.
*
- * @param cr ContentResolver
- * @param origId original video id
- * @param groupId the same groupId used in getThumbnail.
+ * @param videoId the video item to obtain a thumbnail for.
+ * @param kind optimal thumbnail size desired.
+ * @return decoded thumbnail, or {@code null} if problem was
+ * encountered.
+ * @deprecated Callers should migrate to using
+ * {@link ContentResolver#loadThumbnail}, since it
+ * offers richer control over requested thumbnail sizes
+ * and cancellation behavior.
*/
- public static void cancelThumbnailRequest(ContentResolver cr, long origId, long groupId) {
- cancelThumbnailRequest(cr, origId);
+ @Deprecated
+ public static Bitmap getThumbnail(ContentResolver cr, long videoId, long groupId,
+ int kind, BitmapFactory.Options options) {
+ return getThumbnail(cr, videoId, kind, options);
}
/**
@@ -2110,14 +2187,17 @@ public final class MediaStore {
/**
* Path to the thumbnail file on disk.
* <p>
- * Note that apps may not have filesystem permissions to directly
- * access this path. Instead of trying to open this path directly,
- * apps should use
- * {@link ContentResolver#openFileDescriptor(Uri, String)} to gain
- * access.
- * <p>
* Type: TEXT
+ *
+ * @deprecated Apps may not have filesystem permissions to directly
+ * access this path. Instead of trying to open this path
+ * directly, apps should use
+ * {@link ContentResolver#openFileDescriptor(Uri, String)}
+ * to gain access. This value will always be
+ * {@code NULL} for apps targeting
+ * {@link android.os.Build.VERSION_CODES#Q} or higher.
*/
+ @Deprecated
public static final String DATA = "_data";
/**
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index e98efe44dc6f..206a24740391 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -1473,12 +1473,13 @@ public final class Settings {
* <p> If an user action is disabled by policy, this dialog can be triggered to let
* the user know about this.
* <p>
- * Input: Nothing.
+ * Input: {@link Intent#EXTRA_USER}: The user of the admin.
* <p>
* Output: Nothing.
*
* @hide
*/
+ // Intent#EXTRA_USER_ID can also be used
@SystemApi
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
public static final String ACTION_SHOW_ADMIN_SUPPORT_DETAILS
@@ -1613,6 +1614,11 @@ public final class Settings {
public static final String CALL_METHOD_GET_GLOBAL = "GET_global";
/**
+ * @hide - Private call() method on SettingsProvider to read from 'config' table.
+ */
+ public static final String CALL_METHOD_GET_CONFIG = "GET_config";
+
+ /**
* @hide - Specifies that the caller of the fast-path call()-based flow tracks
* the settings generation in order to cache values locally. If this key is
* mapped to a <code>null</code> string extra in the request bundle, the response
@@ -1671,9 +1677,15 @@ public final class Settings {
/** @hide - Private call() method to write to 'global' table */
public static final String CALL_METHOD_PUT_GLOBAL= "PUT_global";
+ /** @hide - Private call() method to write to 'configuration' table */
+ public static final String CALL_METHOD_PUT_CONFIG = "PUT_config";
+
/** @hide - Private call() method to reset to defaults the 'global' table */
public static final String CALL_METHOD_RESET_GLOBAL = "RESET_global";
+ /** @hide - Private call() method to reset to defaults the 'configuration' table */
+ public static final String CALL_METHOD_RESET_CONFIG = "RESET_config";
+
/** @hide - Private call() method to reset to defaults the 'secure' table */
public static final String CALL_METHOD_RESET_SECURE = "RESET_secure";
@@ -11657,6 +11669,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
@@ -12389,6 +12407,28 @@ public final class Settings {
"sms_access_restriction_enabled";
/**
+ * If set to 1, an app must have the READ_PRIVILEGED_PHONE_STATE permission (or be a device
+ * / profile owner with the READ_PHONE_STATE permission) to access device identifiers.
+ *
+ * STOPSHIP: Remove this once we ship with the new device identifier check enabled.
+ *
+ * @hide
+ */
+ public static final String PRIVILEGED_DEVICE_IDENTIFIER_CHECK_ENABLED =
+ "privileged_device_identifier_check_enabled";
+
+ /**
+ * If set to 1, an app that is targeting Q and does not meet the new requirements to access
+ * device identifiers will receive a SecurityException.
+ *
+ * STOPSHIP: Remove this once we ship with the new device identifier check enabled.
+ *
+ * @hide
+ */
+ public static final String PRIVILEGED_DEVICE_IDENTIFIER_TARGET_Q_BEHAVIOR_ENABLED =
+ "privileged_device_identifier_target_q_behavior_enabled";
+
+ /**
* If set to 1, SettingsProvider's restoreAnyVersion="true" attribute will be ignored
* and restoring to lower version of platform API will be skipped.
*
@@ -13458,6 +13498,112 @@ public final class Settings {
}
/**
+ * Configuration system settings, containing settings which are applied identically for all
+ * defined users. Only Android can read these and only a specific configuration service can
+ * write these.
+ *
+ * @hide
+ */
+ public static final class Config extends NameValueTable {
+ /**
+ * The content:// style URL for the config table.
+ *
+ * TODO(b/113100523): Move this to DeviceConfig.java when it is added, and expose it as a
+ * System API.
+ */
+ private static final Uri CONTENT_URI =
+ Uri.parse("content://" + AUTHORITY + "/config");
+
+ private static final ContentProviderHolder sProviderHolder =
+ new ContentProviderHolder(CONTENT_URI);
+
+ // Populated lazily, guarded by class object:
+ private static final NameValueCache sNameValueCache = new NameValueCache(
+ CONTENT_URI,
+ CALL_METHOD_GET_CONFIG,
+ CALL_METHOD_PUT_CONFIG,
+ sProviderHolder);
+
+ /**
+ * Look up a name in the database.
+ * @param resolver to access the database with
+ * @param name to look up in the table
+ * @return the corresponding value, or null if not present
+ *
+ * @hide
+ */
+ // TODO(b/117663715): require a new read permission
+ static String getString(ContentResolver resolver, String name) {
+ return sNameValueCache.getStringForUser(resolver, name, resolver.getUserId());
+ }
+
+ /**
+ * Store a name/value pair into the database.
+ * <p>
+ * The method takes an optional tag to associate with the setting which can be used to clear
+ * only settings made by your package and associated with this tag by passing the tag to
+ * {@link #resetToDefaults(ContentResolver, String)}. The value of this setting can be
+ * overridden by future calls to this or other put methods, and the tag provided in those
+ * calls, which may be null, will override the tag provided in this call. Any call to a put
+ * method which does not accept a tag will effectively set the tag to null.
+ * </p><p>
+ * Also the method takes an argument whether to make the value the default for this setting.
+ * If the system already specified a default value, then the one passed in here will
+ * <strong>not</strong> be set as the default.
+ * </p>
+ *
+ * @param resolver to access the database with.
+ * @param name to store.
+ * @param value to associate with the name.
+ * @param tag to associated with the setting.
+ * @param makeDefault whether to make the value the default one.
+ * @return true if the value was set, false on database errors.
+ *
+ * @see #resetToDefaults(ContentResolver, String)
+ *
+ * @hide
+ */
+ // TODO(b/117663715): require a new write permission restricted to a single source
+ @RequiresPermission(Manifest.permission.WRITE_SECURE_SETTINGS)
+ static boolean putString(@NonNull ContentResolver resolver,
+ @NonNull String name, @Nullable String value, @Nullable String tag,
+ boolean makeDefault) {
+ return sNameValueCache.putStringForUser(resolver, name, value, tag, makeDefault,
+ resolver.getUserId());
+ }
+
+ /**
+ * Reset the settings to their defaults. This would reset <strong>only</strong> settings set
+ * by the caller's package. Passing in the optional tag will reset only settings changed by
+ * your package and associated with this tag.
+ *
+ * @param resolver Handle to the content resolver.
+ * @param tag Optional tag which should be associated with the settings to reset.
+ *
+ * @see #putString(ContentResolver, String, String, String, boolean)
+ *
+ * @hide
+ */
+ // TODO(b/117663715): require a new write permission restricted to a single source
+ @RequiresPermission(Manifest.permission.WRITE_SECURE_SETTINGS)
+ static void resetToDefaults(@NonNull ContentResolver resolver,
+ @Nullable String tag) {
+ try {
+ Bundle arg = new Bundle();
+ arg.putInt(CALL_METHOD_USER_KEY, resolver.getUserId());
+ if (tag != null) {
+ arg.putString(CALL_METHOD_TAG_KEY, tag);
+ }
+ arg.putInt(CALL_METHOD_RESET_MODE_KEY, RESET_MODE_PACKAGE_DEFAULTS);
+ IContentProvider cp = sProviderHolder.getProvider(resolver);
+ cp.call(resolver.getPackageName(), CALL_METHOD_RESET_CONFIG, null, arg);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Can't reset to defaults for " + CONTENT_URI, e);
+ }
+ }
+ }
+
+ /**
* User-defined bookmarks and shortcuts. The target of each bookmark is an
* Intent URL, allowing it to be either a web page or a particular
* application activity.
diff --git a/core/java/android/security/keystore/recovery/KeyChainSnapshot.java b/core/java/android/security/keystore/recovery/KeyChainSnapshot.java
index c748c87e0805..035b226fc724 100644
--- a/core/java/android/security/keystore/recovery/KeyChainSnapshot.java
+++ b/core/java/android/security/keystore/recovery/KeyChainSnapshot.java
@@ -113,19 +113,6 @@ public final class KeyChainSnapshot implements Parcelable {
}
/**
- * Public key used to encrypt {@code encryptedRecoveryKeyBlob}.
- *
- * See implementation for binary key format.
- *
- * @deprecated Use {@link #getTrustedHardwareCertPath} instead.
- * @removed
- */
- @Deprecated
- public @NonNull byte[] getTrustedHardwarePublicKey() {
- throw new UnsupportedOperationException();
- }
-
- /**
* CertPath containing the public key used to encrypt {@code encryptedRecoveryKeyBlob}.
*/
public @NonNull CertPath getTrustedHardwareCertPath() {
@@ -223,18 +210,6 @@ public final class KeyChainSnapshot implements Parcelable {
}
/**
- * Sets public key used to encrypt recovery blob.
- *
- * @param publicKey The public key
- * @return This builder.
- * @removed Use {@link #setTrustedHardwareCertPath} instead.
- */
- @Deprecated
- public Builder setTrustedHardwarePublicKey(byte[] publicKey) {
- throw new UnsupportedOperationException();
- }
-
- /**
* Sets CertPath used to validate the trusted hardware public key. The CertPath should
* contain a certificate of the trusted hardware public key and any necessary intermediate
* certificates.
diff --git a/core/java/android/security/keystore/recovery/RecoveryController.java b/core/java/android/security/keystore/recovery/RecoveryController.java
index 70054fc2d71e..31a5962c7e9a 100644
--- a/core/java/android/security/keystore/recovery/RecoveryController.java
+++ b/core/java/android/security/keystore/recovery/RecoveryController.java
@@ -23,7 +23,6 @@ import android.annotation.SystemApi;
import android.app.KeyguardManager;
import android.app.PendingIntent;
import android.content.Context;
-import android.content.pm.PackageManager.NameNotFoundException;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.ServiceSpecificException;
@@ -301,18 +300,6 @@ public class RecoveryController {
}
/**
- * @deprecated Use {@link #initRecoveryService(String, byte[], byte[])} instead.
- * @removed
- */
- @Deprecated
- @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE)
- public void initRecoveryService(
- @NonNull String rootCertificateAlias, @NonNull byte[] signedPublicKeyList)
- throws CertificateException, InternalRecoveryServiceException {
- throw new UnsupportedOperationException();
- }
-
- /**
* Initializes the recovery service for the calling application. The detailed steps should be:
* <ol>
* <li>Parse {@code signatureFile} to get relevant information.
@@ -363,16 +350,6 @@ public class RecoveryController {
}
/**
- * @deprecated Use {@link #getKeyChainSnapshot()}
- * @removed
- */
- @Deprecated
- @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE)
- public @Nullable KeyChainSnapshot getRecoveryData() throws InternalRecoveryServiceException {
- throw new UnsupportedOperationException();
- }
-
- /**
* Returns data necessary to store all recoverable keys. Key material is
* encrypted with user secret and recovery public key.
*
@@ -440,17 +417,6 @@ public class RecoveryController {
}
/**
- * @deprecated Use {@link #getAliases()}.
- * @removed
- */
- @Deprecated
- @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE)
- public List<String> getAliases(@Nullable String packageName)
- throws InternalRecoveryServiceException {
- throw new UnsupportedOperationException();
- }
-
- /**
* Returns a list of aliases of keys belonging to the application.
*/
@RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE)
@@ -466,18 +432,6 @@ public class RecoveryController {
}
/**
- * @deprecated Use {@link #setRecoveryStatus(String, int)}
- * @removed
- */
- @Deprecated
- @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE)
- public void setRecoveryStatus(
- @NonNull String packageName, String alias, int status)
- throws NameNotFoundException, InternalRecoveryServiceException {
- throw new UnsupportedOperationException();
- }
-
- /**
* Sets the recovery status for given key. It is used to notify the keystore that the key was
* successfully stored on the server or that there was an error. An application can check this
* value using {@link #getRecoveryStatus(String, String)}.
@@ -501,17 +455,6 @@ public class RecoveryController {
}
/**
- * @deprecated Use {@link #getRecoveryStatus(String)}.
- * @removed
- */
- @Deprecated
- @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE)
- public int getRecoveryStatus(String packageName, String alias)
- throws InternalRecoveryServiceException {
- throw new UnsupportedOperationException();
- }
-
- /**
* Returns the recovery status for the key with the given {@code alias}.
*
* <ul>
@@ -584,39 +527,6 @@ public class RecoveryController {
}
/**
- * Deprecated.
- * Generates a AES256/GCM/NoPADDING key called {@code alias} and loads it into the recoverable
- * key store. Returns the raw material of the key.
- *
- * @param alias The key alias.
- * @param account The account associated with the key
- * @throws InternalRecoveryServiceException if an unexpected error occurred in the recovery
- * service.
- * @throws LockScreenRequiredException if the user has not set a lock screen. This is required
- * to generate recoverable keys, as the snapshots are encrypted using a key derived from the
- * lock screen.
- * @deprecated Use {@link #generateKey(String)}
- * @removed
- */
- @Deprecated
- @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE)
- public byte[] generateAndStoreKey(@NonNull String alias, byte[] account)
- throws InternalRecoveryServiceException, LockScreenRequiredException {
- throw new UnsupportedOperationException("Operation is not supported, use generateKey");
- }
-
- /**
- * @deprecated Use {@link #generateKey(String)}.
- * @removed
- */
- @Deprecated
- @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE)
- public Key generateKey(@NonNull String alias, byte[] account)
- throws InternalRecoveryServiceException, LockScreenRequiredException {
- throw new UnsupportedOperationException();
- }
-
- /**
* Generates a recoverable key with the given {@code alias}.
*
* @throws InternalRecoveryServiceException if an unexpected error occurred in the recovery
diff --git a/core/java/android/security/keystore/recovery/RecoverySession.java b/core/java/android/security/keystore/recovery/RecoverySession.java
index 3bb64219cdca..42e718268d2d 100644
--- a/core/java/android/security/keystore/recovery/RecoverySession.java
+++ b/core/java/android/security/keystore/recovery/RecoverySession.java
@@ -78,36 +78,6 @@ public class RecoverySession implements AutoCloseable {
}
/**
- * @deprecated Use {@link #start(String, CertPath, byte[], byte[], List)} instead.
- * @removed
- */
- @Deprecated
- @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE)
- @NonNull public byte[] start(
- @NonNull byte[] verifierPublicKey,
- @NonNull byte[] vaultParams,
- @NonNull byte[] vaultChallenge,
- @NonNull List<KeyChainProtectionParams> secrets)
- throws CertificateException, InternalRecoveryServiceException {
- throw new UnsupportedOperationException();
- }
-
- /**
- * @deprecated Use {@link #start(String, CertPath, byte[], byte[], List)} instead.
- * @removed
- */
- @Deprecated
- @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE)
- @NonNull public byte[] start(
- @NonNull CertPath verifierCertPath,
- @NonNull byte[] vaultParams,
- @NonNull byte[] vaultChallenge,
- @NonNull List<KeyChainProtectionParams> secrets)
- throws CertificateException, InternalRecoveryServiceException {
- throw new UnsupportedOperationException();
- }
-
- /**
* Starts a recovery session and returns a blob with proof of recovery secret possession.
* The method generates a symmetric key for a session, which trusted remote device can use to
* return recovery key.
@@ -162,20 +132,6 @@ public class RecoverySession implements AutoCloseable {
}
/**
- * @deprecated Use {@link #recoverKeyChainSnapshot(byte[], List)} instead.
- * @removed
- */
- @Deprecated
- @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE)
- public Map<String, byte[]> recoverKeys(
- @NonNull byte[] recoveryKeyBlob,
- @NonNull List<WrappedApplicationKey> applicationKeys)
- throws SessionExpiredException, DecryptionFailedException,
- InternalRecoveryServiceException {
- throw new UnsupportedOperationException();
- }
-
- /**
* Imports key chain snapshot recovered from a remote vault.
*
* @param recoveryKeyBlob Recovery blob encrypted by symmetric key generated for this session.
diff --git a/core/java/android/security/keystore/recovery/WrappedApplicationKey.java b/core/java/android/security/keystore/recovery/WrappedApplicationKey.java
index 187a671c57cb..ae4448f9c908 100644
--- a/core/java/android/security/keystore/recovery/WrappedApplicationKey.java
+++ b/core/java/android/security/keystore/recovery/WrappedApplicationKey.java
@@ -75,15 +75,6 @@ public final class WrappedApplicationKey implements Parcelable {
}
/**
- * @deprecated AOSP does not associate keys with accounts. This may be done by system app.
- * @removed
- */
- @Deprecated
- public Builder setAccount(@NonNull byte[] account) {
- throw new UnsupportedOperationException();
- }
-
- /**
* Sets key material encrypted by recovery key.
*
* @param encryptedKeyMaterial The key material
@@ -133,15 +124,6 @@ public final class WrappedApplicationKey implements Parcelable {
return mEncryptedKeyMaterial;
}
- /**
- * @deprecated AOSP does not associate keys with accounts. This may be done by system app.
- * @removed
- */
- @Deprecated
- public @NonNull byte[] getAccount() {
- throw new UnsupportedOperationException();
- }
-
public static final Parcelable.Creator<WrappedApplicationKey> CREATOR =
new Parcelable.Creator<WrappedApplicationKey>() {
public WrappedApplicationKey createFromParcel(Parcel in) {
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/speech/tts/TextToSpeechService.java b/core/java/android/speech/tts/TextToSpeechService.java
index 10d7911316ac..ec63cd941b3f 100644
--- a/core/java/android/speech/tts/TextToSpeechService.java
+++ b/core/java/android/speech/tts/TextToSpeechService.java
@@ -1112,7 +1112,6 @@ public abstract class TextToSpeechService extends Service {
@Override
protected void playImpl() {
- dispatchOnStart();
super.playImpl();
try {
mFileOutputStream.close();
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..f9370a8aa6af 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?
@@ -504,13 +505,13 @@ public class MeasuredParagraph {
}
mWholeWidth += width;
} else {
- builder.addReplacementRun(mCachedPaint, start, end, width);
+ builder.appendReplacementRun(mCachedPaint, end - start, width);
}
}
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.
@@ -519,7 +520,7 @@ public class MeasuredParagraph {
mCopiedBuffer, start, end - start, start, end - start, false /* isRtl */,
mWidths.getRawArray(), start);
} else {
- builder.addStyleRun(mCachedPaint, start, end, false /* isRtl */);
+ builder.appendStyleRun(mCachedPaint, end - start, false /* isRtl */);
}
} else {
// If there is multiple bidi levels, split into individual bidi level and apply style.
@@ -535,7 +536,7 @@ public class MeasuredParagraph {
mCopiedBuffer, levelStart, levelLength, levelStart, levelLength,
isRtl, mWidths.getRawArray(), levelStart);
} else {
- builder.addStyleRun(mCachedPaint, levelStart, levelEnd, isRtl);
+ builder.appendStyleRun(mCachedPaint, levelEnd - levelStart, isRtl);
}
if (levelEnd == end) {
break;
@@ -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..f846a356d8fa 100644
--- a/core/java/android/text/style/TextAppearanceSpan.java
+++ b/core/java/android/text/style/TextAppearanceSpan.java
@@ -23,14 +23,40 @@ import android.content.res.TypedArray;
import android.graphics.LeakyTypefaceStorage;
import android.graphics.Typeface;
import android.graphics.fonts.Font;
+import android.os.LocaleList;
import android.os.Parcel;
import android.text.ParcelableSpan;
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;
@@ -41,6 +67,7 @@ public class TextAppearanceSpan extends MetricAffectingSpan implements Parcelabl
private final Typeface mTypeface;
private final int mTextFontWeight;
+ private final LocaleList mTextLocales;
private final float mShadowRadius;
private final float mShadowDx;
@@ -124,6 +151,19 @@ public class TextAppearanceSpan extends MetricAffectingSpan implements Parcelabl
mTextFontWeight = a.getInt(com.android.internal.R.styleable
.TextAppearance_textFontWeight, -1);
+ final String localeString = a.getString(com.android.internal.R.styleable
+ .TextAppearance_textLocale);
+ if (localeString != null) {
+ LocaleList localeList = LocaleList.forLanguageTags(localeString);
+ if (!localeList.isEmpty()) {
+ mTextLocales = localeList;
+ } else {
+ mTextLocales = null;
+ }
+ } else {
+ mTextLocales = null;
+ }
+
mShadowRadius = a.getFloat(com.android.internal.R.styleable
.TextAppearance_shadowRadius, 0.0f);
mShadowDx = a.getFloat(com.android.internal.R.styleable
@@ -176,6 +216,7 @@ public class TextAppearanceSpan extends MetricAffectingSpan implements Parcelabl
mTypeface = null;
mTextFontWeight = -1;
+ mTextLocales = null;
mShadowRadius = 0.0f;
mShadowDx = 0.0f;
@@ -208,6 +249,7 @@ public class TextAppearanceSpan extends MetricAffectingSpan implements Parcelabl
mTypeface = LeakyTypefaceStorage.readTypefaceFromParcel(src);
mTextFontWeight = src.readInt();
+ mTextLocales = src.readParcelable(LocaleList.class.getClassLoader());
mShadowRadius = src.readFloat();
mShadowDx = src.readFloat();
@@ -260,6 +302,7 @@ public class TextAppearanceSpan extends MetricAffectingSpan implements Parcelabl
LeakyTypefaceStorage.writeTypefaceToParcel(mTypeface, dest);
dest.writeInt(mTextFontWeight);
+ dest.writeParcelable(mTextLocales, flags);
dest.writeFloat(mShadowRadius);
dest.writeFloat(mShadowDx);
@@ -324,6 +367,15 @@ public class TextAppearanceSpan extends MetricAffectingSpan implements Parcelabl
}
/**
+ * Returns the {@link android.os.LocaleList} specified by this span, or <code>null</code>
+ * if it does not specify one.
+ */
+ @Nullable
+ public LocaleList getTextLocales() {
+ return mTextLocales;
+ }
+
+ /**
* Returns the typeface specified by this span, or <code>null</code>
* if it does not specify one.
*/
@@ -462,6 +514,10 @@ public class TextAppearanceSpan extends MetricAffectingSpan implements Parcelabl
ds.setTextSize(mTextSize);
}
+ if (mTextLocales != null) {
+ ds.setTextLocales(mTextLocales);
+ }
+
if (mHasElegantTextHeight) {
ds.setElegantTextHeight(mElegantTextHeight);
}
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/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index 183e83304925..db2c19043361 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -47,7 +47,7 @@ public class FeatureFlagUtils {
DEFAULT_FLAGS.put("settings_mobile_network_v2", "false");
DEFAULT_FLAGS.put("settings_data_usage_v2", "false");
DEFAULT_FLAGS.put("settings_seamless_transfer", "false");
- DEFAULT_FLAGS.put(HEARING_AID_SETTINGS, "true");
+ DEFAULT_FLAGS.put(HEARING_AID_SETTINGS, "false");
DEFAULT_FLAGS.put(EMERGENCY_DIAL_SHORTCUTS, "false");
}
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/MotionEvent.java b/core/java/android/view/MotionEvent.java
index 29c58dc512fa..b59d8c720b9d 100644
--- a/core/java/android/view/MotionEvent.java
+++ b/core/java/android/view/MotionEvent.java
@@ -1776,6 +1776,47 @@ public final class MotionEvent extends InputEvent implements Parcelable {
static public MotionEvent obtain(long downTime, long eventTime, int action,
float x, float y, float pressure, float size, int metaState,
float xPrecision, float yPrecision, int deviceId, int edgeFlags) {
+ return obtain(downTime, eventTime, action, x, y, pressure, size, metaState,
+ xPrecision, yPrecision, deviceId, edgeFlags, InputDevice.SOURCE_UNKNOWN,
+ DEFAULT_DISPLAY);
+ }
+
+ /**
+ * Create a new MotionEvent, filling in all of the basic values that
+ * define the motion.
+ *
+ * @param downTime The time (in ms) when the user originally pressed down to start
+ * a stream of position events. This must be obtained from {@link SystemClock#uptimeMillis()}.
+ * @param eventTime The the time (in ms) when this specific event was generated. This
+ * must be obtained from {@link SystemClock#uptimeMillis()}.
+ * @param action The kind of action being performed, such as {@link #ACTION_DOWN}.
+ * @param x The X coordinate of this event.
+ * @param y The Y coordinate of this event.
+ * @param pressure The current pressure of this event. The pressure generally
+ * ranges from 0 (no pressure at all) to 1 (normal pressure), however
+ * values higher than 1 may be generated depending on the calibration of
+ * the input device.
+ * @param size A scaled value of the approximate size of the area being pressed when
+ * touched with the finger. The actual value in pixels corresponding to the finger
+ * touch is normalized with a device specific range of values
+ * and scaled to a value between 0 and 1.
+ * @param metaState The state of any meta / modifier keys that were in effect when
+ * the event was generated.
+ * @param xPrecision The precision of the X coordinate being reported.
+ * @param yPrecision The precision of the Y coordinate being reported.
+ * @param deviceId The id for the device that this event came from. An id of
+ * zero indicates that the event didn't come from a physical device; other
+ * numbers are arbitrary and you shouldn't depend on the values.
+ * @param source The source of this event.
+ * @param edgeFlags A bitfield indicating which edges, if any, were touched by this
+ * MotionEvent.
+ * @param displayId The display ID associated with this event.
+ * @hide
+ */
+ public static MotionEvent obtain(long downTime, long eventTime, int action,
+ float x, float y, float pressure, float size, int metaState,
+ float xPrecision, float yPrecision, int deviceId, int edgeFlags, int source,
+ int displayId) {
MotionEvent ev = obtain();
synchronized (gSharedTempLock) {
ensureSharedTempPointerCapacity(1);
@@ -1791,7 +1832,7 @@ public final class MotionEvent extends InputEvent implements Parcelable {
pc[0].size = size;
ev.mNativePtr = nativeInitialize(ev.mNativePtr,
- deviceId, InputDevice.SOURCE_UNKNOWN, DEFAULT_DISPLAY,
+ deviceId, source, displayId,
action, 0, edgeFlags, metaState, 0,
0, 0, xPrecision, yPrecision,
downTime * NS_PER_MS, eventTime * NS_PER_MS,
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 959dd328f599..2437949287d1 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);
}
@@ -12873,20 +12896,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();
@@ -14259,9 +14281,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);
}
@@ -17980,10 +18003,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 */);
}
}
@@ -24176,7 +24196,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) {
@@ -24219,51 +24239,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/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 1b3e62d64ef3..58febb050150 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -541,11 +541,11 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
private static final int CHILD_TOP_INDEX = 1;
// Child views of this ViewGroup
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
private View[] mChildren;
// Number of valid children in the mChildren array, the rest should be null or not
// considered as children
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
private int mChildrenCount;
// Whether layout calls are currently being suppressed, controlled by calls to
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..a401c6def23a 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
@@ -1057,13 +1052,6 @@ public final class InputMethodManager {
mNextServedView = null;
if (mServedView != null) {
if (DEBUG) Log.v(TAG, "FINISH INPUT: mServedView=" + dumpViewInfo(mServedView));
- if (mCurrentTextBoxAttribute != null) {
- try {
- mService.finishInput(mClient);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
mServedView = null;
mCompletions = null;
mServedConnecting = false;
@@ -2690,7 +2678,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/view/textclassifier/TextClassifier.java b/core/java/android/view/textclassifier/TextClassifier.java
index 9692579de6ba..2e92f14c931c 100644
--- a/core/java/android/view/textclassifier/TextClassifier.java
+++ b/core/java/android/view/textclassifier/TextClassifier.java
@@ -21,7 +21,6 @@ import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.StringDef;
-import android.annotation.UnsupportedAppUsage;
import android.annotation.WorkerThread;
import android.os.LocaleList;
import android.os.Looper;
@@ -212,34 +211,13 @@ public interface TextClassifier {
return suggestSelection(request);
}
- // TODO: Remove once apps can build against the latest sdk.
- /** @hide */
- @UnsupportedAppUsage
- default TextSelection suggestSelection(
- @NonNull CharSequence text,
- @IntRange(from = 0) int selectionStartIndex,
- @IntRange(from = 0) int selectionEndIndex,
- @Nullable TextSelection.Options options) {
- if (options == null) {
- return suggestSelection(new TextSelection.Request.Builder(
- text, selectionStartIndex, selectionEndIndex).build());
- } else if (options.getRequest() != null) {
- return suggestSelection(options.getRequest());
- } else {
- return suggestSelection(
- new TextSelection.Request.Builder(text, selectionStartIndex, selectionEndIndex)
- .setDefaultLocales(options.getDefaultLocales())
- .build());
- }
- }
-
/**
* Classifies the specified text and returns a {@link TextClassification} object that can be
* used to generate a widget for handling the classified text.
*
* <p><strong>NOTE: </strong>Call on a worker thread.
*
- * <strong>NOTE: </strong>If a TextClassifier has been destroyed, calls to this method should
+ * <p><strong>NOTE: </strong>If a TextClassifier has been destroyed, calls to this method should
* throw an {@link IllegalStateException}. See {@link #isDestroyed()}.
*
* @param request the text classification request
@@ -262,7 +240,7 @@ public interface TextClassifier {
* {@link #classifyText(TextClassification.Request)}. If that method calls this method,
* a stack overflow error will happen.
*
- * <strong>NOTE: </strong>If a TextClassifier has been destroyed, calls to this method should
+ * <p><strong>NOTE: </strong>If a TextClassifier has been destroyed, calls to this method should
* throw an {@link IllegalStateException}. See {@link #isDestroyed()}.
*
* @param text text providing context for the text to classify (which is specified
@@ -292,34 +270,13 @@ public interface TextClassifier {
return classifyText(request);
}
- // TODO: Remove once apps can build against the latest sdk.
- /** @hide */
- @UnsupportedAppUsage
- default TextClassification classifyText(
- @NonNull CharSequence text,
- @IntRange(from = 0) int startIndex,
- @IntRange(from = 0) int endIndex,
- @Nullable TextClassification.Options options) {
- if (options == null) {
- return classifyText(
- new TextClassification.Request.Builder(text, startIndex, endIndex).build());
- } else if (options.getRequest() != null) {
- return classifyText(options.getRequest());
- } else {
- return classifyText(new TextClassification.Request.Builder(text, startIndex, endIndex)
- .setDefaultLocales(options.getDefaultLocales())
- .setReferenceTime(options.getReferenceTime())
- .build());
- }
- }
-
/**
* Generates and returns a {@link TextLinks} that may be applied to the text to annotate it with
* links information.
*
* <p><strong>NOTE: </strong>Call on a worker thread.
*
- * <strong>NOTE: </strong>If a TextClassifier has been destroyed, calls to this method should
+ * <p><strong>NOTE: </strong>If a TextClassifier has been destroyed, calls to this method should
* throw an {@link IllegalStateException}. See {@link #isDestroyed()}.
*
* @param request the text links request
@@ -334,27 +291,10 @@ public interface TextClassifier {
return new TextLinks.Builder(request.getText().toString()).build();
}
- // TODO: Remove once apps can build against the latest sdk.
- /** @hide */
- @UnsupportedAppUsage
- default TextLinks generateLinks(
- @NonNull CharSequence text, @Nullable TextLinks.Options options) {
- if (options == null) {
- return generateLinks(new TextLinks.Request.Builder(text).build());
- } else if (options.getRequest() != null) {
- return generateLinks(options.getRequest());
- } else {
- return generateLinks(new TextLinks.Request.Builder(text)
- .setDefaultLocales(options.getDefaultLocales())
- .setEntityConfig(options.getEntityConfig())
- .build());
- }
- }
-
/**
* Returns the maximal length of text that can be processed by generateLinks.
*
- * <strong>NOTE: </strong>If a TextClassifier has been destroyed, calls to this method should
+ * <p><strong>NOTE: </strong>If a TextClassifier has been destroyed, calls to this method should
* throw an {@link IllegalStateException}. See {@link #isDestroyed()}.
*
* @see #generateLinks(TextLinks.Request)
@@ -365,9 +305,29 @@ public interface TextClassifier {
}
/**
+ * Detects the language of the specified text.
+ *
+ * <p><strong>NOTE: </strong>Call on a worker thread.
+ *
+ *
+ * <p><strong>NOTE: </strong>If a TextClassifier has been destroyed, calls to this method should
+ * throw an {@link IllegalStateException}. See {@link #isDestroyed()}.
+ *
+ * @param request the {@link TextLanguage} request.
+ * @return the {@link TextLanguage} result.
+ */
+ @WorkerThread
+ @NonNull
+ default TextLanguage detectLanguage(@NonNull TextLanguage.Request request) {
+ Preconditions.checkNotNull(request);
+ Utils.checkMainThread();
+ return TextLanguage.EMPTY;
+ }
+
+ /**
* Reports a selection event.
*
- * <strong>NOTE: </strong>If a TextClassifier has been destroyed, calls to this method should
+ * <p><strong>NOTE: </strong>If a TextClassifier has been destroyed, calls to this method should
* throw an {@link IllegalStateException}. See {@link #isDestroyed()}.
*/
default void onSelectionEvent(@NonNull SelectionEvent event) {}
@@ -375,7 +335,7 @@ public interface TextClassifier {
/**
* Destroys this TextClassifier.
*
- * <strong>NOTE: </strong>If a TextClassifier has been destroyed, calls to its methods should
+ * <p><strong>NOTE: </strong>If a TextClassifier has been destroyed, calls to its methods should
* throw an {@link IllegalStateException}. See {@link #isDestroyed()}.
*
* <p>Subsequent calls to this method are no-ops.
@@ -385,7 +345,7 @@ public interface TextClassifier {
/**
* Returns whether or not this TextClassifier has been destroyed.
*
- * <strong>NOTE: </strong>If a TextClassifier has been destroyed, caller should not interact
+ * <p><strong>NOTE: </strong>If a TextClassifier has been destroyed, caller should not interact
* with the classifier and an attempt to do so would throw an {@link IllegalStateException}.
* However, this method should never throw an {@link IllegalStateException}.
*
@@ -396,9 +356,7 @@ public interface TextClassifier {
}
/** @hide **/
- default void dump(@NonNull IndentingPrintWriter printWriter) {
-
- }
+ default void dump(@NonNull IndentingPrintWriter printWriter) {}
/**
* Configuration object for specifying what entities to identify.
diff --git a/core/java/android/view/textclassifier/TextLanguage.java b/core/java/android/view/textclassifier/TextLanguage.java
new file mode 100644
index 000000000000..d28459e733f0
--- /dev/null
+++ b/core/java/android/view/textclassifier/TextLanguage.java
@@ -0,0 +1,307 @@
+/*
+ * 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.view.textclassifier;
+
+import android.annotation.FloatRange;
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.icu.util.ULocale;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.ArrayMap;
+
+import com.android.internal.util.Preconditions;
+
+import java.util.Locale;
+import java.util.Map;
+
+/**
+ * Represents the result of language detection of a piece of text.
+ * <p>
+ * This contains a list of locales, each paired with a confidence score, sorted in decreasing
+ * order of those scores. E.g., for a given input text, the model may return
+ * {@code [<"en", 0.85>, <"fr", 0.15>]}. This sample result means the model reports that it is
+ * 85% likely that the entire text is in English and 15% likely that the entire text is in French,
+ * etc. It does not mean that 85% of the input is in English and 15% is in French.
+ */
+public final class TextLanguage implements Parcelable {
+
+ public static final Creator<TextLanguage> CREATOR = new Creator<TextLanguage>() {
+ @Override
+ public TextLanguage createFromParcel(Parcel in) {
+ return readFromParcel(in);
+ }
+
+ @Override
+ public TextLanguage[] newArray(int size) {
+ return new TextLanguage[size];
+ }
+ };
+
+ static final TextLanguage EMPTY = new Builder().build();
+
+ @Nullable private final String mId;
+ private final EntityConfidence mEntityConfidence;
+ private final Bundle mBundle;
+
+ private TextLanguage(
+ @Nullable String id,
+ EntityConfidence entityConfidence,
+ Bundle bundle) {
+ mId = id;
+ mEntityConfidence = entityConfidence;
+ mBundle = bundle;
+ }
+
+ /**
+ * Returns the id, if one exists, for this object.
+ */
+ @Nullable
+ public String getId() {
+ return mId;
+ }
+
+ /**
+ * Returns the number of possible locales for the processed text.
+ */
+ @IntRange(from = 0)
+ public int getLocaleHypothesisCount() {
+ return mEntityConfidence.getEntities().size();
+ }
+
+ /**
+ * Returns the language locale at the specified index. Locales are ordered from high
+ * confidence to low confidence.
+ *
+ * @throws IndexOutOfBoundsException if the specified index is out of range.
+ * @see #getLocaleCount() for the number of locales available.
+ */
+ @NonNull
+ public ULocale getLocale(int index) {
+ return ULocale.forLanguageTag(mEntityConfidence.getEntities().get(index));
+ }
+
+ /**
+ * Returns the confidence score for the specified language locale. The value ranges from
+ * 0 (low confidence) to 1 (high confidence). 0 indicates that the locale was not found for
+ * the processed text.
+ */
+ @FloatRange(from = 0.0, to = 1.0)
+ public float getConfidenceScore(@NonNull ULocale locale) {
+ return mEntityConfidence.getConfidenceScore(locale.toLanguageTag());
+ }
+
+ /**
+ * Returns a bundle containing non-structured extra information about this result.
+ *
+ * <p><b>NOTE: </b>Each call to this method returns a new bundle copy so clients should prefer
+ * to hold a reference to the returned bundle rather than frequently calling this method.
+ */
+ @NonNull
+ public Bundle getExtras() {
+ return mBundle.deepCopy();
+ }
+
+ @Override
+ public String toString() {
+ return String.format(
+ Locale.US,
+ "TextLanguage {id=%s, locales=%s, bundle=%s}",
+ mId, mEntityConfidence, mBundle);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(mId);
+ mEntityConfidence.writeToParcel(dest, flags);
+ dest.writeBundle(mBundle);
+ }
+
+ private static TextLanguage readFromParcel(Parcel in) {
+ return new TextLanguage(
+ in.readString(),
+ EntityConfidence.CREATOR.createFromParcel(in),
+ in.readBundle());
+ }
+
+ /**
+ * Builder used to build TextLanguage objects.
+ */
+ public static final class Builder {
+
+ @Nullable private String mId;
+ private final Map<String, Float> mEntityConfidenceMap = new ArrayMap<>();
+ @Nullable private Bundle mBundle;
+
+ /**
+ * Sets a language locale for the processed text and assigns a confidence score. If the
+ * locale has already been set, this updates it.
+ *
+ * @param confidenceScore a value from 0 (low confidence) to 1 (high confidence).
+ * 0 implies the locale does not exist for the processed text.
+ * Values greater than 1 are clamped to 1.
+ */
+ @NonNull
+ public Builder putLocale(
+ @NonNull ULocale locale,
+ @FloatRange(from = 0.0, to = 1.0) float confidenceScore) {
+ Preconditions.checkNotNull(locale);
+ mEntityConfidenceMap.put(locale.toLanguageTag(), confidenceScore);
+ return this;
+ }
+
+ /**
+ * Sets an optional id for the TextLanguage object.
+ */
+ @NonNull
+ public Builder setId(@Nullable String id) {
+ mId = id;
+ return this;
+ }
+
+ /**
+ * Sets a bundle containing non-structured extra information about the TextLanguage object.
+ */
+ @NonNull
+ public Builder setExtras(@NonNull Bundle bundle) {
+ mBundle = Preconditions.checkNotNull(bundle);
+ return this;
+ }
+
+ /**
+ * Builds and returns a new TextLanguage object.
+ * <p>
+ * If necessary, this method will verify fields, clamp them, and make them immutable.
+ */
+ @NonNull
+ public TextLanguage build() {
+ mBundle = mBundle == null ? new Bundle() : mBundle.deepCopy();
+ return new TextLanguage(
+ mId,
+ new EntityConfidence(mEntityConfidenceMap),
+ mBundle);
+ }
+ }
+
+ /**
+ * A request object for detecting the language of a piece of text.
+ */
+ public static final class Request implements Parcelable {
+
+ public static final Creator<Request> CREATOR = new Creator<Request>() {
+ @Override
+ public Request createFromParcel(Parcel in) {
+ return readFromParcel(in);
+ }
+
+ @Override
+ public Request[] newArray(int size) {
+ return new Request[size];
+ }
+ };
+
+ private final CharSequence mText;
+ private final Bundle mBundle;
+
+ private Request(CharSequence text, Bundle bundle) {
+ mText = text;
+ mBundle = bundle;
+ }
+
+ /**
+ * Returns the text to process.
+ */
+ @NonNull
+ public CharSequence getText() {
+ return mText;
+ }
+
+ /**
+ * Returns a bundle containing non-structured extra information about this request.
+ *
+ * <p><b>NOTE: </b>Each call to this method returns a new bundle copy so clients should
+ * prefer to hold a reference to the returned bundle rather than frequently calling this
+ * method.
+ */
+ @NonNull
+ public Bundle getExtras() {
+ return mBundle.deepCopy();
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeCharSequence(mText);
+ dest.writeBundle(mBundle);
+ }
+
+ private static Request readFromParcel(Parcel in) {
+ return new Request(
+ in.readCharSequence(),
+ in.readBundle());
+ }
+
+ /**
+ * A builder for building TextLanguage requests.
+ */
+ public static final class Builder {
+
+ private final CharSequence mText;
+ @Nullable private Bundle mBundle;
+
+ /**
+ * Creates a builder to build TextLanguage requests.
+ *
+ * @param text the text to process.
+ */
+ public Builder(@NonNull CharSequence text) {
+ mText = Preconditions.checkNotNull(text);
+ }
+
+ /**
+ * Sets a bundle containing non-structured extra information about the request.
+ */
+ @NonNull
+ public Builder setExtras(@NonNull Bundle bundle) {
+ mBundle = Preconditions.checkNotNull(bundle);
+ return this;
+ }
+
+ /**
+ * Builds and returns a new TextLanguage request object.
+ * <p>
+ * If necessary, this method will verify fields, clamp them, and make them immutable.
+ */
+ @NonNull
+ public Request build() {
+ mBundle = mBundle == null ? new Bundle() : mBundle.deepCopy();
+ return new Request(mText.toString(), mBundle);
+ }
+ }
+ }
+}
diff --git a/core/java/android/webkit/WebViewClient.java b/core/java/android/webkit/WebViewClient.java
index bdd7a0900213..300bb6fd4890 100644
--- a/core/java/android/webkit/WebViewClient.java
+++ b/core/java/android/webkit/WebViewClient.java
@@ -282,19 +282,28 @@ public class WebViewClient {
SAFE_BROWSING_THREAT_UNKNOWN,
SAFE_BROWSING_THREAT_MALWARE,
SAFE_BROWSING_THREAT_PHISHING,
- SAFE_BROWSING_THREAT_UNWANTED_SOFTWARE
+ SAFE_BROWSING_THREAT_UNWANTED_SOFTWARE,
+ SAFE_BROWSING_THREAT_BILLING,
})
@Retention(RetentionPolicy.SOURCE)
public @interface SafeBrowsingThreat {}
- /** The resource was blocked for an unknown reason */
+ /** The resource was blocked for an unknown reason. */
public static final int SAFE_BROWSING_THREAT_UNKNOWN = 0;
- /** The resource was blocked because it contains malware */
+ /** The resource was blocked because it contains malware. */
public static final int SAFE_BROWSING_THREAT_MALWARE = 1;
- /** The resource was blocked because it contains deceptive content */
+ /** The resource was blocked because it contains deceptive content. */
public static final int SAFE_BROWSING_THREAT_PHISHING = 2;
- /** The resource was blocked because it contains unwanted software */
+ /** The resource was blocked because it contains unwanted software. */
public static final int SAFE_BROWSING_THREAT_UNWANTED_SOFTWARE = 3;
+ /**
+ * The resource was blocked because it may trick the user into a billing agreement.
+ *
+ * <p>This constant is only used when targetSdkVersion is at least {@link
+ * android.os.Build.VERSION_CODES#Q}. Otherwise, {@link #SAFE_BROWSING_THREAT_UNKNOWN} is used
+ * instead.
+ */
+ public static final int SAFE_BROWSING_THREAT_BILLING = 4;
/**
* Report an error to the host application. These errors are unrecoverable
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 35ff6cc23499..4d031232152a 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.
@@ -368,10 +370,12 @@ public class RemoteViews implements Parcelable, Filter {
// TODO: Unregister this handler if PendingIntent.FLAG_ONE_SHOT?
Context context = view.getContext();
ActivityOptions opts = getActivityOptions(context);
+ // The NEW_TASK flags are applied through the activity options and not as a part of
+ // the call to startIntentSender() to ensure that they are consistently applied to
+ // both mutable and immutable PendingIntents.
context.startIntentSender(
pendingIntent.getIntentSender(), fillInIntent,
- Intent.FLAG_ACTIVITY_NEW_TASK,
- Intent.FLAG_ACTIVITY_NEW_TASK, 0, opts.toBundle());
+ 0, 0, 0, opts.toBundle());
} catch (IntentSender.SendIntentException e) {
android.util.Log.e(LOG_TAG, "Cannot send pending intent: ", e);
return false;
@@ -399,10 +403,15 @@ public class RemoteViews implements Parcelable, Filter {
windowAnimationStyle.recycle();
if (enterAnimationId != 0) {
- return ActivityOptions.makeCustomAnimation(context, enterAnimationId, 0);
+ final ActivityOptions opts = ActivityOptions.makeCustomAnimation(context,
+ enterAnimationId, 0);
+ opts.setPendingIntentLaunchFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ return opts;
}
}
- return ActivityOptions.makeBasic();
+ final ActivityOptions opts = ActivityOptions.makeBasic();
+ opts.setPendingIntentLaunchFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ return opts;
}
}
@@ -1122,6 +1131,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 +2450,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 +2913,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..3dd6fd1410bd 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -3517,11 +3517,12 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
ColorStateList mTextColorHint = null;
ColorStateList mTextColorLink = null;
int mTextSize = -1;
+ LocaleList mTextLocales = null;
String mFontFamily = null;
Typeface mFontTypeface = null;
boolean mFontFamilyExplicit = false;
int mTypefaceIndex = -1;
- int mStyleIndex = -1;
+ int mTextStyle = 0;
int mFontWeight = -1;
boolean mAllCaps = false;
int mShadowColor = 0;
@@ -3543,11 +3544,12 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
+ " mTextColorHint:" + mTextColorHint + "\n"
+ " mTextColorLink:" + mTextColorLink + "\n"
+ " mTextSize:" + mTextSize + "\n"
+ + " mTextLocales:" + mTextLocales + "\n"
+ " mFontFamily:" + mFontFamily + "\n"
+ " mFontTypeface:" + mFontTypeface + "\n"
+ " mFontFamilyExplicit:" + mFontFamilyExplicit + "\n"
+ " mTypefaceIndex:" + mTypefaceIndex + "\n"
- + " mStyleIndex:" + mStyleIndex + "\n"
+ + " mTextStyle:" + mTextStyle + "\n"
+ " mFontWeight:" + mFontWeight + "\n"
+ " mAllCaps:" + mAllCaps + "\n"
+ " mShadowColor:" + mShadowColor + "\n"
@@ -3579,6 +3581,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
com.android.internal.R.styleable.TextAppearance_textColorLink);
sAppearanceValues.put(com.android.internal.R.styleable.TextView_textSize,
com.android.internal.R.styleable.TextAppearance_textSize);
+ sAppearanceValues.put(com.android.internal.R.styleable.TextView_textLocale,
+ com.android.internal.R.styleable.TextAppearance_textLocale);
sAppearanceValues.put(com.android.internal.R.styleable.TextView_typeface,
com.android.internal.R.styleable.TextAppearance_typeface);
sAppearanceValues.put(com.android.internal.R.styleable.TextView_fontFamily,
@@ -3652,6 +3656,15 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
attributes.mTextSize =
appearance.getDimensionPixelSize(attr, attributes.mTextSize);
break;
+ case com.android.internal.R.styleable.TextAppearance_textLocale:
+ final String localeString = appearance.getString(attr);
+ if (localeString != null) {
+ final LocaleList localeList = LocaleList.forLanguageTags(localeString);
+ if (!localeList.isEmpty()) {
+ attributes.mTextLocales = localeList;
+ }
+ }
+ break;
case com.android.internal.R.styleable.TextAppearance_typeface:
attributes.mTypefaceIndex = appearance.getInt(attr, attributes.mTypefaceIndex);
if (attributes.mTypefaceIndex != -1 && !attributes.mFontFamilyExplicit) {
@@ -3672,7 +3685,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);
@@ -3738,11 +3751,15 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
setRawTextSize(attributes.mTextSize, true /* shouldRequestLayout */);
}
+ if (attributes.mTextLocales != null) {
+ setTextLocales(attributes.mTextLocales);
+ }
+
if (attributes.mTypefaceIndex != -1 && !attributes.mFontFamilyExplicit) {
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/AssistUtils.java b/core/java/com/android/internal/app/AssistUtils.java
index 0f8295ac5868..7c371cb18878 100644
--- a/core/java/com/android/internal/app/AssistUtils.java
+++ b/core/java/com/android/internal/app/AssistUtils.java
@@ -31,6 +31,8 @@ import android.os.ServiceManager;
import android.provider.Settings;
import android.util.Log;
+import com.android.internal.R;
+
import java.util.ArrayList;
import java.util.Set;
@@ -42,6 +44,14 @@ public class AssistUtils {
private static final String TAG = "AssistUtils";
+ /**
+ * Sentinel value for "no default assistant specified."
+ *
+ * Empty string is already used to represent an explicit setting of No Assistant. null cannot
+ * be used because we can't represent a null value in XML.
+ */
+ private static final String UNSET = "#+UNSET";
+
private final Context mContext;
private final IVoiceInteractionManagerService mVoiceInteractionManagerService;
@@ -178,10 +188,21 @@ public class AssistUtils {
return ComponentName.unflattenFromString(setting);
}
+ final String defaultSetting = mContext.getResources().getString(
+ R.string.config_defaultAssistantComponentName);
+ if (defaultSetting != null && !defaultSetting.equals(UNSET)) {
+ return ComponentName.unflattenFromString(defaultSetting);
+ }
+
// Fallback to keep backward compatible behavior when there is no user setting.
if (activeServiceSupportsAssistGesture()) {
return getActiveServiceComponentName();
}
+
+ if (UNSET.equals(defaultSetting)) {
+ return null;
+ }
+
final SearchManager searchManager =
(SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE);
if (searchManager == null) {
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/KernelWakelockReader.java b/core/java/com/android/internal/os/KernelWakelockReader.java
index 46667d1ea688..2442d0b84bd6 100644
--- a/core/java/com/android/internal/os/KernelWakelockReader.java
+++ b/core/java/com/android/internal/os/KernelWakelockReader.java
@@ -158,7 +158,7 @@ public class KernelWakelockReader {
PROC_WAKELOCKS_FORMAT,
nameStringArray, wlData, null);
- name = nameStringArray[0];
+ name = nameStringArray[0].trim();
count = (int) wlData[1];
if (wakeup_sources) {
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/view/IInputMethodManager.aidl b/core/java/com/android/internal/view/IInputMethodManager.aidl
index dceacda5d4a3..34e850130b50 100644
--- a/core/java/com/android/internal/view/IInputMethodManager.aidl
+++ b/core/java/com/android/internal/view/IInputMethodManager.aidl
@@ -46,7 +46,6 @@ interface IInputMethodManager {
// Currently there is a bug that aidl doesn't accept List<Parcelable>
List getShortcutInputMethodsAndSubtypes();
- void finishInput(in IInputMethodClient client);
boolean showSoftInput(in IInputMethodClient client, int flags,
in ResultReceiver resultReceiver);
boolean hideSoftInput(in IInputMethodClient client, int flags,
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/java/com/google/android/collect/Lists.java b/core/java/com/google/android/collect/Lists.java
index c029bb20d24c..3ea873bbb0f9 100644
--- a/core/java/com/google/android/collect/Lists.java
+++ b/core/java/com/google/android/collect/Lists.java
@@ -16,6 +16,7 @@
package com.google.android.collect;
+import android.annotation.UnsupportedAppUsage;
import java.util.ArrayList;
import java.util.Collections;
@@ -33,6 +34,7 @@ public class Lists {
*
* @return a newly-created, initially-empty {@code ArrayList}
*/
+ @UnsupportedAppUsage
public static <E> ArrayList<E> newArrayList() {
return new ArrayList<E>();
}
diff --git a/core/java/com/google/android/collect/Maps.java b/core/java/com/google/android/collect/Maps.java
index fc2c9feb8068..6ba33207631a 100644
--- a/core/java/com/google/android/collect/Maps.java
+++ b/core/java/com/google/android/collect/Maps.java
@@ -16,6 +16,7 @@
package com.google.android.collect;
+import android.annotation.UnsupportedAppUsage;
import android.util.ArrayMap;
import java.util.HashMap;
@@ -29,6 +30,7 @@ public class Maps {
*
* @return a newly-created, initially-empty {@code HashMap}
*/
+ @UnsupportedAppUsage
public static <K, V> HashMap<K, V> newHashMap() {
return new HashMap<K, V>();
}
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index d34fdd95d543..b1384879621b 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -46,6 +46,7 @@ cc_library_shared {
"android_app_NativeActivity.cpp",
"android_app_admin_SecurityLog.cpp",
"android_opengl_EGL14.cpp",
+ "android_opengl_EGL15.cpp",
"android_opengl_EGLExt.cpp",
"android_opengl_GLES10.cpp",
"android_opengl_GLES10Ext.cpp",
@@ -85,8 +86,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",
@@ -162,6 +161,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",
@@ -241,6 +242,7 @@ cc_library_shared {
shared_libs: [
"libbpf",
+ "libnetdbpf",
"libnetdutils",
"libmemtrack",
"libandroidfw",
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index f09a231f7229..5863fd055edf 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -77,6 +77,7 @@ extern int register_android_graphics_YuvImage(JNIEnv* env);
extern int register_com_google_android_gles_jni_EGLImpl(JNIEnv* env);
extern int register_com_google_android_gles_jni_GLImpl(JNIEnv* env);
extern int register_android_opengl_jni_EGL14(JNIEnv* env);
+extern int register_android_opengl_jni_EGL15(JNIEnv* env);
extern int register_android_opengl_jni_EGLExt(JNIEnv* env);
extern int register_android_opengl_jni_GLES10(JNIEnv* env);
extern int register_android_opengl_jni_GLES10Ext(JNIEnv* env);
@@ -146,6 +147,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);
@@ -186,8 +189,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);
@@ -1339,8 +1340,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),
@@ -1372,6 +1371,7 @@ static const RegJNIRec gRegJNI[] = {
REG_JNI(register_com_google_android_gles_jni_EGLImpl),
REG_JNI(register_com_google_android_gles_jni_GLImpl),
REG_JNI(register_android_opengl_jni_EGL14),
+ REG_JNI(register_android_opengl_jni_EGL15),
REG_JNI(register_android_opengl_jni_EGLExt),
REG_JNI(register_android_opengl_jni_GLES10),
REG_JNI(register_android_opengl_jni_GLES10Ext),
@@ -1418,6 +1418,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/NinePatch.cpp b/core/jni/android/graphics/NinePatch.cpp
index 261910727db9..bb291e74ce0d 100644
--- a/core/jni/android/graphics/NinePatch.cpp
+++ b/core/jni/android/graphics/NinePatch.cpp
@@ -23,8 +23,6 @@
#include <hwui/Paint.h>
#include <utils/Log.h>
-#include <ResourceCache.h>
-
#include "SkCanvas.h"
#include "SkLatticeIter.h"
#include "SkRegion.h"
@@ -83,12 +81,7 @@ public:
static void finalize(JNIEnv* env, jobject, jlong patchHandle) {
int8_t* patch = reinterpret_cast<int8_t*>(patchHandle);
- if (android::uirenderer::ResourceCache::hasInstance()) {
- Res_png_9patch* p = (Res_png_9patch*) patch;
- android::uirenderer::ResourceCache::getInstance().destructor(p);
- } else {
- delete[] patch;
- }
+ delete[] patch;
}
static jlong getTransparentRegion(JNIEnv* env, jobject, jobject jbitmap,
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_opengl_EGL15.cpp b/core/jni/android_opengl_EGL15.cpp
new file mode 100644
index 000000000000..4a30babafa49
--- /dev/null
+++ b/core/jni/android_opengl_EGL15.cpp
@@ -0,0 +1,557 @@
+/*
+** 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.
+*/
+
+#pragma GCC diagnostic ignored "-Wunused-variable"
+#pragma GCC diagnostic ignored "-Wunused-function"
+
+#include "jni.h"
+#include <nativehelper/JNIHelp.h>
+#include <android_runtime/AndroidRuntime.h>
+#include <utils/misc.h>
+
+#include <assert.h>
+#include <EGL/egl.h>
+
+#include <ui/ANativeObjectBase.h>
+
+static int initialized = 0;
+
+// classes from EGL 1.4
+static jclass egldisplayClass;
+static jclass eglsurfaceClass;
+static jclass eglconfigClass;
+static jclass eglcontextClass;
+static jclass bufferClass;
+static jclass nioAccessClass;
+
+static jfieldID positionID;
+static jfieldID limitID;
+static jfieldID elementSizeShiftID;
+
+static jmethodID getBasePointerID;
+static jmethodID getBaseArrayID;
+static jmethodID getBaseArrayOffsetID;
+
+static jmethodID egldisplayGetHandleID;
+static jmethodID eglconfigGetHandleID;
+static jmethodID eglcontextGetHandleID;
+static jmethodID eglsurfaceGetHandleID;
+
+static jmethodID egldisplayConstructor;
+static jmethodID eglcontextConstructor;
+static jmethodID eglsurfaceConstructor;
+static jmethodID eglconfigConstructor;
+
+static jobject eglNoContextObject;
+static jobject eglNoDisplayObject;
+static jobject eglNoSurfaceObject;
+
+// classes from EGL 1.5
+static jclass eglimageClass;
+static jclass eglsyncClass;
+
+static jmethodID eglimageGetHandleID;
+static jmethodID eglsyncGetHandleID;
+
+static jmethodID eglimageConstructor;
+static jmethodID eglsyncConstructor;
+
+static jobject eglNoImageObject;
+static jobject eglNoSyncObject;
+
+/* Cache method IDs each time the class is loaded. */
+
+static void
+nativeClassInit(JNIEnv *_env, jclass glImplClass)
+{
+ // EGL 1.4 Init
+ jclass eglconfigClassLocal = _env->FindClass("android/opengl/EGLConfig");
+ eglconfigClass = (jclass) _env->NewGlobalRef(eglconfigClassLocal);
+ jclass eglcontextClassLocal = _env->FindClass("android/opengl/EGLContext");
+ eglcontextClass = (jclass) _env->NewGlobalRef(eglcontextClassLocal);
+ jclass egldisplayClassLocal = _env->FindClass("android/opengl/EGLDisplay");
+ egldisplayClass = (jclass) _env->NewGlobalRef(egldisplayClassLocal);
+ jclass eglsurfaceClassLocal = _env->FindClass("android/opengl/EGLSurface");
+ eglsurfaceClass = (jclass) _env->NewGlobalRef(eglsurfaceClassLocal);
+
+ eglconfigGetHandleID = _env->GetMethodID(eglconfigClass, "getNativeHandle", "()J");
+ eglcontextGetHandleID = _env->GetMethodID(eglcontextClass, "getNativeHandle", "()J");
+ egldisplayGetHandleID = _env->GetMethodID(egldisplayClass, "getNativeHandle", "()J");
+ eglsurfaceGetHandleID = _env->GetMethodID(eglsurfaceClass, "getNativeHandle", "()J");
+
+
+ eglconfigConstructor = _env->GetMethodID(eglconfigClass, "<init>", "(J)V");
+ eglcontextConstructor = _env->GetMethodID(eglcontextClass, "<init>", "(J)V");
+ egldisplayConstructor = _env->GetMethodID(egldisplayClass, "<init>", "(J)V");
+ eglsurfaceConstructor = _env->GetMethodID(eglsurfaceClass, "<init>", "(J)V");
+
+ jobject localeglNoContextObject = _env->NewObject(eglcontextClass, eglcontextConstructor, reinterpret_cast<jlong>(EGL_NO_CONTEXT));
+ eglNoContextObject = _env->NewGlobalRef(localeglNoContextObject);
+ jobject localeglNoDisplayObject = _env->NewObject(egldisplayClass, egldisplayConstructor, reinterpret_cast<jlong>(EGL_NO_DISPLAY));
+ eglNoDisplayObject = _env->NewGlobalRef(localeglNoDisplayObject);
+ jobject localeglNoSurfaceObject = _env->NewObject(eglsurfaceClass, eglsurfaceConstructor, reinterpret_cast<jlong>(EGL_NO_SURFACE));
+ eglNoSurfaceObject = _env->NewGlobalRef(localeglNoSurfaceObject);
+
+
+ jclass eglClass = _env->FindClass("android/opengl/EGL15");
+ jfieldID noContextFieldID = _env->GetStaticFieldID(eglClass, "EGL_NO_CONTEXT", "Landroid/opengl/EGLContext;");
+ _env->SetStaticObjectField(eglClass, noContextFieldID, eglNoContextObject);
+
+ jfieldID noDisplayFieldID = _env->GetStaticFieldID(eglClass, "EGL_NO_DISPLAY", "Landroid/opengl/EGLDisplay;");
+ _env->SetStaticObjectField(eglClass, noDisplayFieldID, eglNoDisplayObject);
+
+ jfieldID noSurfaceFieldID = _env->GetStaticFieldID(eglClass, "EGL_NO_SURFACE", "Landroid/opengl/EGLSurface;");
+ _env->SetStaticObjectField(eglClass, noSurfaceFieldID, eglNoSurfaceObject);
+
+ // EGL 1.5 init
+ jclass nioAccessClassLocal = _env->FindClass("java/nio/NIOAccess");
+ nioAccessClass = (jclass) _env->NewGlobalRef(nioAccessClassLocal);
+
+ jclass bufferClassLocal = _env->FindClass("java/nio/Buffer");
+ bufferClass = (jclass) _env->NewGlobalRef(bufferClassLocal);
+
+ getBasePointerID = _env->GetStaticMethodID(nioAccessClass,
+ "getBasePointer", "(Ljava/nio/Buffer;)J");
+ getBaseArrayID = _env->GetStaticMethodID(nioAccessClass,
+ "getBaseArray", "(Ljava/nio/Buffer;)Ljava/lang/Object;");
+ getBaseArrayOffsetID = _env->GetStaticMethodID(nioAccessClass,
+ "getBaseArrayOffset", "(Ljava/nio/Buffer;)I");
+
+ positionID = _env->GetFieldID(bufferClass, "position", "I");
+ limitID = _env->GetFieldID(bufferClass, "limit", "I");
+ elementSizeShiftID =
+ _env->GetFieldID(bufferClass, "_elementSizeShift", "I");
+
+ jclass eglimageClassLocal = _env->FindClass("android/opengl/EGLImage");
+ eglimageClass = (jclass) _env->NewGlobalRef(eglimageClassLocal);
+ jclass eglsyncClassLocal = _env->FindClass("android/opengl/EGLSync");
+ eglsyncClass = (jclass) _env->NewGlobalRef(eglsyncClassLocal);
+
+ eglimageGetHandleID = _env->GetMethodID(eglimageClass, "getNativeHandle", "()J");
+ eglsyncGetHandleID = _env->GetMethodID(eglsyncClass, "getNativeHandle", "()J");
+
+ eglimageConstructor = _env->GetMethodID(eglimageClass, "<init>", "(J)V");
+ eglsyncConstructor = _env->GetMethodID(eglsyncClass, "<init>", "(J)V");
+
+ jfieldID noImageFieldID = _env->GetStaticFieldID(eglClass, "EGL_NO_IMAGE", "Landroid/opengl/EGLImage;");
+ _env->SetStaticObjectField(eglClass, noImageFieldID, eglNoImageObject);
+
+ jfieldID noSyncFieldID = _env->GetStaticFieldID(eglClass, "EGL_NO_SYNC", "Landroid/opengl/EGLSync;");
+ _env->SetStaticObjectField(eglClass, noSyncFieldID, eglNoSyncObject);
+}
+
+static void *
+getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining, jint *offset)
+{
+ jint position;
+ jint limit;
+ jint elementSizeShift;
+ jlong pointer;
+
+ position = _env->GetIntField(buffer, positionID);
+ limit = _env->GetIntField(buffer, limitID);
+ elementSizeShift = _env->GetIntField(buffer, elementSizeShiftID);
+ *remaining = (limit - position) << elementSizeShift;
+ pointer = _env->CallStaticLongMethod(nioAccessClass,
+ getBasePointerID, buffer);
+ if (pointer != 0L) {
+ *array = NULL;
+ return reinterpret_cast<void*>(pointer);
+ }
+ eglimageGetHandleID = _env->GetMethodID(eglimageClass, "getNativeHandle", "()J");
+ eglsyncGetHandleID = _env->GetMethodID(eglsyncClass, "getNativeHandle", "()J");
+
+ *array = (jarray) _env->CallStaticObjectMethod(nioAccessClass,
+ getBaseArrayID, buffer);
+ *offset = _env->CallStaticIntMethod(nioAccessClass,
+ getBaseArrayOffsetID, buffer);
+
+ return NULL;
+}
+
+static void
+releasePointer(JNIEnv *_env, jarray array, void *data, jboolean commit)
+{
+ _env->ReleasePrimitiveArrayCritical(array, data,
+ commit ? 0 : JNI_ABORT);
+}
+
+static void *
+fromEGLHandle(JNIEnv *_env, jmethodID mid, jobject obj) {
+ if (obj == NULL){
+ jniThrowException(_env, "java/lang/IllegalArgumentException",
+ "Object is set to null.");
+ }
+
+ jlong handle = _env->CallLongMethod(obj, mid);
+ return reinterpret_cast<void*>(handle);
+}
+
+static jobject
+toEGLHandle(JNIEnv *_env, jclass cls, jmethodID con, void * handle) {
+ if (cls == eglimageClass &&
+ (EGLImage)handle == EGL_NO_IMAGE) {
+ return eglNoImageObject;
+ }
+
+ return _env->NewObject(cls, con, reinterpret_cast<jlong>(handle));
+}
+
+// --------------------------------------------------------------------------
+/* EGLSync eglCreateSync ( EGLDisplay dpy, EGLenum type, const EGLAttrib *attrib_list ) */
+static jobject
+android_eglCreateSync
+ (JNIEnv *_env, jobject _this, jobject dpy, jint type, jlongArray attrib_list_ref, jint offset) {
+ jint _exception = 0;
+ const char * _exceptionType = NULL;
+ const char * _exceptionMessage = NULL;
+ EGLSync _returnValue = (EGLSync) 0;
+ EGLDisplay dpy_native = (EGLDisplay) fromEGLHandle(_env, egldisplayGetHandleID, dpy);
+ EGLAttrib *attrib_list_base = (EGLAttrib *) 0;
+ jint _remaining;
+ EGLAttrib *attrib_list = (EGLAttrib *) 0;
+
+ if (!attrib_list_ref) {
+ _exception = 1;
+ _exceptionType = "java/lang/IllegalArgumentException";
+ _exceptionMessage = "attrib_list == null";
+ goto exit;
+ }
+ if (offset < 0) {
+ _exception = 1;
+ _exceptionType = "java/lang/IllegalArgumentException";
+ _exceptionMessage = "offset < 0";
+ goto exit;
+ }
+ _remaining = _env->GetArrayLength(attrib_list_ref) - offset;
+ attrib_list_base = (EGLAttrib *)
+ _env->GetLongArrayElements(attrib_list_ref, (jboolean *)0);
+ attrib_list = attrib_list_base + offset;
+
+ _returnValue = eglCreateSync(
+ (EGLDisplay)dpy_native,
+ (EGLenum)type,
+ (EGLAttrib *)attrib_list
+ );
+
+exit:
+ if (attrib_list_base) {
+ _env->ReleaseLongArrayElements(attrib_list_ref, (jlong*)attrib_list_base,
+ JNI_ABORT);
+ }
+ if (_exception) {
+ jniThrowException(_env, _exceptionType, _exceptionMessage);
+ }
+ return toEGLHandle(_env, eglsyncClass, eglsyncConstructor, _returnValue);
+}
+
+/* EGLBoolean eglDestroySync ( EGLDisplay dpy, EGLSync sync ) */
+static jboolean
+android_eglDestroySync
+ (JNIEnv *_env, jobject _this, jobject dpy, jobject sync) {
+ EGLBoolean _returnValue = (EGLBoolean) 0;
+ EGLDisplay dpy_native = (EGLDisplay) fromEGLHandle(_env, egldisplayGetHandleID, dpy);
+ EGLSync sync_native = (EGLSync) fromEGLHandle(_env, eglsyncGetHandleID, sync);
+
+ _returnValue = eglDestroySync(
+ (EGLDisplay)dpy_native,
+ (EGLSync)sync_native
+ );
+ return (jboolean)_returnValue;
+}
+
+/* EGLint eglClientWaitSync ( EGLDisplay dpy, EGLSync sync, EGLint flags, EGLTime timeout ) */
+static jint
+android_eglClientWaitSync
+ (JNIEnv *_env, jobject _this, jobject dpy, jobject sync, jint flags, jlong timeout) {
+ EGLint _returnValue = (EGLint) 0;
+ EGLDisplay dpy_native = (EGLDisplay) fromEGLHandle(_env, egldisplayGetHandleID, dpy);
+ EGLSync sync_native = (EGLSync) fromEGLHandle(_env, eglsyncGetHandleID, sync);
+
+ _returnValue = eglClientWaitSync(
+ (EGLDisplay)dpy_native,
+ (EGLSync)sync_native,
+ (EGLint)flags,
+ (EGLTime)timeout
+ );
+ return (jint)_returnValue;
+}
+
+/* EGLBoolean eglGetSyncAttrib ( EGLDisplay dpy, EGLSync sync, EGLint attribute, EGLAttrib *value ) */
+static jboolean
+android_eglGetSyncAttrib
+ (JNIEnv *_env, jobject _this, jobject dpy, jobject sync, jint attribute, jlongArray value_ref, jint offset) {
+ jint _exception = 0;
+ const char * _exceptionType = NULL;
+ const char * _exceptionMessage = NULL;
+ EGLBoolean _returnValue = (EGLBoolean) 0;
+ EGLDisplay dpy_native = (EGLDisplay) fromEGLHandle(_env, egldisplayGetHandleID, dpy);
+ EGLSync sync_native = (EGLSync) fromEGLHandle(_env, eglsyncGetHandleID, sync);
+ EGLAttrib *value_base = (EGLAttrib *) 0;
+ jint _remaining;
+ EGLAttrib *value = (EGLAttrib *) 0;
+
+ if (!value_ref) {
+ _exception = 1;
+ _exceptionType = "java/lang/IllegalArgumentException";
+ _exceptionMessage = "value == null";
+ goto exit;
+ }
+ if (offset < 0) {
+ _exception = 1;
+ _exceptionType = "java/lang/IllegalArgumentException";
+ _exceptionMessage = "offset < 0";
+ goto exit;
+ }
+ _remaining = _env->GetArrayLength(value_ref) - offset;
+ value_base = (EGLAttrib *)
+ _env->GetLongArrayElements(value_ref, (jboolean *)0);
+ value = value_base + offset;
+
+ _returnValue = eglGetSyncAttrib(
+ (EGLDisplay)dpy_native,
+ (EGLSync)sync_native,
+ (EGLint)attribute,
+ (EGLAttrib *)value
+ );
+
+exit:
+ if (value_base) {
+ _env->ReleaseLongArrayElements(value_ref, (jlong*)value_base,
+ _exception ? JNI_ABORT: 0);
+ }
+ if (_exception) {
+ jniThrowException(_env, _exceptionType, _exceptionMessage);
+ }
+ return (jboolean)_returnValue;
+}
+
+/* EGLDisplay eglGetPlatformDisplay ( EGLenum platform, EGLAttrib native_display, const EGLAttrib *attrib_list ) */
+static jobject
+android_eglGetPlatformDisplay
+ (JNIEnv *_env, jobject _this, jint platform, jlong native_display, jlongArray attrib_list_ref, jint offset) {
+ jint _exception = 0;
+ const char * _exceptionType = NULL;
+ const char * _exceptionMessage = NULL;
+ EGLDisplay _returnValue = (EGLDisplay) 0;
+ EGLAttrib *attrib_list_base = (EGLAttrib *) 0;
+ jint _remaining;
+ EGLAttrib *attrib_list = (EGLAttrib *) 0;
+
+ if (!attrib_list_ref) {
+ _exception = 1;
+ _exceptionType = "java/lang/IllegalArgumentException";
+ _exceptionMessage = "attrib_list == null";
+ goto exit;
+ }
+ if (offset < 0) {
+ _exception = 1;
+ _exceptionType = "java/lang/IllegalArgumentException";
+ _exceptionMessage = "offset < 0";
+ goto exit;
+ }
+ _remaining = _env->GetArrayLength(attrib_list_ref) - offset;
+ attrib_list_base = (EGLAttrib *)
+ _env->GetLongArrayElements(attrib_list_ref, (jboolean *)0);
+ attrib_list = attrib_list_base + offset;
+
+ _returnValue = eglGetPlatformDisplay(
+ (EGLenum)platform,
+ (void *)native_display,
+ (EGLAttrib *)attrib_list
+ );
+
+exit:
+ if (attrib_list_base) {
+ _env->ReleaseLongArrayElements(attrib_list_ref, (jlong*)attrib_list_base,
+ JNI_ABORT);
+ }
+ if (_exception) {
+ jniThrowException(_env, _exceptionType, _exceptionMessage);
+ }
+ return toEGLHandle(_env, egldisplayClass, egldisplayConstructor, _returnValue);
+}
+
+/* EGLSurface eglCreatePlatformWindowSurface ( EGLDisplay dpy, EGLConfig config, void *native_window, const EGLAttrib *attrib_list ) */
+static jobject
+android_eglCreatePlatformWindowSurface
+ (JNIEnv *_env, jobject _this, jobject dpy, jobject config, jobject native_window_buf, jlongArray attrib_list_ref, jint offset) {
+ jint _exception = 0;
+ const char * _exceptionType = NULL;
+ const char * _exceptionMessage = NULL;
+ jarray _array = (jarray) 0;
+ jint _bufferOffset = (jint) 0;
+ EGLSurface _returnValue = (EGLSurface) 0;
+ EGLDisplay dpy_native = (EGLDisplay) fromEGLHandle(_env, egldisplayGetHandleID, dpy);
+ EGLConfig config_native = (EGLConfig) fromEGLHandle(_env, eglconfigGetHandleID, config);
+ jint _native_windowRemaining;
+ void *native_window = (void *) 0;
+ EGLAttrib *attrib_list_base = (EGLAttrib *) 0;
+ jint _attrib_listRemaining;
+ EGLAttrib *attrib_list = (EGLAttrib *) 0;
+
+ if (!native_window_buf) {
+ _exception = 1;
+ _exceptionType = "java/lang/IllegalArgumentException";
+ _exceptionMessage = "native_window == null";
+ goto exit;
+ }
+ native_window = (void *)getPointer(_env, native_window_buf, (jarray*)&_array, &_native_windowRemaining, &_bufferOffset);
+ if (!attrib_list_ref) {
+ _exception = 1;
+ _exceptionType = "java/lang/IllegalArgumentException";
+ _exceptionMessage = "attrib_list == null";
+ goto exit;
+ }
+ if (offset < 0) {
+ _exception = 1;
+ _exceptionType = "java/lang/IllegalArgumentException";
+ _exceptionMessage = "offset < 0";
+ goto exit;
+ }
+ _attrib_listRemaining = _env->GetArrayLength(attrib_list_ref) - offset;
+ attrib_list_base = (EGLAttrib *)
+ _env->GetLongArrayElements(attrib_list_ref, (jboolean *)0);
+ attrib_list = attrib_list_base + offset;
+
+ if (native_window == NULL) {
+ char * _native_windowBase = (char *)_env->GetPrimitiveArrayCritical(_array, (jboolean *) 0);
+ native_window = (void *) (_native_windowBase + _bufferOffset);
+ }
+ _returnValue = eglCreatePlatformWindowSurface(
+ (EGLDisplay)dpy_native,
+ (EGLConfig)config_native,
+ (void *)native_window,
+ (EGLAttrib *)attrib_list
+ );
+
+exit:
+ if (attrib_list_base) {
+ _env->ReleaseLongArrayElements(attrib_list_ref, (jlong*)attrib_list_base,
+ JNI_ABORT);
+ }
+ if (_array) {
+ releasePointer(_env, _array, native_window, _exception ? JNI_FALSE : JNI_TRUE);
+ }
+ if (_exception) {
+ jniThrowException(_env, _exceptionType, _exceptionMessage);
+ }
+ return toEGLHandle(_env, eglsurfaceClass, eglsurfaceConstructor, _returnValue);
+}
+
+/* EGLSurface eglCreatePlatformPixmapSurface ( EGLDisplay dpy, EGLConfig config, void *native_pixmap, const EGLAttrib *attrib_list ) */
+static jobject
+android_eglCreatePlatformPixmapSurface
+ (JNIEnv *_env, jobject _this, jobject dpy, jobject config, jobject native_pixmap_buf, jlongArray attrib_list_ref, jint offset) {
+ jint _exception = 0;
+ const char * _exceptionType = NULL;
+ const char * _exceptionMessage = NULL;
+ jarray _array = (jarray) 0;
+ jint _bufferOffset = (jint) 0;
+ EGLSurface _returnValue = (EGLSurface) 0;
+ EGLDisplay dpy_native = (EGLDisplay) fromEGLHandle(_env, egldisplayGetHandleID, dpy);
+ EGLConfig config_native = (EGLConfig) fromEGLHandle(_env, eglconfigGetHandleID, config);
+ jint _native_pixmapRemaining;
+ void *native_pixmap = (void *) 0;
+ EGLAttrib *attrib_list_base = (EGLAttrib *) 0;
+ jint _attrib_listRemaining;
+ EGLAttrib *attrib_list = (EGLAttrib *) 0;
+
+ if (!native_pixmap_buf) {
+ _exception = 1;
+ _exceptionType = "java/lang/IllegalArgumentException";
+ _exceptionMessage = "native_pixmap == null";
+ goto exit;
+ }
+ native_pixmap = (void *)getPointer(_env, native_pixmap_buf, (jarray*)&_array, &_native_pixmapRemaining, &_bufferOffset);
+ if (!attrib_list_ref) {
+ _exception = 1;
+ _exceptionType = "java/lang/IllegalArgumentException";
+ _exceptionMessage = "attrib_list == null";
+ goto exit;
+ }
+ if (offset < 0) {
+ _exception = 1;
+ _exceptionType = "java/lang/IllegalArgumentException";
+ _exceptionMessage = "offset < 0";
+ goto exit;
+ }
+ _attrib_listRemaining = _env->GetArrayLength(attrib_list_ref) - offset;
+ attrib_list_base = (EGLAttrib *)
+ _env->GetLongArrayElements(attrib_list_ref, (jboolean *)0);
+ attrib_list = attrib_list_base + offset;
+
+ if (native_pixmap == NULL) {
+ char * _native_pixmapBase = (char *)_env->GetPrimitiveArrayCritical(_array, (jboolean *) 0);
+ native_pixmap = (void *) (_native_pixmapBase + _bufferOffset);
+ }
+ _returnValue = eglCreatePlatformPixmapSurface(
+ (EGLDisplay)dpy_native,
+ (EGLConfig)config_native,
+ (void *)native_pixmap,
+ (EGLAttrib *)attrib_list
+ );
+
+exit:
+ if (attrib_list_base) {
+ _env->ReleaseLongArrayElements(attrib_list_ref, (jlong*)attrib_list_base,
+ JNI_ABORT);
+ }
+ if (_array) {
+ releasePointer(_env, _array, native_pixmap, _exception ? JNI_FALSE : JNI_TRUE);
+ }
+ if (_exception) {
+ jniThrowException(_env, _exceptionType, _exceptionMessage);
+ }
+ return toEGLHandle(_env, eglsurfaceClass, eglsurfaceConstructor, _returnValue);
+}
+
+/* EGLBoolean eglWaitSync ( EGLDisplay dpy, EGLSync sync, EGLint flags ) */
+static jboolean
+android_eglWaitSync
+ (JNIEnv *_env, jobject _this, jobject dpy, jobject sync, jint flags) {
+ EGLBoolean _returnValue = (EGLBoolean) 0;
+ EGLDisplay dpy_native = (EGLDisplay) fromEGLHandle(_env, egldisplayGetHandleID, dpy);
+ EGLSync sync_native = (EGLSync) fromEGLHandle(_env, eglsyncGetHandleID, sync);
+
+ _returnValue = eglWaitSync(
+ (EGLDisplay)dpy_native,
+ (EGLSync)sync_native,
+ (EGLint)flags
+ );
+ return (jboolean)_returnValue;
+}
+
+static const char *classPathName = "android/opengl/EGL15";
+
+static const JNINativeMethod methods[] = {
+{"_nativeClassInit", "()V", (void*)nativeClassInit },
+{"eglCreateSync", "(Landroid/opengl/EGLDisplay;I[JI)Landroid/opengl/EGLSync;", (void *) android_eglCreateSync },
+{"eglDestroySync", "(Landroid/opengl/EGLDisplay;Landroid/opengl/EGLSync;)Z", (void *) android_eglDestroySync },
+{"eglClientWaitSync", "(Landroid/opengl/EGLDisplay;Landroid/opengl/EGLSync;IJ)I", (void *) android_eglClientWaitSync },
+{"eglGetSyncAttrib", "(Landroid/opengl/EGLDisplay;Landroid/opengl/EGLSync;I[JI)Z", (void *) android_eglGetSyncAttrib },
+{"eglGetPlatformDisplay", "(IJ[JI)Landroid/opengl/EGLDisplay;", (void *) android_eglGetPlatformDisplay },
+{"eglCreatePlatformWindowSurface", "(Landroid/opengl/EGLDisplay;Landroid/opengl/EGLConfig;Ljava/nio/Buffer;[JI)Landroid/opengl/EGLSurface;", (void *) android_eglCreatePlatformWindowSurface },
+{"eglCreatePlatformPixmapSurface", "(Landroid/opengl/EGLDisplay;Landroid/opengl/EGLConfig;Ljava/nio/Buffer;[JI)Landroid/opengl/EGLSurface;", (void *) android_eglCreatePlatformPixmapSurface },
+{"eglWaitSync", "(Landroid/opengl/EGLDisplay;Landroid/opengl/EGLSync;I)Z", (void *) android_eglWaitSync },
+};
+
+int register_android_opengl_jni_EGL15(JNIEnv *_env)
+{
+ int err;
+ err = android::AndroidRuntime::registerNativeMethods(_env, classPathName, methods, NELEM(methods));
+ return err;
+}
diff --git a/core/jni/android_os_GraphicsEnvironment.cpp b/core/jni/android_os_GraphicsEnvironment.cpp
index b70485d9a0ea..e64da5ca0b24 100644
--- a/core/jni/android_os_GraphicsEnvironment.cpp
+++ b/core/jni/android_os_GraphicsEnvironment.cpp
@@ -23,17 +23,25 @@
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());
}
-void setAngleInfo_native(JNIEnv* env, jobject clazz, jstring path, jstring appName, jstring appPref, jboolean devOptIn) {
+void setAngleInfo_native(JNIEnv* env, jobject clazz, jstring path, jstring appName, jstring appPref, jboolean devOptIn,
+ jobject rulesFd, jlong rulesOffset, jlong rulesLength) {
ScopedUtfChars pathChars(env, path);
ScopedUtfChars appNameChars(env, appName);
ScopedUtfChars appPrefChars(env, appPref);
+
+ int rulesFd_native = jniGetFDFromFileDescriptor(env, rulesFd);
+
android::GraphicsEnv::getInstance().setAngleInfo(pathChars.c_str(), appNameChars.c_str(),
- appPrefChars.c_str(), devOptIn);
+ appPrefChars.c_str(), devOptIn, rulesFd_native, rulesOffset, rulesLength);
}
void setLayerPaths_native(JNIEnv* env, jobject clazz, jobject classLoader, jstring layerPaths) {
@@ -51,8 +59,9 @@ 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) },
+ { "setAngleInfo", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ZLjava/io/FileDescriptor;JJ)V", reinterpret_cast<void*>(setAngleInfo_native) },
{ "setLayerPaths", "(Ljava/lang/ClassLoader;Ljava/lang/String;)V", reinterpret_cast<void*>(setLayerPaths_native) },
{ "setDebugLayers", "(Ljava/lang/String;)V", reinterpret_cast<void*>(setDebugLayers_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/com_android_internal_net_NetworkStatsFactory.cpp b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp
index 109e65c4a1d0..b3ff4dbf8bef 100644
--- a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp
+++ b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp
@@ -32,8 +32,8 @@
#include <utils/misc.h>
#include "android-base/unique_fd.h"
-#include "bpf/BpfNetworkStats.h"
#include "bpf/BpfUtils.h"
+#include "netdbpf/BpfNetworkStats.h"
using android::bpf::hasBpfSupport;
using android::bpf::parseBpfNetworkStatsDetail;
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/os/system_properties.proto b/core/proto/android/os/system_properties.proto
index a41edf30f913..1f63be93fb94 100644
--- a/core/proto/android/os/system_properties.proto
+++ b/core/proto/android/os/system_properties.proto
@@ -512,7 +512,9 @@ message SystemPropertiesProto {
optional int32 vts_coverage = 43;
optional string zygote = 44;
- // Next Tag: 45
+ optional string gfx_driver_whitelist_0 = 45;
+
+ // Next Tag: 46
}
optional Ro ro = 21;
diff --git a/core/proto/android/providers/settings/global.proto b/core/proto/android/providers/settings/global.proto
index 56f0f53b6741..444c737c7636 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 3cca62d6dcf5..626285b4b865 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -139,7 +139,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" />
@@ -1182,6 +1181,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 -->
<!-- ====================================================================== -->
@@ -1582,6 +1603,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"
@@ -2784,7 +2806,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/attrs.xml b/core/res/res/values/attrs.xml
index cdb65edd81e7..9bedab53bb2c 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -4551,6 +4551,11 @@
<attr name="typeface" />
<!-- Font family (named by string or as a font resource reference) for the text. -->
<attr name="fontFamily" />
+ <!-- Specifies the {@link android.os.LocaleList} for the text.
+ May be a string value, which is a comma-separated language tag list, such as "ja-JP,zh-CN".
+ When not specified or an empty string is given, it will fallback to the default one.
+ {@see android.os.LocaleList#forLanguageTags(String)} -->
+ <attr name="textLocale" format="string" />
<!-- Color of the text selection highlight. -->
<attr name="textColorHighlight" />
<!-- Color of the hint text. -->
@@ -4642,6 +4647,13 @@
<attr name="textFontWeight" />
<!-- Font family (named by string or as a font resource reference) for the text. -->
<attr name="fontFamily" />
+ <!-- Specifies the {@link android.os.LocaleList} for the text in this TextView.
+ If not given, the system default will be used.
+ May be a string value, which is a comma-separated language tag list, such as "ja-JP,zh-CN".
+ When not specified or an empty string is given, it will fallback to the default one.
+ {@see android.os.LocaleList#forLanguageTags(String)}
+ {@see android.text.TextView#setTextLocales(android.os.LocaleList)} -->
+ <attr name="textLocale" format="string" />
<!-- Text color for links. -->
<attr name="textColorLink" />
<!-- Makes the cursor visible (the default) or invisible. -->
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 866b68d9ffd7..7a5d30aebe95 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -378,8 +378,8 @@
Values must be from NetworkCapabilities#NET_CAPABILITIES_* constants.
[IP config] Optional. If empty or not specified - DHCP will be used, otherwise
use the following format to specify static IP configuration:
- ip=<ip-address/mask> gateway=<ip-address> dns=<comma-sep-ip-addresses>
- domains=<comma-sep-domains>
+ ip=<ip-address/mask> gateway=<ip-address> dns=<comma-sep-ip-addresses>
+ domains=<comma-sep-domains>
-->
<string-array translatable="false" name="config_ethernet_interfaces">
<!--
@@ -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>
@@ -2116,8 +2120,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>
@@ -3373,22 +3377,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>
@@ -3493,7 +3497,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>
@@ -3568,8 +3572,12 @@
<!-- Whether or not the "SMS app service" feature is enabled -->
<bool name="config_useSmsAppService">true</bool>
-
+
<!-- List of names that represent dual SoftAp interfaces. -->
<string-array translatable="false" name="config_wifi_dual_sap_interfaces">
</string-array>
+
+ <!-- Component name for default assistant on this device -->
+ <string name="config_defaultAssistantComponentName">#+UNSET</string>
+
</resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 2e42e4ac27f3..31212a6ab28f 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2915,6 +2915,7 @@
<public name="minimumUiTimeout" />
<public name="isLightTheme" />
<public name="isSplitRequired" />
+ <public name="textLocale" />
</public-group>
<public-group type="drawable" first-id="0x010800b4">
@@ -2930,17 +2931,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 +2951,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 6bf893d94ce5..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. -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index af8c03293d94..346837fc1bd7 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" />
@@ -3272,17 +3275,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" />
@@ -3488,4 +3491,6 @@
<java-symbol type="fraction" name="config_prescaleAbsoluteVolume_index3" />
<java-symbol type="bool" name="config_useSmsAppService" />
+
+ <java-symbol type="string" name="config_defaultAssistantComponentName" />
</resources>
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/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/content/ContentResolverTest.java b/core/tests/coretests/src/android/content/ContentResolverTest.java
index 6256d08adb00..0036186994fe 100644
--- a/core/tests/coretests/src/android/content/ContentResolverTest.java
+++ b/core/tests/coretests/src/android/content/ContentResolverTest.java
@@ -13,31 +13,149 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package android.content;
-import android.content.ContentResolver;
-import android.provider.ContactsContract;
-import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.test.suitebuilder.annotation.Suppress;
-
-@Suppress // Failing.
-public class ContentResolverTest extends AndroidTestCase {
- private ContentResolver mContentResolver;
-
- @Override
- protected void setUp() throws Exception {
- super.setUp();
- mContentResolver = mContext.getContentResolver();
- }
-
- @LargeTest
- public void testCursorFinalizer() throws Exception {
- // TODO: Want a test case that more predictably reproduce this issue. Selected
- // 600 as this causes the problem 100% of the runs on current hw, it might not
- // do so on some other configuration though.
- for (int i = 0; i < 600; i++) {
- mContentResolver.query(ContactsContract.Contacts.CONTENT_URI, null, null, null, null);
- }
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.content.res.AssetFileDescriptor;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.ImageDecoder;
+import android.graphics.Paint;
+import android.net.Uri;
+import android.os.MemoryFile;
+import android.os.ParcelFileDescriptor;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+import android.util.Size;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class ContentResolverTest {
+
+ private ContentResolver mResolver;
+ private IContentProvider mProvider;
+ private ContentProviderClient mClient;
+
+ private int mSize = 256_000;
+ private MemoryFile mImage;
+
+ @Before
+ public void setUp() throws Exception {
+ mResolver = InstrumentationRegistry.getInstrumentation().getTargetContext()
+ .getContentResolver();
+ mProvider = mock(IContentProvider.class);
+ mClient = new ContentProviderClient(mResolver, mProvider, false);
+
+ mImage = new MemoryFile("temp.png", mSize);
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ mImage.close();
+ mImage = null;
+ }
+
+ private void initImage(int width, int height) throws Exception {
+ final Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
+ final Canvas canvas = new Canvas(bitmap);
+
+ canvas.drawColor(Color.RED);
+
+ final Paint paint = new Paint();
+ paint.setColor(Color.BLUE);
+ paint.setStyle(Paint.Style.FILL);
+ canvas.drawRect(0, 0, width / 2, height / 2, paint);
+
+ bitmap.compress(Bitmap.CompressFormat.PNG, 90, mImage.getOutputStream());
+
+ final AssetFileDescriptor afd = new AssetFileDescriptor(
+ new ParcelFileDescriptor(mImage.getFileDescriptor()), 0, mSize, null);
+ when(mProvider.openTypedAssetFile(any(), any(), any(), any(), any())).thenReturn(afd);
+ }
+
+ private static void assertImageAspectAndContents(Bitmap bitmap) {
+ // And correct aspect ratio
+ final int before = (100 * 1280) / 960;
+ final int after = (100 * bitmap.getWidth()) / bitmap.getHeight();
+ assertEquals(before, after);
+
+ // And scaled correctly
+ final int halfX = bitmap.getWidth() / 2;
+ final int halfY = bitmap.getHeight() / 2;
+ assertEquals(Color.BLUE, bitmap.getPixel(halfX - 10, halfY - 10));
+ assertEquals(Color.RED, bitmap.getPixel(halfX + 10, halfY - 10));
+ assertEquals(Color.RED, bitmap.getPixel(halfX - 10, halfY + 10));
+ assertEquals(Color.RED, bitmap.getPixel(halfX + 10, halfY + 10));
+ }
+
+ @Test
+ public void testLoadThumbnail_Normal() throws Exception {
+ initImage(1280, 960);
+
+ Bitmap res = ContentResolver.loadThumbnail(mClient,
+ Uri.parse("content://com.example/"), new Size(1280, 960), null,
+ ImageDecoder.ALLOCATOR_SOFTWARE);
+
+ // Size should be untouched
+ assertEquals(1280, res.getWidth());
+ assertEquals(960, res.getHeight());
+
+ assertImageAspectAndContents(res);
+ }
+
+ @Test
+ public void testLoadThumbnail_Scaling() throws Exception {
+ initImage(1280, 960);
+
+ Bitmap res = ContentResolver.loadThumbnail(mClient,
+ Uri.parse("content://com.example/"), new Size(320, 240), null,
+ ImageDecoder.ALLOCATOR_SOFTWARE);
+
+ // Size should be much smaller
+ assertTrue(res.getWidth() <= 640);
+ assertTrue(res.getHeight() <= 480);
+
+ assertImageAspectAndContents(res);
+ }
+
+ @Test
+ public void testLoadThumbnail_Aspect() throws Exception {
+ initImage(1280, 960);
+
+ Bitmap res = ContentResolver.loadThumbnail(mClient,
+ Uri.parse("content://com.example/"), new Size(240, 320), null,
+ ImageDecoder.ALLOCATOR_SOFTWARE);
+
+ // Size should be much smaller
+ assertTrue(res.getWidth() <= 640);
+ assertTrue(res.getHeight() <= 480);
+
+ assertImageAspectAndContents(res);
+ }
+
+ @Test
+ public void testLoadThumbnail_Tiny() throws Exception {
+ initImage(32, 24);
+
+ Bitmap res = ContentResolver.loadThumbnail(mClient,
+ Uri.parse("content://com.example/"), new Size(320, 240), null,
+ ImageDecoder.ALLOCATOR_SOFTWARE);
+
+ // Size should be untouched
+ assertEquals(32, res.getWidth());
+ assertEquals(24, res.getHeight());
+
+ assertImageAspectAndContents(res);
}
}
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..6966448f7d63 100644
--- a/core/tests/coretests/src/android/os/FileUtilsTest.java
+++ b/core/tests/coretests/src/android/os/FileUtilsTest.java
@@ -41,6 +41,7 @@ import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
import android.content.Context;
import android.os.FileUtils.MemoryPipe;
@@ -48,7 +49,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 +95,7 @@ public class FileUtilsTest {
@After
public void tearDown() throws Exception {
- IoUtils.deleteContents(mDir);
+ FileUtils.deleteContents(mDir);
FileUtils.deleteContents(mTarget);
}
@@ -511,6 +511,20 @@ public class FileUtilsTest {
MODE_WRITE_ONLY | MODE_CREATE | MODE_APPEND);
}
+ @Test
+ public void testTranslateMode_Invalid() throws Exception {
+ try {
+ translateModeStringToPosix("rwx");
+ fail();
+ } catch (IllegalArgumentException expected) {
+ }
+ try {
+ translateModeStringToPosix("");
+ fail();
+ } catch (IllegalArgumentException expected) {
+ }
+ }
+
private static void assertTranslate(String string, int posix, int pfd) {
assertEquals(posix, translateModeStringToPosix(string));
assertEquals(string, translateModePosixToString(posix));
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index 60abd9468179..9778acba8213 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -368,6 +368,8 @@ public class SettingsBackupTest {
Settings.Global.PRIV_APP_OOB_ENABLED,
Settings.Global.PRIV_APP_OOB_LIST,
Settings.Global.PRIVATE_DNS_DEFAULT_MODE,
+ Settings.Global.PRIVILEGED_DEVICE_IDENTIFIER_CHECK_ENABLED,
+ Settings.Global.PRIVILEGED_DEVICE_IDENTIFIER_TARGET_Q_BEHAVIOR_ENABLED,
Settings.Global.PROVISIONING_APN_ALARM_DELAY_IN_MS,
Settings.Global.RADIO_BLUETOOTH,
Settings.Global.RADIO_CELL,
@@ -450,6 +452,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,
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/text/method/ForwardDeleteTest.java b/core/tests/coretests/src/android/text/method/ForwardDeleteTest.java
index c98e6460c189..7360e9f7d6f6 100644
--- a/core/tests/coretests/src/android/text/method/ForwardDeleteTest.java
+++ b/core/tests/coretests/src/android/text/method/ForwardDeleteTest.java
@@ -20,7 +20,6 @@ import android.platform.test.annotations.Presubmit;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
-import android.test.suitebuilder.annotation.Suppress;
import android.text.InputType;
import android.util.KeyUtils;
import android.view.KeyEvent;
@@ -239,7 +238,6 @@ public class ForwardDeleteTest {
}
@Test
- @Suppress
public void testEmojiModifier() {
EditorState state = new EditorState();
@@ -256,20 +254,15 @@ public class ForwardDeleteTest {
// Isolated multiple emoji modifier
state.setByString("| U+1F3FB U+1F3FB");
forwardDelete(state, 0);
- state.assertEquals("| U+1F3FB");
- forwardDelete(state, 0);
state.assertEquals("|");
// Multiple emoji modifiers
state.setByString("| U+1F466 U+1F3FB U+1F3FB");
forwardDelete(state, 0);
- state.assertEquals("| U+1F3FB");
- forwardDelete(state, 0);
state.assertEquals("|");
}
@Test
- @Suppress
public void testMixedEdgeCases() {
EditorState state = new EditorState();
@@ -318,7 +311,7 @@ public class ForwardDeleteTest {
// COMBINING ENCLOSING KEYCAP + emoji modifier
state.setByString("| '1' U+20E3 U+1F3FB");
forwardDelete(state, 0);
- state.assertEquals("| U+1F3FB");
+ state.assertEquals("|");
// Emoji modifier + COMBINING ENCLOSING KEYCAP
state.setByString("| U+1F466 U+1F3FB U+20E3");
@@ -360,7 +353,7 @@ public class ForwardDeleteTest {
// Variation selector + emoji modifier
state.setByString("| U+2665 U+FE0F U+1F3FB");
forwardDelete(state, 0);
- state.assertEquals("| U+1F3FB");
+ state.assertEquals("|");
// Emoji modifier + variation selector
state.setByString("| U+1F466 U+1F3FB U+FE0F");
@@ -396,7 +389,7 @@ public class ForwardDeleteTest {
// Start with ZERO WIDTH JOINER + emoji modifier
state.setByString("| U+200D U+1F3FB");
forwardDelete(state, 0);
- state.assertEquals("| U+1F3FB");
+ state.assertEquals("|");
// ZERO WIDTH JOINER + emoji modifier
state.setByString("| U+1F469 U+200D U+1F3FB");
@@ -418,8 +411,6 @@ public class ForwardDeleteTest {
// Regional indicator symbol + emoji modifier
state.setByString("| U+1F1FA U+1F3FB");
forwardDelete(state, 0);
- state.assertEquals("| U+1F3FB");
- forwardDelete(state, 0);
state.assertEquals("|");
// Emoji modifier + regional indicator symbol
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/MotionEventTest.java b/core/tests/coretests/src/android/view/MotionEventTest.java
index 1a480c77ada0..023526f7e37f 100644
--- a/core/tests/coretests/src/android/view/MotionEventTest.java
+++ b/core/tests/coretests/src/android/view/MotionEventTest.java
@@ -54,6 +54,13 @@ public class MotionEventTest {
MotionEvent motionEvent = MotionEvent.obtain(0, 0, ACTION_DOWN,
pointerCount, properties, coords,
0, 0, 0, 0, 0, 0, InputDevice.SOURCE_TOUCHSCREEN, displayId, 0);
+
+ MotionEvent motionEvent_Single = MotionEvent.obtain(0 /* downTime */, 0 /* eventTime */,
+ ACTION_DOWN /* action */, 0f /* x */, 0f /* y */, 0/* pressure */, 0 /* size */,
+ 0 /* metaState */, 0 /* xPrecision */, 0 /* yPrecision */,
+ 0 /* deviceId */, 0 /* edgeFlags */, InputDevice.SOURCE_TOUCHSCREEN, displayId);
+
+ assertEquals(displayId, motionEvent_Single.getDisplayId());
assertEquals(displayId, motionEvent.getDisplayId());
displayId = 5;
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/android/view/textclassifier/TextLanguageTest.java b/core/tests/coretests/src/android/view/textclassifier/TextLanguageTest.java
new file mode 100644
index 000000000000..75ca769294ce
--- /dev/null
+++ b/core/tests/coretests/src/android/view/textclassifier/TextLanguageTest.java
@@ -0,0 +1,85 @@
+/*
+ * 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.view.textclassifier;
+
+import static org.junit.Assert.assertEquals;
+
+import android.icu.util.ULocale;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Tests for TextLanguage.
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public final class TextLanguageTest {
+
+ private static final float EPSILON = 0.000001f;
+
+ @Test
+ public void testParcel() throws Exception {
+ final String bundleKey = "experiment.int";
+ final Bundle bundle = new Bundle();
+ bundle.putInt(bundleKey, 1234);
+
+ final TextLanguage reference = new TextLanguage.Builder()
+ .setId("id")
+ .setExtras(bundle)
+ .putLocale(ULocale.ENGLISH, 0.8f)
+ .putLocale(ULocale.GERMAN, 0.2f)
+ .build();
+
+ final Parcel parcel = Parcel.obtain();
+ reference.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+ final TextLanguage result = TextLanguage.CREATOR.createFromParcel(parcel);
+
+ assertEquals("id", result.getId());
+ assertEquals(1234, result.getExtras().getInt(bundleKey));
+ assertEquals(2, result.getLocaleHypothesisCount());
+ assertEquals(ULocale.ENGLISH, result.getLocale(0));
+ assertEquals(0.8f, result.getConfidenceScore(ULocale.ENGLISH), EPSILON);
+ assertEquals(ULocale.GERMAN, result.getLocale(1));
+ assertEquals(0.2f, result.getConfidenceScore(ULocale.GERMAN), EPSILON);
+ }
+
+ @Test
+ public void testRequestParcel() throws Exception {
+ final String text = "This is random text";
+ final String bundleKey = "experiment.str";
+ final Bundle bundle = new Bundle();
+ bundle.putString(bundleKey, "bundle");
+
+ final TextLanguage.Request reference = new TextLanguage.Request.Builder(text)
+ .setExtras(bundle)
+ .build();
+
+ final Parcel parcel = Parcel.obtain();
+ reference.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+ final TextLanguage.Request result = TextLanguage.Request.CREATOR.createFromParcel(parcel);
+
+ assertEquals(text, result.getText());
+ assertEquals("bundle", result.getExtras().getString(bundleKey));
+ }
+}
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/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index ac1fbdd90bdd..44f8737da2c1 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -218,7 +218,6 @@ applications that come with the platform
<permission name="android.permission.ACCESS_MTP"/>
<permission name="android.permission.INTERACT_ACROSS_USERS"/>
<permission name="android.permission.MANAGE_USERS"/>
- <permission name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
<permission name="android.permission.USE_RESERVED_DISK"/>
<permission name="android.permission.WRITE_MEDIA_STORAGE"/>
</privapp-permissions>
@@ -326,6 +325,7 @@ applications that come with the platform
<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/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/Point.java b/graphics/java/android/graphics/Point.java
index f291e2702948..ea9350174f97 100644
--- a/graphics/java/android/graphics/Point.java
+++ b/graphics/java/android/graphics/Point.java
@@ -19,6 +19,7 @@ package android.graphics;
import android.annotation.NonNull;
import android.os.Parcel;
import android.os.Parcelable;
+import android.util.Size;
import android.util.proto.ProtoOutputStream;
import java.io.PrintWriter;
@@ -168,4 +169,14 @@ public class Point implements Parcelable {
x = in.readInt();
y = in.readInt();
}
+
+ /** {@hide} */
+ public static @NonNull Point convert(@NonNull Size size) {
+ return new Point(size.getWidth(), size.getHeight());
+ }
+
+ /** {@hide} */
+ public static @NonNull Size convert(@NonNull Point point) {
+ return new Size(point.x, point.y);
+ }
}
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..16479095a63a 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,60 @@ 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();
+ * Paint bigPaint = new Paint();
+ * bigPaint.setTextSize(paint.getTextSize() * 2.0);
+ * String text = "Hello, Android.";
+ *
+ * // Prepare the measured text
+ * MeasuredText mt = new MeasuredText.Builder(text.toCharArray())
+ * .appendStyleRun(paint, 7, false) // Use paint for "Hello, "
+ * .appednStyleRun(bigPaint, 8, false) // Use bigPaint for "Hello, "
+ * .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 +95,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 +131,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 +175,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 +184,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 +196,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 +207,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 +218,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 +230,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 +253,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 +265,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 +279,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 +302,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 +311,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 +329,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 +353,7 @@ public class NativeLineBreaker {
}
/**
- * Returns a number of line count.
+ * Returns the number of lines in the paragraph.
*
* @return number of lines
*/
@@ -283,7 +362,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 +372,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 +392,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 +416,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 +427,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 +452,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..3efe655b2565
--- /dev/null
+++ b/graphics/java/android/graphics/text/MeasuredText.java
@@ -0,0 +1,348 @@
+/*
+ * 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.
+ *
+ * <p>
+ * <pre>
+ * <code>
+ * Paint paint = new Paint();
+ * Paint bigPaint = new Paint();
+ * bigPaint.setTextSize(paint.getTextSize() * 2.0);
+ * String text = "Hello, Android.";
+ * MeasuredText mt = new MeasuredText.Builder(text.toCharArray())
+ * .appendStyleRun(paint, 7, false) // Use paint for "Hello, "
+ * .appendStyleRun(bigPaint, 8, false) // Use bigPaint for "Hello, "
+ * .build();
+ * </code>
+ * </pre>
+ * </p>
+ */
+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}.
+ * <p>
+ * <pre>
+ * <code>
+ * Paint paint = new Paint();
+ * String text = "Hello, Android.";
+ * MeasuredText mt = new MeasuredText.Builder(text.toCharArray())
+ * .appendStyleRun(paint, text.length, false)
+ * .build();
+ * </code>
+ * </pre>
+ * </p>
+ *
+ * Note: The appendStyle and appendReplacementRun should be called to cover the text length.
+ */
+ public static class Builder {
+ private long mNativePtr;
+
+ private final @NonNull char[] mText;
+ private boolean mComputeHyphenation = false;
+ private boolean mComputeLayout = true;
+ private int mCurrentOffset = 0;
+
+ /**
+ * 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 length.
+ *
+ * Keeps an internal offset which increases at every append. The initial value for this
+ * offset is zero. After the style is applied the internal offset is moved to {@code offset
+ * + length}, and next call will start from this new position.
+ *
+ * @param paint a paint
+ * @param length a length to be applied with a given paint, can not exceed the length of the
+ * text
+ * @param isRtl true if the text is in RTL context, otherwise false.
+ */
+ public Builder appendStyleRun(@NonNull Paint paint, @IntRange(from = 0) int length,
+ boolean isRtl) {
+ Preconditions.checkNotNull(paint);
+ Preconditions.checkArgument(length > 0, "length can not be negative");
+ final int end = mCurrentOffset + length;
+ Preconditions.checkArgument(end <= mText.length, "Style exceeds the text length");
+ nAddStyleRun(mNativePtr, paint.getNativeInstance(), mCurrentOffset, end, isRtl);
+ mCurrentOffset = end;
+ return this;
+ }
+
+ /**
+ * Used to inform the text layout that the given length is replaced with the object of given
+ * width.
+ *
+ * Keeps an internal offset which increases at every append. The initial value for this
+ * offset is zero. After the style is applied the internal offset is moved to {@code offset
+ * + length}, and next call will start from this new position.
+ *
+ * Informs the layout engine that the given length should not be processed, instead the
+ * provided width should be used for calculating the width of that range.
+ *
+ * @param length a length to be replaced with the object, can not exceed the length of the
+ * text
+ * @param width a replacement width of the range
+ */
+ public Builder appendReplacementRun(@NonNull Paint paint,
+ @IntRange(from = 0) int length, @FloatRange(from = 0) float width) {
+ Preconditions.checkArgument(length > 0, "length can not be negative");
+ final int end = mCurrentOffset + length;
+ Preconditions.checkArgument(end <= mText.length, "Replacement exceeds the text length");
+ nAddReplacementRun(mNativePtr, paint.getNativeInstance(), mCurrentOffset, end, width);
+ mCurrentOffset = end;
+ 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.
+ * @throws IllegalStateException if the whole text is not covered by one or more runs (style
+ * or replacement)
+ */
+ public MeasuredText build() {
+ ensureNativePtrNoReuse();
+ if (mCurrentOffset != mText.length) {
+ throw new IllegalStateException("Style info has not been provided for all text.");
+ }
+ 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;
+ }
+ }
+
+ /**
+ * Ensures {@link #mNativePtr} is not reused.
+ *
+ * <p/> This is a method by itself to help increase testability - eg. Robolectric might want
+ * to override the validation behavior in test environment.
+ */
+ private void ensureNativePtrNoReuse() {
+ if (mNativePtr == 0) {
+ throw new IllegalStateException("Builder can not be reused.");
+ }
+ }
+
+ 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 e3ec45b20883..503951d1adc6 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -202,9 +202,7 @@ cc_defaults {
"AnimationContext.cpp",
"Animator.cpp",
"AnimatorManager.cpp",
- "CanvasState.cpp",
"CanvasTransform.cpp",
- "ClipArea.cpp",
"DamageAccumulator.cpp",
"DeferredLayerUpdater.cpp",
"DeviceInfo.cpp",
@@ -227,9 +225,7 @@ cc_defaults {
"RecordingCanvas.cpp",
"RenderNode.cpp",
"RenderProperties.cpp",
- "ResourceCache.cpp",
"SkiaCanvas.cpp",
- "Snapshot.cpp",
"TreeInfo.cpp",
"VectorDrawable.cpp",
"protos/graphicsstats.proto",
@@ -308,8 +304,6 @@ cc_test {
"tests/unit/main.cpp",
"tests/unit/CacheManagerTests.cpp",
"tests/unit/CanvasContextTests.cpp",
- "tests/unit/CanvasStateTests.cpp",
- "tests/unit/ClipAreaTests.cpp",
"tests/unit/DamageAccumulatorTests.cpp",
"tests/unit/DeferredLayerUpdaterTests.cpp",
"tests/unit/FatVectorTests.cpp",
@@ -328,7 +322,6 @@ cc_test {
"tests/unit/SkiaPipelineTests.cpp",
"tests/unit/SkiaRenderPropertiesTests.cpp",
"tests/unit/SkiaCanvasTests.cpp",
- "tests/unit/SnapshotTests.cpp",
"tests/unit/StringUtilsTests.cpp",
"tests/unit/TestUtilsTests.cpp",
"tests/unit/ThreadBaseTests.cpp",
diff --git a/libs/hwui/CanvasState.cpp b/libs/hwui/CanvasState.cpp
deleted file mode 100644
index d18c4abde7f2..000000000000
--- a/libs/hwui/CanvasState.cpp
+++ /dev/null
@@ -1,284 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "CanvasState.h"
-#include "hwui/Canvas.h"
-#include "utils/MathUtils.h"
-
-namespace android {
-namespace uirenderer {
-
-CanvasState::CanvasState(CanvasStateClient& renderer)
- : mWidth(-1), mHeight(-1), mSaveCount(1), mCanvas(renderer), mSnapshot(&mFirstSnapshot) {}
-
-CanvasState::~CanvasState() {
- // First call freeSnapshot on all but mFirstSnapshot
- // to invoke all the dtors
- freeAllSnapshots();
-
- // Now actually release the memory
- while (mSnapshotPool) {
- void* temp = mSnapshotPool;
- mSnapshotPool = mSnapshotPool->previous;
- free(temp);
- }
-}
-
-void CanvasState::initializeRecordingSaveStack(int viewportWidth, int viewportHeight) {
- if (mWidth != viewportWidth || mHeight != viewportHeight) {
- mWidth = viewportWidth;
- mHeight = viewportHeight;
- mFirstSnapshot.initializeViewport(viewportWidth, viewportHeight);
- mCanvas.onViewportInitialized();
- }
-
- freeAllSnapshots();
- mSnapshot = allocSnapshot(&mFirstSnapshot, SaveFlags::MatrixClip);
- mSnapshot->setRelativeLightCenter(Vector3());
- mSaveCount = 1;
-}
-
-void CanvasState::initializeSaveStack(int viewportWidth, int viewportHeight, float clipLeft,
- float clipTop, float clipRight, float clipBottom,
- const Vector3& lightCenter) {
- if (mWidth != viewportWidth || mHeight != viewportHeight) {
- mWidth = viewportWidth;
- mHeight = viewportHeight;
- mFirstSnapshot.initializeViewport(viewportWidth, viewportHeight);
- mCanvas.onViewportInitialized();
- }
-
- freeAllSnapshots();
- mSnapshot = allocSnapshot(&mFirstSnapshot, SaveFlags::MatrixClip);
- mSnapshot->setClip(clipLeft, clipTop, clipRight, clipBottom);
- mSnapshot->fbo = mCanvas.getTargetFbo();
- mSnapshot->setRelativeLightCenter(lightCenter);
- mSaveCount = 1;
-}
-
-Snapshot* CanvasState::allocSnapshot(Snapshot* previous, int savecount) {
- void* memory;
- if (mSnapshotPool) {
- memory = mSnapshotPool;
- mSnapshotPool = mSnapshotPool->previous;
- mSnapshotPoolCount--;
- } else {
- memory = malloc(sizeof(Snapshot));
- }
- return new (memory) Snapshot(previous, savecount);
-}
-
-void CanvasState::freeSnapshot(Snapshot* snapshot) {
- snapshot->~Snapshot();
- // Arbitrary number, just don't let this grown unbounded
- if (mSnapshotPoolCount > 10) {
- free((void*)snapshot);
- } else {
- snapshot->previous = mSnapshotPool;
- mSnapshotPool = snapshot;
- mSnapshotPoolCount++;
- }
-}
-
-void CanvasState::freeAllSnapshots() {
- while (mSnapshot != &mFirstSnapshot) {
- Snapshot* temp = mSnapshot;
- mSnapshot = mSnapshot->previous;
- freeSnapshot(temp);
- }
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// Save (layer)
-///////////////////////////////////////////////////////////////////////////////
-
-/**
- * Guaranteed to save without side-effects
- *
- * This approach, here and in restoreSnapshot(), allows subclasses to directly manipulate the save
- * stack, and ensures restoreToCount() doesn't call back into subclass overrides.
- */
-int CanvasState::saveSnapshot(int flags) {
- mSnapshot = allocSnapshot(mSnapshot, flags);
- return mSaveCount++;
-}
-
-int CanvasState::save(int flags) {
- return saveSnapshot(flags);
-}
-
-/**
- * Guaranteed to restore without side-effects.
- */
-void CanvasState::restoreSnapshot() {
- Snapshot* toRemove = mSnapshot;
- Snapshot* toRestore = mSnapshot->previous;
-
- mSaveCount--;
- mSnapshot = toRestore;
-
- // subclass handles restore implementation
- mCanvas.onSnapshotRestored(*toRemove, *toRestore);
-
- freeSnapshot(toRemove);
-}
-
-void CanvasState::restore() {
- if (mSaveCount > 1) {
- restoreSnapshot();
- }
-}
-
-void CanvasState::restoreToCount(int saveCount) {
- if (saveCount < 1) saveCount = 1;
-
- while (mSaveCount > saveCount) {
- restoreSnapshot();
- }
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// Matrix
-///////////////////////////////////////////////////////////////////////////////
-
-void CanvasState::getMatrix(SkMatrix* matrix) const {
- mSnapshot->transform->copyTo(*matrix);
-}
-
-void CanvasState::translate(float dx, float dy, float dz) {
- mSnapshot->transform->translate(dx, dy, dz);
-}
-
-void CanvasState::rotate(float degrees) {
- mSnapshot->transform->rotate(degrees, 0.0f, 0.0f, 1.0f);
-}
-
-void CanvasState::scale(float sx, float sy) {
- mSnapshot->transform->scale(sx, sy, 1.0f);
-}
-
-void CanvasState::skew(float sx, float sy) {
- mSnapshot->transform->skew(sx, sy);
-}
-
-void CanvasState::setMatrix(const SkMatrix& matrix) {
- mSnapshot->transform->load(matrix);
-}
-
-void CanvasState::setMatrix(const Matrix4& matrix) {
- *(mSnapshot->transform) = matrix;
-}
-
-void CanvasState::concatMatrix(const SkMatrix& matrix) {
- mat4 transform(matrix);
- mSnapshot->transform->multiply(transform);
-}
-
-void CanvasState::concatMatrix(const Matrix4& matrix) {
- mSnapshot->transform->multiply(matrix);
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// Clip
-///////////////////////////////////////////////////////////////////////////////
-
-bool CanvasState::clipRect(float left, float top, float right, float bottom, SkClipOp op) {
- mSnapshot->clip(Rect(left, top, right, bottom), op);
- return !mSnapshot->clipIsEmpty();
-}
-
-bool CanvasState::clipPath(const SkPath* path, SkClipOp op) {
- mSnapshot->clipPath(*path, op);
- return !mSnapshot->clipIsEmpty();
-}
-
-void CanvasState::setClippingOutline(LinearAllocator& allocator, const Outline* outline) {
- Rect bounds;
- float radius;
- if (!outline->getAsRoundRect(&bounds, &radius)) return; // only RR supported
-
- bool outlineIsRounded = MathUtils::isPositive(radius);
- if (!outlineIsRounded || currentTransform()->isSimple()) {
- // TODO: consider storing this rect separately, so that this can't be replaced with clip ops
- clipRect(bounds.left, bounds.top, bounds.right, bounds.bottom, SkClipOp::kIntersect);
- }
- if (outlineIsRounded) {
- setClippingRoundRect(allocator, bounds, radius, false);
- }
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// Quick Rejection
-///////////////////////////////////////////////////////////////////////////////
-
-/**
- * Calculates whether content drawn within the passed bounds would be outside of, or intersect with
- * the clipRect. Does not modify the scissor.
- *
- * @param clipRequired if not null, will be set to true if element intersects clip
- * (and wasn't rejected)
- *
- * @param snapOut if set, the geometry will be treated as having an AA ramp.
- * See Rect::snapGeometryToPixelBoundaries()
- */
-bool CanvasState::calculateQuickRejectForScissor(float left, float top, float right, float bottom,
- bool* clipRequired, bool* roundRectClipRequired,
- bool snapOut) const {
- if (bottom <= top || right <= left) {
- return true;
- }
-
- Rect r(left, top, right, bottom);
- currentTransform()->mapRect(r);
- r.snapGeometryToPixelBoundaries(snapOut);
-
- Rect clipRect(currentRenderTargetClip());
- clipRect.snapToPixelBoundaries();
-
- if (!clipRect.intersects(r)) return true;
-
- // clip is required if geometry intersects clip rect
- if (clipRequired) {
- *clipRequired = !clipRect.contains(r);
- }
-
- // round rect clip is required if RR clip exists, and geometry intersects its corners
- if (roundRectClipRequired) {
- *roundRectClipRequired = mSnapshot->roundRectClipState != nullptr &&
- mSnapshot->roundRectClipState->areaRequiresRoundRectClip(r);
- }
- return false;
-}
-
-bool CanvasState::quickRejectConservative(float left, float top, float right, float bottom) const {
- if (bottom <= top || right <= left) {
- return true;
- }
-
- Rect r(left, top, right, bottom);
- currentTransform()->mapRect(r);
- r.roundOut(); // rounded out to be conservative
-
- Rect clipRect(currentRenderTargetClip());
- clipRect.snapToPixelBoundaries();
-
- if (!clipRect.intersects(r)) return true;
-
- return false;
-}
-
-} // namespace uirenderer
-} // namespace android
diff --git a/libs/hwui/CanvasState.h b/libs/hwui/CanvasState.h
deleted file mode 100644
index 9ac35ff47dab..000000000000
--- a/libs/hwui/CanvasState.h
+++ /dev/null
@@ -1,195 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "Snapshot.h"
-
-#include <SkClipOp.h>
-#include <SkMatrix.h>
-#include <SkPath.h>
-#include <SkRegion.h>
-
-namespace android {
-namespace uirenderer {
-
-/**
- * Abstract base class for any class containing CanvasState.
- * Defines three mandatory callbacks.
- */
-class CanvasStateClient {
-public:
- CanvasStateClient() {}
- virtual ~CanvasStateClient() {}
-
- /**
- * Callback allowing embedder to take actions in the middle of a
- * setViewport() call.
- */
- virtual void onViewportInitialized() = 0;
-
- /**
- * Callback allowing embedder to take actions in the middle of a
- * restore() call. May be called several times sequentially.
- */
- virtual void onSnapshotRestored(const Snapshot& removed, const Snapshot& restored) = 0;
-
- /**
- * Allows subclasses to control what value is stored in snapshot's
- * fbo field in * initializeSaveStack.
- */
- virtual GLuint getTargetFbo() const = 0;
-
-}; // class CanvasStateClient
-
-/**
- * Implements Canvas state methods on behalf of Renderers.
- *
- * Manages the Snapshot stack, implementing matrix, save/restore, and clipping methods in the
- * Renderer interface. Drawing and recording classes that include a CanvasState will have
- * different use cases:
- *
- * Drawing code maintaining canvas state (e.g. FrameBuilder) can query attributes (such as
- * transform) or hook into changes (e.g. save/restore) with minimal surface area for manipulating
- * the stack itself.
- *
- * Recording code maintaining canvas state (e.g. RecordingCanvas) can both record and pass
- * through state operations to CanvasState, so that not only will querying operations work
- * (getClip/Matrix), but so that quickRejection can also be used.
- */
-
-class CanvasState {
-public:
- explicit CanvasState(CanvasStateClient& renderer);
- ~CanvasState();
-
- /**
- * Initializes the first snapshot, computing the projection matrix,
- * and stores the dimensions of the render target.
- */
- void initializeRecordingSaveStack(int viewportWidth, int viewportHeight);
-
- /**
- * Initializes the first snapshot, computing the projection matrix,
- * and stores the dimensions of the render target.
- */
- void initializeSaveStack(int viewportWidth, int viewportHeight, float clipLeft, float clipTop,
- float clipRight, float clipBottom, const Vector3& lightCenter);
-
- bool hasRectToRectTransform() const { return CC_LIKELY(currentTransform()->rectToRect()); }
-
- // Save (layer)
- int getSaveCount() const { return mSaveCount; }
- int save(int flags);
- void restore();
- void restoreToCount(int saveCount);
-
- // Save/Restore without side-effects
- int saveSnapshot(int flags);
- void restoreSnapshot();
-
- // Matrix
- void getMatrix(SkMatrix* outMatrix) const;
- void translate(float dx, float dy, float dz = 0.0f);
- void rotate(float degrees);
- void scale(float sx, float sy);
- void skew(float sx, float sy);
-
- void setMatrix(const SkMatrix& matrix);
- void setMatrix(const Matrix4& matrix); // internal only convenience method
- void concatMatrix(const SkMatrix& matrix);
- void concatMatrix(const Matrix4& matrix); // internal only convenience method
-
- // Clip
- const Rect& getLocalClipBounds() const { return mSnapshot->getLocalClip(); }
- const Rect& getRenderTargetClipBounds() const { return mSnapshot->getRenderTargetClip(); }
-
- bool quickRejectConservative(float left, float top, float right, float bottom) const;
-
- bool clipRect(float left, float top, float right, float bottom, SkClipOp op);
- bool clipPath(const SkPath* path, SkClipOp op);
-
- /**
- * Sets a "clipping outline", which is independent from the regular clip.
- * Currently only supports rectangles or rounded rectangles; passing in a
- * more complicated outline fails silently. Replaces any previous clipping
- * outline.
- */
- void setClippingOutline(LinearAllocator& allocator, const Outline* outline);
- void setClippingRoundRect(LinearAllocator& allocator, const Rect& rect, float radius,
- bool highPriority = true) {
- mSnapshot->setClippingRoundRect(allocator, rect, radius, highPriority);
- }
- void setProjectionPathMask(const SkPath* path) { mSnapshot->setProjectionPathMask(path); }
-
- /**
- * Returns true if drawing in the rectangle (left, top, right, bottom)
- * will be clipped out. Is conservative: might return false when subpixel-
- * perfect tests would return true.
- */
- bool calculateQuickRejectForScissor(float left, float top, float right, float bottom,
- bool* clipRequired, bool* roundRectClipRequired,
- bool snapOut) const;
-
- void scaleAlpha(float alpha) { mSnapshot->alpha *= alpha; }
-
- inline const mat4* currentTransform() const { return currentSnapshot()->transform; }
- inline const Rect& currentRenderTargetClip() const {
- return currentSnapshot()->getRenderTargetClip();
- }
- inline int currentFlags() const { return currentSnapshot()->flags; }
- const Vector3& currentLightCenter() const {
- return currentSnapshot()->getRelativeLightCenter();
- }
- int getViewportWidth() const { return currentSnapshot()->getViewportWidth(); }
- int getViewportHeight() const { return currentSnapshot()->getViewportHeight(); }
- int getWidth() const { return mWidth; }
- int getHeight() const { return mHeight; }
- bool clipIsSimple() const { return currentSnapshot()->clipIsSimple(); }
-
- inline const Snapshot* currentSnapshot() const { return mSnapshot; }
- inline Snapshot* writableSnapshot() { return mSnapshot; }
- inline const Snapshot* firstSnapshot() const { return &mFirstSnapshot; }
-
-private:
- Snapshot* allocSnapshot(Snapshot* previous, int savecount);
- void freeSnapshot(Snapshot* snapshot);
- void freeAllSnapshots();
-
- /// Dimensions of the drawing surface
- int mWidth, mHeight;
-
- /// Number of saved states
- int mSaveCount;
-
- /// Base state
- Snapshot mFirstSnapshot;
-
- /// Host providing callbacks
- CanvasStateClient& mCanvas;
-
- /// Current state
- Snapshot* mSnapshot;
-
- // Pool of allocated snapshots to re-use
- // NOTE: The dtors have already been invoked!
- Snapshot* mSnapshotPool = nullptr;
- int mSnapshotPoolCount = 0;
-
-}; // class CanvasState
-
-}; // namespace uirenderer
-}; // namespace android
diff --git a/libs/hwui/ClipArea.cpp b/libs/hwui/ClipArea.cpp
deleted file mode 100644
index 27d93cfa0391..000000000000
--- a/libs/hwui/ClipArea.cpp
+++ /dev/null
@@ -1,534 +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.
- */
-#include "ClipArea.h"
-
-#include "utils/LinearAllocator.h"
-
-#include <SkPath.h>
-#include <limits>
-#include <type_traits>
-
-namespace android {
-namespace uirenderer {
-
-static void handlePoint(Rect& transformedBounds, const Matrix4& transform, float x, float y) {
- Vertex v = {x, y};
- transform.mapPoint(v.x, v.y);
- transformedBounds.expandToCover(v.x, v.y);
-}
-
-Rect transformAndCalculateBounds(const Rect& r, const Matrix4& transform) {
- const float kMinFloat = std::numeric_limits<float>::lowest();
- const float kMaxFloat = std::numeric_limits<float>::max();
- Rect transformedBounds = {kMaxFloat, kMaxFloat, kMinFloat, kMinFloat};
- handlePoint(transformedBounds, transform, r.left, r.top);
- handlePoint(transformedBounds, transform, r.right, r.top);
- handlePoint(transformedBounds, transform, r.left, r.bottom);
- handlePoint(transformedBounds, transform, r.right, r.bottom);
- return transformedBounds;
-}
-
-void ClipBase::dump() const {
- ALOGD("mode %d" RECT_STRING, mode, RECT_ARGS(rect));
-}
-
-/*
- * TransformedRectangle
- */
-
-TransformedRectangle::TransformedRectangle() {}
-
-TransformedRectangle::TransformedRectangle(const Rect& bounds, const Matrix4& transform)
- : mBounds(bounds), mTransform(transform) {}
-
-bool TransformedRectangle::canSimplyIntersectWith(const TransformedRectangle& other) const {
- return mTransform == other.mTransform;
-}
-
-void TransformedRectangle::intersectWith(const TransformedRectangle& other) {
- mBounds.doIntersect(other.mBounds);
-}
-
-bool TransformedRectangle::isEmpty() const {
- return mBounds.isEmpty();
-}
-
-/*
- * RectangleList
- */
-
-RectangleList::RectangleList() : mTransformedRectanglesCount(0) {}
-
-bool RectangleList::isEmpty() const {
- if (mTransformedRectanglesCount < 1) {
- return true;
- }
-
- for (int i = 0; i < mTransformedRectanglesCount; i++) {
- if (mTransformedRectangles[i].isEmpty()) {
- return true;
- }
- }
- return false;
-}
-
-int RectangleList::getTransformedRectanglesCount() const {
- return mTransformedRectanglesCount;
-}
-
-const TransformedRectangle& RectangleList::getTransformedRectangle(int i) const {
- return mTransformedRectangles[i];
-}
-
-void RectangleList::setEmpty() {
- mTransformedRectanglesCount = 0;
-}
-
-void RectangleList::set(const Rect& bounds, const Matrix4& transform) {
- mTransformedRectanglesCount = 1;
- mTransformedRectangles[0] = TransformedRectangle(bounds, transform);
-}
-
-bool RectangleList::intersectWith(const Rect& bounds, const Matrix4& transform) {
- TransformedRectangle newRectangle(bounds, transform);
-
- // Try to find a rectangle with a compatible transformation
- int index = 0;
- for (; index < mTransformedRectanglesCount; index++) {
- TransformedRectangle& tr(mTransformedRectangles[index]);
- if (tr.canSimplyIntersectWith(newRectangle)) {
- tr.intersectWith(newRectangle);
- return true;
- }
- }
-
- // Add it to the list if there is room
- if (index < kMaxTransformedRectangles) {
- mTransformedRectangles[index] = newRectangle;
- mTransformedRectanglesCount += 1;
- return true;
- }
-
- // This rectangle list is full
- return false;
-}
-
-Rect RectangleList::calculateBounds() const {
- Rect bounds;
- for (int index = 0; index < mTransformedRectanglesCount; index++) {
- const TransformedRectangle& tr(mTransformedRectangles[index]);
- if (index == 0) {
- bounds = tr.transformedBounds();
- } else {
- bounds.doIntersect(tr.transformedBounds());
- }
- }
- return bounds;
-}
-
-static SkPath pathFromTransformedRectangle(const Rect& bounds, const Matrix4& transform) {
- SkPath rectPath;
- SkPath rectPathTransformed;
- rectPath.addRect(bounds.left, bounds.top, bounds.right, bounds.bottom);
- SkMatrix skTransform;
- transform.copyTo(skTransform);
- rectPath.transform(skTransform, &rectPathTransformed);
- return rectPathTransformed;
-}
-
-SkRegion RectangleList::convertToRegion(const SkRegion& clip) const {
- SkRegion rectangleListAsRegion;
- for (int index = 0; index < mTransformedRectanglesCount; index++) {
- const TransformedRectangle& tr(mTransformedRectangles[index]);
- SkPath rectPathTransformed =
- pathFromTransformedRectangle(tr.getBounds(), tr.getTransform());
- if (index == 0) {
- rectangleListAsRegion.setPath(rectPathTransformed, clip);
- } else {
- SkRegion rectRegion;
- rectRegion.setPath(rectPathTransformed, clip);
- rectangleListAsRegion.op(rectRegion, SkRegion::kIntersect_Op);
- }
- }
- return rectangleListAsRegion;
-}
-
-void RectangleList::transform(const Matrix4& transform) {
- for (int index = 0; index < mTransformedRectanglesCount; index++) {
- mTransformedRectangles[index].transform(transform);
- }
-}
-
-/*
- * ClipArea
- */
-
-ClipArea::ClipArea() : mMode(ClipMode::Rectangle) {}
-
-/*
- * Interface
- */
-
-void ClipArea::setViewportDimensions(int width, int height) {
- mPostViewportClipObserved = false;
- mViewportBounds.set(0, 0, width, height);
- mClipRect = mViewportBounds;
-}
-
-void ClipArea::setEmpty() {
- onClipUpdated();
- mMode = ClipMode::Rectangle;
- mClipRect.setEmpty();
- mClipRegion.setEmpty();
- mRectangleList.setEmpty();
-}
-
-void ClipArea::setClip(float left, float top, float right, float bottom) {
- onClipUpdated();
- mMode = ClipMode::Rectangle;
- mClipRect.set(left, top, right, bottom);
- mClipRegion.setEmpty();
-}
-
-void ClipArea::clipRectWithTransform(const Rect& r, const mat4* transform, SkRegion::Op op) {
- if (op == SkRegion::kReplace_Op) mReplaceOpObserved = true;
- if (!mPostViewportClipObserved && op == SkRegion::kIntersect_Op) op = SkRegion::kReplace_Op;
- onClipUpdated();
- switch (mMode) {
- case ClipMode::Rectangle:
- rectangleModeClipRectWithTransform(r, transform, op);
- break;
- case ClipMode::RectangleList:
- rectangleListModeClipRectWithTransform(r, transform, op);
- break;
- case ClipMode::Region:
- regionModeClipRectWithTransform(r, transform, op);
- break;
- }
-}
-
-void ClipArea::clipRegion(const SkRegion& region, SkRegion::Op op) {
- if (op == SkRegion::kReplace_Op) mReplaceOpObserved = true;
- if (!mPostViewportClipObserved && op == SkRegion::kIntersect_Op) op = SkRegion::kReplace_Op;
- onClipUpdated();
- enterRegionMode();
- mClipRegion.op(region, op);
- onClipRegionUpdated();
-}
-
-void ClipArea::clipPathWithTransform(const SkPath& path, const mat4* transform, SkRegion::Op op) {
- if (op == SkRegion::kReplace_Op) mReplaceOpObserved = true;
- if (!mPostViewportClipObserved && op == SkRegion::kIntersect_Op) op = SkRegion::kReplace_Op;
- onClipUpdated();
- SkMatrix skTransform;
- transform->copyTo(skTransform);
- SkPath transformed;
- path.transform(skTransform, &transformed);
- SkRegion region;
- regionFromPath(transformed, region);
- enterRegionMode();
- mClipRegion.op(region, op);
- onClipRegionUpdated();
-}
-
-/*
- * Rectangle mode
- */
-
-void ClipArea::enterRectangleMode() {
- // Entering rectangle mode discards any
- // existing clipping information from the other modes.
- // The only way this occurs is by a clip setting operation.
- mMode = ClipMode::Rectangle;
-}
-
-void ClipArea::rectangleModeClipRectWithTransform(const Rect& r, const mat4* transform,
- SkRegion::Op op) {
- if (op == SkRegion::kReplace_Op && transform->rectToRect()) {
- mClipRect = r;
- transform->mapRect(mClipRect);
- return;
- } else if (op != SkRegion::kIntersect_Op) {
- enterRegionMode();
- regionModeClipRectWithTransform(r, transform, op);
- return;
- }
-
- if (transform->rectToRect()) {
- Rect transformed(r);
- transform->mapRect(transformed);
- mClipRect.doIntersect(transformed);
- return;
- }
-
- enterRectangleListMode();
- rectangleListModeClipRectWithTransform(r, transform, op);
-}
-
-/*
- * RectangleList mode implementation
- */
-
-void ClipArea::enterRectangleListMode() {
- // Is is only legal to enter rectangle list mode from
- // rectangle mode, since rectangle list mode cannot represent
- // all clip areas that can be represented by a region.
- ALOG_ASSERT(mMode == ClipMode::Rectangle);
- mMode = ClipMode::RectangleList;
- mRectangleList.set(mClipRect, Matrix4::identity());
-}
-
-void ClipArea::rectangleListModeClipRectWithTransform(const Rect& r, const mat4* transform,
- SkRegion::Op op) {
- if (op != SkRegion::kIntersect_Op || !mRectangleList.intersectWith(r, *transform)) {
- enterRegionMode();
- regionModeClipRectWithTransform(r, transform, op);
- }
-}
-
-/*
- * Region mode implementation
- */
-
-void ClipArea::enterRegionMode() {
- ClipMode oldMode = mMode;
- mMode = ClipMode::Region;
- if (oldMode != ClipMode::Region) {
- if (oldMode == ClipMode::Rectangle) {
- mClipRegion.setRect(mClipRect.toSkIRect());
- } else {
- mClipRegion = mRectangleList.convertToRegion(createViewportRegion());
- onClipRegionUpdated();
- }
- }
-}
-
-void ClipArea::regionModeClipRectWithTransform(const Rect& r, const mat4* transform,
- SkRegion::Op op) {
- SkPath transformedRect = pathFromTransformedRectangle(r, *transform);
- SkRegion transformedRectRegion;
- regionFromPath(transformedRect, transformedRectRegion);
- mClipRegion.op(transformedRectRegion, op);
- onClipRegionUpdated();
-}
-
-void ClipArea::onClipRegionUpdated() {
- if (!mClipRegion.isEmpty()) {
- mClipRect.set(mClipRegion.getBounds());
-
- if (mClipRegion.isRect()) {
- mClipRegion.setEmpty();
- enterRectangleMode();
- }
- } else {
- mClipRect.setEmpty();
- }
-}
-
-/**
- * Clip serialization
- */
-
-const ClipBase* ClipArea::serializeClip(LinearAllocator& allocator) {
- if (!mPostViewportClipObserved) {
- // Only initial clip-to-viewport observed, so no serialization of clip necessary
- return nullptr;
- }
-
- static_assert(std::is_trivially_destructible<Rect>::value,
- "expect Rect to be trivially destructible");
- static_assert(std::is_trivially_destructible<RectangleList>::value,
- "expect RectangleList to be trivially destructible");
-
- if (mLastSerialization == nullptr) {
- ClipBase* serialization = nullptr;
- switch (mMode) {
- case ClipMode::Rectangle:
- serialization = allocator.create<ClipRect>(mClipRect);
- break;
- case ClipMode::RectangleList:
- serialization = allocator.create<ClipRectList>(mRectangleList);
- serialization->rect = mRectangleList.calculateBounds();
- break;
- case ClipMode::Region:
- serialization = allocator.create<ClipRegion>(mClipRegion);
- serialization->rect.set(mClipRegion.getBounds());
- break;
- }
- serialization->intersectWithRoot = mReplaceOpObserved;
- // TODO: this is only done for draw time, should eventually avoid for record time
- serialization->rect.snapToPixelBoundaries();
- mLastSerialization = serialization;
- }
- return mLastSerialization;
-}
-
-inline static const RectangleList& getRectList(const ClipBase* scb) {
- return reinterpret_cast<const ClipRectList*>(scb)->rectList;
-}
-
-inline static const SkRegion& getRegion(const ClipBase* scb) {
- return reinterpret_cast<const ClipRegion*>(scb)->region;
-}
-
-// Conservative check for too many rectangles to fit in rectangle list.
-// For simplicity, doesn't account for rect merging
-static bool cannotFitInRectangleList(const ClipArea& clipArea, const ClipBase* scb) {
- int currentRectCount = clipArea.isRectangleList()
- ? clipArea.getRectangleList().getTransformedRectanglesCount()
- : 1;
- int recordedRectCount = (scb->mode == ClipMode::RectangleList)
- ? getRectList(scb).getTransformedRectanglesCount()
- : 1;
- return currentRectCount + recordedRectCount > RectangleList::kMaxTransformedRectangles;
-}
-
-static const ClipRect sEmptyClipRect(Rect(0, 0));
-
-const ClipBase* ClipArea::serializeIntersectedClip(LinearAllocator& allocator,
- const ClipBase* recordedClip,
- const Matrix4& recordedClipTransform) {
- // if no recordedClip passed, just serialize current state
- if (!recordedClip) return serializeClip(allocator);
-
- // if either is empty, clip is empty
- if (CC_UNLIKELY(recordedClip->rect.isEmpty()) || mClipRect.isEmpty()) return &sEmptyClipRect;
-
- if (!mLastResolutionResult || recordedClip != mLastResolutionClip ||
- recordedClipTransform != mLastResolutionTransform) {
- mLastResolutionClip = recordedClip;
- mLastResolutionTransform = recordedClipTransform;
-
- if (CC_LIKELY(mMode == ClipMode::Rectangle && recordedClip->mode == ClipMode::Rectangle &&
- recordedClipTransform.rectToRect())) {
- // common case - result is a single rectangle
- auto rectClip = allocator.create<ClipRect>(recordedClip->rect);
- recordedClipTransform.mapRect(rectClip->rect);
- rectClip->rect.doIntersect(mClipRect);
- rectClip->rect.snapToPixelBoundaries();
- mLastResolutionResult = rectClip;
- } else if (CC_UNLIKELY(mMode == ClipMode::Region ||
- recordedClip->mode == ClipMode::Region ||
- cannotFitInRectangleList(*this, recordedClip))) {
- // region case
- SkRegion other;
- switch (recordedClip->mode) {
- case ClipMode::Rectangle:
- if (CC_LIKELY(recordedClipTransform.rectToRect())) {
- // simple transform, skip creating SkPath
- Rect resultClip(recordedClip->rect);
- recordedClipTransform.mapRect(resultClip);
- other.setRect(resultClip.toSkIRect());
- } else {
- SkPath transformedRect = pathFromTransformedRectangle(
- recordedClip->rect, recordedClipTransform);
- other.setPath(transformedRect, createViewportRegion());
- }
- break;
- case ClipMode::RectangleList: {
- RectangleList transformedList(getRectList(recordedClip));
- transformedList.transform(recordedClipTransform);
- other = transformedList.convertToRegion(createViewportRegion());
- break;
- }
- case ClipMode::Region:
- other = getRegion(recordedClip);
- applyTransformToRegion(recordedClipTransform, &other);
- }
-
- ClipRegion* regionClip = allocator.create<ClipRegion>();
- switch (mMode) {
- case ClipMode::Rectangle:
- regionClip->region.op(mClipRect.toSkIRect(), other, SkRegion::kIntersect_Op);
- break;
- case ClipMode::RectangleList:
- regionClip->region.op(mRectangleList.convertToRegion(createViewportRegion()),
- other, SkRegion::kIntersect_Op);
- break;
- case ClipMode::Region:
- regionClip->region.op(mClipRegion, other, SkRegion::kIntersect_Op);
- break;
- }
- // Don't need to snap, since region's in int bounds
- regionClip->rect.set(regionClip->region.getBounds());
- mLastResolutionResult = regionClip;
- } else {
- auto rectListClip = allocator.create<ClipRectList>(mRectangleList);
- auto&& rectList = rectListClip->rectList;
- if (mMode == ClipMode::Rectangle) {
- rectList.set(mClipRect, Matrix4::identity());
- }
-
- if (recordedClip->mode == ClipMode::Rectangle) {
- rectList.intersectWith(recordedClip->rect, recordedClipTransform);
- } else {
- const RectangleList& other = getRectList(recordedClip);
- for (int i = 0; i < other.getTransformedRectanglesCount(); i++) {
- auto&& tr = other.getTransformedRectangle(i);
- Matrix4 totalTransform(recordedClipTransform);
- totalTransform.multiply(tr.getTransform());
- rectList.intersectWith(tr.getBounds(), totalTransform);
- }
- }
- rectListClip->rect = rectList.calculateBounds();
- rectListClip->rect.snapToPixelBoundaries();
- mLastResolutionResult = rectListClip;
- }
- }
- return mLastResolutionResult;
-}
-
-void ClipArea::applyClip(const ClipBase* clip, const Matrix4& transform) {
- if (!clip) return; // nothing to do
-
- if (CC_LIKELY(clip->mode == ClipMode::Rectangle)) {
- clipRectWithTransform(clip->rect, &transform, SkRegion::kIntersect_Op);
- } else if (CC_LIKELY(clip->mode == ClipMode::RectangleList)) {
- auto&& rectList = getRectList(clip);
- for (int i = 0; i < rectList.getTransformedRectanglesCount(); i++) {
- auto&& tr = rectList.getTransformedRectangle(i);
- Matrix4 totalTransform(transform);
- totalTransform.multiply(tr.getTransform());
- clipRectWithTransform(tr.getBounds(), &totalTransform, SkRegion::kIntersect_Op);
- }
- } else {
- SkRegion region(getRegion(clip));
- applyTransformToRegion(transform, &region);
- clipRegion(region, SkRegion::kIntersect_Op);
- }
-}
-
-void ClipArea::applyTransformToRegion(const Matrix4& transform, SkRegion* region) {
- if (transform.rectToRect() && !transform.isPureTranslate()) {
- // handle matrices with scale manually by mapping each rect
- SkRegion other;
- SkRegion::Iterator it(*region);
- while (!it.done()) {
- Rect rect(it.rect());
- transform.mapRect(rect);
- rect.snapGeometryToPixelBoundaries(true);
- other.op(rect.left, rect.top, rect.right, rect.bottom, SkRegion::kUnion_Op);
- it.next();
- }
- region->swap(other);
- } else {
- // TODO: handle non-translate transforms properly!
- region->translate(transform.getTranslateX(), transform.getTranslateY());
- }
-}
-
-} /* namespace uirenderer */
-} /* namespace android */
diff --git a/libs/hwui/ClipArea.h b/libs/hwui/ClipArea.h
deleted file mode 100644
index a7a11801cfe2..000000000000
--- a/libs/hwui/ClipArea.h
+++ /dev/null
@@ -1,212 +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.
- */
-#ifndef CLIPAREA_H
-#define CLIPAREA_H
-
-#include "Matrix.h"
-#include "Rect.h"
-#include "utils/Pair.h"
-
-#include <SkRegion.h>
-
-namespace android {
-namespace uirenderer {
-
-class LinearAllocator;
-
-Rect transformAndCalculateBounds(const Rect& r, const Matrix4& transform);
-
-class TransformedRectangle {
-public:
- TransformedRectangle();
- TransformedRectangle(const Rect& bounds, const Matrix4& transform);
-
- bool canSimplyIntersectWith(const TransformedRectangle& other) const;
- void intersectWith(const TransformedRectangle& other);
-
- bool isEmpty() const;
-
- const Rect& getBounds() const { return mBounds; }
-
- Rect transformedBounds() const {
- Rect transformedBounds(transformAndCalculateBounds(mBounds, mTransform));
- return transformedBounds;
- }
-
- const Matrix4& getTransform() const { return mTransform; }
-
- void transform(const Matrix4& transform) {
- Matrix4 t;
- t.loadMultiply(transform, mTransform);
- mTransform = t;
- }
-
-private:
- Rect mBounds;
- Matrix4 mTransform;
-};
-
-class RectangleList {
-public:
- RectangleList();
-
- bool isEmpty() const;
- int getTransformedRectanglesCount() const;
- const TransformedRectangle& getTransformedRectangle(int i) const;
-
- void setEmpty();
- void set(const Rect& bounds, const Matrix4& transform);
- bool intersectWith(const Rect& bounds, const Matrix4& transform);
- void transform(const Matrix4& transform);
-
- SkRegion convertToRegion(const SkRegion& clip) const;
- Rect calculateBounds() const;
-
- enum { kMaxTransformedRectangles = 5 };
-
-private:
- int mTransformedRectanglesCount;
- TransformedRectangle mTransformedRectangles[kMaxTransformedRectangles];
-};
-
-enum class ClipMode {
- Rectangle,
- RectangleList,
-
- // region and path - intersected. if either is empty, don't use
- Region
-};
-
-struct ClipBase {
- explicit ClipBase(ClipMode mode) : mode(mode) {}
- explicit ClipBase(const Rect& rect) : mode(ClipMode::Rectangle), rect(rect) {}
- const ClipMode mode;
- bool intersectWithRoot = false;
- // Bounds of the clipping area, used to define the scissor, and define which
- // portion of the stencil is updated/used
- Rect rect;
-
- void dump() const;
-};
-
-struct ClipRect : ClipBase {
- explicit ClipRect(const Rect& rect) : ClipBase(rect) {}
-};
-
-struct ClipRectList : ClipBase {
- explicit ClipRectList(const RectangleList& rectList)
- : ClipBase(ClipMode::RectangleList), rectList(rectList) {}
- RectangleList rectList;
-};
-
-struct ClipRegion : ClipBase {
- explicit ClipRegion(const SkRegion& region) : ClipBase(ClipMode::Region), region(region) {}
- ClipRegion() : ClipBase(ClipMode::Region) {}
- SkRegion region;
-};
-
-class ClipArea {
-public:
- ClipArea();
-
- void setViewportDimensions(int width, int height);
-
- bool isEmpty() const { return mClipRect.isEmpty(); }
-
- void setEmpty();
- void setClip(float left, float top, float right, float bottom);
- void clipRectWithTransform(const Rect& r, const mat4* transform, SkRegion::Op op);
- void clipPathWithTransform(const SkPath& path, const mat4* transform, SkRegion::Op op);
-
- const Rect& getClipRect() const { return mClipRect; }
-
- const SkRegion& getClipRegion() const { return mClipRegion; }
-
- const RectangleList& getRectangleList() const { return mRectangleList; }
-
- bool isRegion() const { return ClipMode::Region == mMode; }
-
- bool isSimple() const { return mMode == ClipMode::Rectangle; }
-
- bool isRectangleList() const { return mMode == ClipMode::RectangleList; }
-
- WARN_UNUSED_RESULT const ClipBase* serializeClip(LinearAllocator& allocator);
- WARN_UNUSED_RESULT const ClipBase* serializeIntersectedClip(
- LinearAllocator& allocator, const ClipBase* recordedClip,
- const Matrix4& recordedClipTransform);
- void applyClip(const ClipBase* recordedClip, const Matrix4& recordedClipTransform);
-
- static void applyTransformToRegion(const Matrix4& transform, SkRegion* region);
-
-private:
- void enterRectangleMode();
- void rectangleModeClipRectWithTransform(const Rect& r, const mat4* transform, SkRegion::Op op);
-
- void enterRectangleListMode();
- void rectangleListModeClipRectWithTransform(const Rect& r, const mat4* transform,
- SkRegion::Op op);
-
- void enterRegionModeFromRectangleMode();
- void enterRegionModeFromRectangleListMode();
- void enterRegionMode();
- void regionModeClipRectWithTransform(const Rect& r, const mat4* transform, SkRegion::Op op);
-
- void clipRegion(const SkRegion& region, SkRegion::Op op);
- void ensureClipRegion();
- void onClipRegionUpdated();
-
- // Called by every state modifying public method.
- void onClipUpdated() {
- mPostViewportClipObserved = true;
- mLastSerialization = nullptr;
- mLastResolutionResult = nullptr;
- }
-
- SkRegion createViewportRegion() { return SkRegion(mViewportBounds.toSkIRect()); }
-
- void regionFromPath(const SkPath& path, SkRegion& pathAsRegion) {
- // TODO: this should not mask every path to the viewport - this makes it impossible to use
- // paths to clip to larger areas (which is valid e.g. with SkRegion::kReplace_Op)
- pathAsRegion.setPath(path, createViewportRegion());
- }
-
- ClipMode mMode;
- bool mPostViewportClipObserved = false;
- bool mReplaceOpObserved = false;
-
- /**
- * If mLastSerialization is non-null, it represents an already serialized copy
- * of the current clip state. If null, it has not been computed.
- */
- const ClipBase* mLastSerialization = nullptr;
-
- /**
- * This pair of pointers is a single entry cache of most recently seen
- */
- const ClipBase* mLastResolutionResult = nullptr;
- const ClipBase* mLastResolutionClip = nullptr;
- Matrix4 mLastResolutionTransform;
-
- Rect mViewportBounds;
- Rect mClipRect;
- SkRegion mClipRegion;
- RectangleList mRectangleList;
-};
-
-} /* namespace uirenderer */
-} /* namespace android */
-
-#endif /* CLIPAREA_H_ */
diff --git a/libs/hwui/FloatColor.h b/libs/hwui/FloatColor.h
deleted file mode 100644
index b424f97a5004..000000000000
--- a/libs/hwui/FloatColor.h
+++ /dev/null
@@ -1,71 +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.
- */
-#ifndef FLOATCOLOR_H
-#define FLOATCOLOR_H
-
-#include "utils/Color.h"
-#include "utils/Macros.h"
-#include "utils/MathUtils.h"
-
-#include <stdint.h>
-
-namespace android {
-namespace uirenderer {
-
-struct FloatColor {
- // "color" is a gamma-encoded sRGB color
- // After calling this method, the color is stored as a pre-multiplied linear color
- // if linear blending is enabled. Otherwise, the color is stored as a pre-multiplied
- // gamma-encoded sRGB color
- void set(uint32_t color) {
- a = ((color >> 24) & 0xff) / 255.0f;
- r = a * EOCF(((color >> 16) & 0xff) / 255.0f);
- g = a * EOCF(((color >> 8) & 0xff) / 255.0f);
- b = a * EOCF(((color)&0xff) / 255.0f);
- }
-
- // "color" is a gamma-encoded sRGB color
- // After calling this method, the color is stored as a un-premultiplied linear color
- // if linear blending is enabled. Otherwise, the color is stored as a un-premultiplied
- // gamma-encoded sRGB color
- void setUnPreMultiplied(uint32_t color) {
- a = ((color >> 24) & 0xff) / 255.0f;
- r = EOCF(((color >> 16) & 0xff) / 255.0f);
- g = EOCF(((color >> 8) & 0xff) / 255.0f);
- b = EOCF(((color)&0xff) / 255.0f);
- }
-
- bool isNotBlack() { return a < 1.0f || r > 0.0f || g > 0.0f || b > 0.0f; }
-
- bool operator==(const FloatColor& other) const {
- return MathUtils::areEqual(r, other.r) && MathUtils::areEqual(g, other.g) &&
- MathUtils::areEqual(b, other.b) && MathUtils::areEqual(a, other.a);
- }
-
- bool operator!=(const FloatColor& other) const { return !(*this == other); }
-
- float r;
- float g;
- float b;
- float a;
-};
-
-REQUIRE_COMPATIBLE_LAYOUT(FloatColor);
-
-} /* namespace uirenderer */
-} /* namespace android */
-
-#endif /* FLOATCOLOR_H */
diff --git a/libs/hwui/ResourceCache.cpp b/libs/hwui/ResourceCache.cpp
deleted file mode 100644
index 65bee476f14d..000000000000
--- a/libs/hwui/ResourceCache.cpp
+++ /dev/null
@@ -1,145 +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.
- */
-
-#include "ResourceCache.h"
-
-namespace android {
-
-using namespace uirenderer;
-ANDROID_SINGLETON_STATIC_INSTANCE(ResourceCache);
-
-namespace uirenderer {
-
-///////////////////////////////////////////////////////////////////////////////
-// Resource cache
-///////////////////////////////////////////////////////////////////////////////
-
-void ResourceCache::logCache() {
- ALOGD("ResourceCache: cacheReport:");
- for (size_t i = 0; i < mCache->size(); ++i) {
- ResourceReference* ref = mCache->valueAt(i);
- ALOGD(" ResourceCache: mCache(%zu): resource, ref = 0x%p, 0x%p", i, mCache->keyAt(i),
- mCache->valueAt(i));
- ALOGD(" ResourceCache: mCache(%zu): refCount, destroyed, type = %d, %d, %d", i,
- ref->refCount, ref->destroyed, ref->resourceType);
- }
-}
-
-ResourceCache::ResourceCache() {
- Mutex::Autolock _l(mLock);
- mCache = new KeyedVector<const void*, ResourceReference*>();
-}
-
-ResourceCache::~ResourceCache() {
- Mutex::Autolock _l(mLock);
- delete mCache;
-}
-
-void ResourceCache::lock() {
- mLock.lock();
-}
-
-void ResourceCache::unlock() {
- mLock.unlock();
-}
-
-void ResourceCache::incrementRefcount(void* resource, ResourceType resourceType) {
- Mutex::Autolock _l(mLock);
- incrementRefcountLocked(resource, resourceType);
-}
-
-void ResourceCache::incrementRefcount(const Res_png_9patch* patchResource) {
- incrementRefcount((void*)patchResource, kNinePatch);
-}
-
-void ResourceCache::incrementRefcountLocked(void* resource, ResourceType resourceType) {
- ssize_t index = mCache->indexOfKey(resource);
- ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : nullptr;
- if (ref == nullptr || mCache->size() == 0) {
- ref = new ResourceReference(resourceType);
- mCache->add(resource, ref);
- }
- ref->refCount++;
-}
-
-void ResourceCache::decrementRefcount(void* resource) {
- Mutex::Autolock _l(mLock);
- decrementRefcountLocked(resource);
-}
-
-void ResourceCache::decrementRefcount(const Res_png_9patch* patchResource) {
- decrementRefcount((void*)patchResource);
-}
-
-void ResourceCache::decrementRefcountLocked(void* resource) {
- ssize_t index = mCache->indexOfKey(resource);
- ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : nullptr;
- if (ref == nullptr) {
- // Should not get here - shouldn't get a call to decrement if we're not yet tracking it
- return;
- }
- ref->refCount--;
- if (ref->refCount == 0) {
- deleteResourceReferenceLocked(resource, ref);
- }
-}
-
-void ResourceCache::decrementRefcountLocked(const Res_png_9patch* patchResource) {
- decrementRefcountLocked((void*)patchResource);
-}
-
-void ResourceCache::destructor(Res_png_9patch* resource) {
- Mutex::Autolock _l(mLock);
- destructorLocked(resource);
-}
-
-void ResourceCache::destructorLocked(Res_png_9patch* resource) {
- ssize_t index = mCache->indexOfKey(resource);
- ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : nullptr;
- if (ref == nullptr) {
- // If we're not tracking this resource, just delete it
- // A Res_png_9patch is actually an array of byte that's larger
- // than sizeof(Res_png_9patch). It must be freed as an array.
- delete[](int8_t*) resource;
- return;
- }
- ref->destroyed = true;
- if (ref->refCount == 0) {
- deleteResourceReferenceLocked(resource, ref);
- }
-}
-
-/**
- * This method should only be called while the mLock mutex is held (that mutex is grabbed
- * by the various destructor() and recycle() methods which call this method).
- */
-void ResourceCache::deleteResourceReferenceLocked(const void* resource, ResourceReference* ref) {
- if (ref->destroyed) {
- switch (ref->resourceType) {
- case kNinePatch: {
- // A Res_png_9patch is actually an array of byte that's larger
- // than sizeof(Res_png_9patch). It must be freed as an array.
- int8_t* patch = (int8_t*)resource;
- delete[] patch;
- } break;
- }
- }
- mCache->removeItem(resource);
- delete ref;
-}
-
-}; // namespace uirenderer
-}; // namespace android
diff --git a/libs/hwui/ResourceCache.h b/libs/hwui/ResourceCache.h
deleted file mode 100644
index fd3f9fd05d58..000000000000
--- a/libs/hwui/ResourceCache.h
+++ /dev/null
@@ -1,103 +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.
- */
-
-#ifndef ANDROID_HWUI_RESOURCE_CACHE_H
-#define ANDROID_HWUI_RESOURCE_CACHE_H
-
-#include <cutils/compiler.h>
-
-#include <SkBitmap.h>
-#include <SkPixelRef.h>
-
-#include <utils/KeyedVector.h>
-#include <utils/Singleton.h>
-
-#include <androidfw/ResourceTypes.h>
-
-namespace android {
-namespace uirenderer {
-
-class Layer;
-
-/**
- * Type of Resource being cached
- */
-enum ResourceType {
- kNinePatch,
-};
-
-class ResourceReference {
-public:
- explicit ResourceReference(ResourceType type) {
- refCount = 0;
- destroyed = false;
- resourceType = type;
- }
-
- int refCount;
- bool destroyed;
- ResourceType resourceType;
-};
-
-class ANDROID_API ResourceCache : public Singleton<ResourceCache> {
- ResourceCache();
- ~ResourceCache();
-
- friend class Singleton<ResourceCache>;
-
-public:
- /**
- * When using these two methods, make sure to only invoke the *Locked()
- * variants of increment/decrementRefcount(), recyle() and destructor()
- */
- void lock();
- void unlock();
-
- void incrementRefcount(const Res_png_9patch* resource);
-
- void decrementRefcount(const Res_png_9patch* resource);
-
- void decrementRefcountLocked(const Res_png_9patch* resource);
-
- void destructor(Res_png_9patch* resource);
-
- void destructorLocked(Res_png_9patch* resource);
-
-private:
- void deleteResourceReferenceLocked(const void* resource, ResourceReference* ref);
-
- void incrementRefcount(void* resource, ResourceType resourceType);
- void incrementRefcountLocked(void* resource, ResourceType resourceType);
-
- void decrementRefcount(void* resource);
- void decrementRefcountLocked(void* resource);
-
- void logCache();
-
- /**
- * Used to increment, decrement, and destroy. Incrementing is generally accessed on the UI
- * thread, but destroying resources may be called from the GC thread, the finalizer thread,
- * or a reference queue finalization thread.
- */
- mutable Mutex mLock;
-
- KeyedVector<const void*, ResourceReference*>* mCache;
-};
-
-}; // namespace uirenderer
-}; // namespace android
-
-#endif // ANDROID_HWUI_RESOURCE_CACHE_H
diff --git a/libs/hwui/Snapshot.cpp b/libs/hwui/Snapshot.cpp
deleted file mode 100644
index f1a1bef7c94e..000000000000
--- a/libs/hwui/Snapshot.cpp
+++ /dev/null
@@ -1,209 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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 "Snapshot.h"
-
-#include "hwui/Canvas.h"
-
-namespace android {
-namespace uirenderer {
-
-///////////////////////////////////////////////////////////////////////////////
-// Constructors
-///////////////////////////////////////////////////////////////////////////////
-
-Snapshot::Snapshot()
- : flags(0)
- , previous(nullptr)
- , layer(nullptr)
- , fbo(0)
- , alpha(1.0f)
- , roundRectClipState(nullptr)
- , projectionPathMask(nullptr)
- , mClipArea(&mClipAreaRoot) {
- transform = &mTransformRoot;
- mRelativeLightCenter.x = mRelativeLightCenter.y = mRelativeLightCenter.z = 0;
-}
-
-/**
- * Copies the specified snapshot/ The specified snapshot is stored as
- * the previous snapshot.
- */
-Snapshot::Snapshot(Snapshot* s, int saveFlags)
- : flags(0)
- , previous(s)
- , layer(s->layer)
- , fbo(s->fbo)
- , alpha(s->alpha)
- , roundRectClipState(s->roundRectClipState)
- , projectionPathMask(s->projectionPathMask)
- , mClipArea(nullptr)
- , mViewportData(s->mViewportData)
- , mRelativeLightCenter(s->mRelativeLightCenter) {
- if (saveFlags & SaveFlags::Matrix) {
- mTransformRoot = *s->transform;
- transform = &mTransformRoot;
- } else {
- transform = s->transform;
- }
-
- if (saveFlags & SaveFlags::Clip) {
- mClipAreaRoot = s->getClipArea();
- mClipArea = &mClipAreaRoot;
- } else {
- mClipArea = s->mClipArea;
- }
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// Clipping
-///////////////////////////////////////////////////////////////////////////////
-
-void Snapshot::clip(const Rect& localClip, SkClipOp op) {
- flags |= Snapshot::kFlagClipSet;
- mClipArea->clipRectWithTransform(localClip, transform, static_cast<SkRegion::Op>(op));
-}
-
-void Snapshot::clipPath(const SkPath& path, SkClipOp op) {
- flags |= Snapshot::kFlagClipSet;
- mClipArea->clipPathWithTransform(path, transform, static_cast<SkRegion::Op>(op));
-}
-
-void Snapshot::setClip(float left, float top, float right, float bottom) {
- flags |= Snapshot::kFlagClipSet;
- mClipArea->setClip(left, top, right, bottom);
-}
-
-bool Snapshot::hasPerspectiveTransform() const {
- return transform->isPerspective();
-}
-
-const Rect& Snapshot::getLocalClip() {
- mat4 inverse;
- inverse.loadInverse(*transform);
-
- mLocalClip.set(mClipArea->getClipRect());
- inverse.mapRect(mLocalClip);
-
- return mLocalClip;
-}
-
-void Snapshot::resetClip(float left, float top, float right, float bottom) {
- // TODO: This is incorrect, when we start rendering into a new layer,
- // we may have to modify the previous snapshot's clip rect and clip
- // region if the previous restore() call did not restore the clip
- mClipArea = &mClipAreaRoot;
- setClip(left, top, right, bottom);
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// Clipping round rect
-///////////////////////////////////////////////////////////////////////////////
-
-void Snapshot::setClippingRoundRect(LinearAllocator& allocator, const Rect& bounds, float radius,
- bool highPriority) {
- if (bounds.isEmpty()) {
- mClipArea->setEmpty();
- return;
- }
-
- if (roundRectClipState && roundRectClipState->highPriority) {
- // ignore, don't replace, already have a high priority clip
- return;
- }
-
- RoundRectClipState* state = new (allocator) RoundRectClipState;
-
- state->highPriority = highPriority;
-
- // store the inverse drawing matrix
- Matrix4 roundRectDrawingMatrix = getOrthoMatrix();
- roundRectDrawingMatrix.multiply(*transform);
- state->matrix.loadInverse(roundRectDrawingMatrix);
-
- // compute area under rounded corners - only draws overlapping these rects need to be clipped
- for (int i = 0; i < 4; i++) {
- state->dangerRects[i] = bounds;
- }
- state->dangerRects[0].bottom = state->dangerRects[1].bottom = bounds.top + radius;
- state->dangerRects[0].right = state->dangerRects[2].right = bounds.left + radius;
- state->dangerRects[1].left = state->dangerRects[3].left = bounds.right - radius;
- state->dangerRects[2].top = state->dangerRects[3].top = bounds.bottom - radius;
- for (int i = 0; i < 4; i++) {
- transform->mapRect(state->dangerRects[i]);
-
- // round danger rects out as though they are AA geometry (since they essentially are)
- state->dangerRects[i].snapGeometryToPixelBoundaries(true);
- }
-
- // store RR area
- state->innerRect = bounds;
- state->innerRect.inset(radius);
- state->radius = radius;
-
- // store as immutable so, for this frame, pointer uniquely identifies this bundle of shader info
- roundRectClipState = state;
-}
-
-void Snapshot::setProjectionPathMask(const SkPath* path) {
- projectionPathMask = path;
-}
-
-static Snapshot* getClipRoot(Snapshot* target) {
- while (target->previous && target->previous->previous) {
- target = target->previous;
- }
- return target;
-}
-
-const ClipBase* Snapshot::serializeIntersectedClip(LinearAllocator& allocator,
- const ClipBase* recordedClip,
- const Matrix4& recordedClipTransform) {
- auto target = this;
- if (CC_UNLIKELY(recordedClip && recordedClip->intersectWithRoot)) {
- // Clip must be intersected with root, instead of current clip.
- target = getClipRoot(this);
- }
-
- return target->mClipArea->serializeIntersectedClip(allocator, recordedClip,
- recordedClipTransform);
-}
-
-void Snapshot::applyClip(const ClipBase* recordedClip, const Matrix4& transform) {
- if (CC_UNLIKELY(recordedClip && recordedClip->intersectWithRoot)) {
- // current clip is being replaced, but must intersect with clip root
- *mClipArea = *(getClipRoot(this)->mClipArea);
- }
- mClipArea->applyClip(recordedClip, transform);
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// Queries
-///////////////////////////////////////////////////////////////////////////////
-
-void Snapshot::dump() const {
- ALOGD("Snapshot %p, flags %x, prev %p, height %d, hasComplexClip %d", this, flags, previous,
- getViewportHeight(), !mClipArea->isSimple());
- const Rect& clipRect(mClipArea->getClipRect());
- ALOGD(" ClipRect %.1f %.1f %.1f %.1f, clip simple %d", clipRect.left, clipRect.top,
- clipRect.right, clipRect.bottom, mClipArea->isSimple());
-
- ALOGD(" Transform (at %p):", transform);
- transform->dump();
-}
-
-}; // namespace uirenderer
-}; // namespace android
diff --git a/libs/hwui/Snapshot.h b/libs/hwui/Snapshot.h
deleted file mode 100644
index 655f819ca41b..000000000000
--- a/libs/hwui/Snapshot.h
+++ /dev/null
@@ -1,279 +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.
- */
-
-#pragma once
-
-#include <GLES2/gl2.h>
-#include <GLES2/gl2ext.h>
-
-#include <ui/Region.h>
-#include <utils/LinearAllocator.h>
-#include <utils/RefBase.h>
-
-#include <SkClipOp.h>
-#include <SkRegion.h>
-
-#include "ClipArea.h"
-#include "Layer.h"
-#include "Matrix.h"
-#include "Outline.h"
-#include "Rect.h"
-#include "utils/Macros.h"
-
-namespace android {
-namespace uirenderer {
-
-/**
- * Temporary structure holding information for a single outline clip.
- *
- * These structures are treated as immutable once created, and only exist for a single frame, which
- * is why they may only be allocated with a LinearAllocator.
- */
-class RoundRectClipState {
-public:
- static void* operator new(size_t size) = delete;
- static void* operator new(size_t size, LinearAllocator& allocator) {
- return allocator.alloc<RoundRectClipState>(size);
- }
-
- bool areaRequiresRoundRectClip(const Rect& rect) const {
- return rect.intersects(dangerRects[0]) || rect.intersects(dangerRects[1]) ||
- rect.intersects(dangerRects[2]) || rect.intersects(dangerRects[3]);
- }
-
- bool highPriority;
- Matrix4 matrix;
- Rect dangerRects[4];
- Rect innerRect;
- float radius;
-};
-
-/**
- * A snapshot holds information about the current state of the rendering
- * surface. A snapshot is usually created whenever the user calls save()
- * and discarded when the user calls restore(). Once a snapshot is created,
- * it can hold information for deferred rendering.
- *
- * Each snapshot has a link to a previous snapshot, indicating the previous
- * state of the renderer.
- */
-class Snapshot {
-public:
- Snapshot();
- Snapshot(Snapshot* s, int saveFlags);
-
- /**
- * Various flags set on ::flags.
- */
- enum Flags {
- /**
- * Indicates that the clip region was modified. When this
- * snapshot is restored so must the clip.
- */
- kFlagClipSet = 0x1,
- /**
- * Indicates that this snapshot was created when saving
- * a new layer.
- */
- kFlagIsLayer = 0x2,
- /**
- * Indicates that this snapshot is a special type of layer
- * backed by an FBO. This flag only makes sense when the
- * flag kFlagIsLayer is also set.
- *
- * Viewport has been modified to fit the new Fbo, and must be
- * restored when this snapshot is restored.
- */
- kFlagIsFboLayer = 0x4,
- };
-
- /**
- * Modifies the current clip with the new clip rectangle and
- * the specified operation. The specified rectangle is transformed
- * by this snapshot's trasnformation.
- */
- void clip(const Rect& localClip, SkClipOp op);
-
- /**
- * Modifies the current clip with the new clip rectangle and
- * the specified operation. The specified rectangle is considered
- * already transformed.
- */
- void clipTransformed(const Rect& r, SkClipOp op = SkClipOp::kIntersect);
-
- /**
- * Modifies the current clip with the specified path and operation.
- */
- void clipPath(const SkPath& path, SkClipOp op);
-
- /**
- * Sets the current clip.
- */
- void setClip(float left, float top, float right, float bottom);
-
- /**
- * Returns the current clip in local coordinates. The clip rect is
- * transformed by the inverse transform matrix.
- */
- ANDROID_API const Rect& getLocalClip();
-
- /**
- * Returns the current clip in render target coordinates.
- */
- const Rect& getRenderTargetClip() const { return mClipArea->getClipRect(); }
-
- /*
- * Accessor functions so that the clip area can stay private
- */
- bool clipIsEmpty() const { return mClipArea->isEmpty(); }
- const SkRegion& getClipRegion() const { return mClipArea->getClipRegion(); }
- bool clipIsSimple() const { return mClipArea->isSimple(); }
- const ClipArea& getClipArea() const { return *mClipArea; }
- ClipArea& mutateClipArea() { return *mClipArea; }
-
- WARN_UNUSED_RESULT const ClipBase* serializeIntersectedClip(
- LinearAllocator& allocator, const ClipBase* recordedClip,
- const Matrix4& recordedClipTransform);
- void applyClip(const ClipBase* clip, const Matrix4& transform);
-
- /**
- * Resets the clip to the specified rect.
- */
- void resetClip(float left, float top, float right, float bottom);
-
- void initializeViewport(int width, int height) {
- mViewportData.initialize(width, height);
- mClipAreaRoot.setViewportDimensions(width, height);
- }
-
- int getViewportWidth() const { return mViewportData.mWidth; }
- int getViewportHeight() const { return mViewportData.mHeight; }
- const Matrix4& getOrthoMatrix() const { return mViewportData.mOrthoMatrix; }
-
- const Vector3& getRelativeLightCenter() const { return mRelativeLightCenter; }
- void setRelativeLightCenter(const Vector3& lightCenter) { mRelativeLightCenter = lightCenter; }
-
- /**
- * Sets (and replaces) the current clipping outline
- *
- * If the current round rect clip is high priority, the incoming clip is ignored.
- */
- void setClippingRoundRect(LinearAllocator& allocator, const Rect& bounds, float radius,
- bool highPriority);
-
- /**
- * Sets (and replaces) the current projection mask
- */
- void setProjectionPathMask(const SkPath* path);
-
- /**
- * Indicates whether the current transform has perspective components.
- */
- bool hasPerspectiveTransform() const;
-
- /**
- * Dirty flags.
- */
- int flags;
-
- /**
- * Previous snapshot.
- */
- Snapshot* previous;
-
- /**
- * A pointer to the currently active layer.
- *
- * This snapshot does not own the layer, this pointer must not be freed.
- */
- Layer* layer;
-
- /**
- * Target FBO used for rendering. Set to 0 when rendering directly
- * into the framebuffer.
- */
- GLuint fbo;
-
- /**
- * Local transformation. Holds the current translation, scale and
- * rotation values.
- *
- * This is a reference to a matrix owned by this snapshot or another
- * snapshot. This pointer must not be freed. See ::mTransformRoot.
- */
- mat4* transform;
-
- /**
- * Current alpha value. This value is 1 by default, but may be set by a DisplayList which
- * has translucent rendering in a non-overlapping View. This value will be used by
- * the renderer to set the alpha in the current color being used for ensuing drawing
- * operations. The value is inherited by child snapshots because the same value should
- * be applied to descendants of the current DisplayList (for example, a TextView contains
- * the base alpha value which should be applied to the child DisplayLists used for drawing
- * the actual text).
- */
- float alpha;
-
- /**
- * Current clipping round rect.
- *
- * Points to data not owned by the snapshot, and may only be replaced by subsequent RR clips,
- * never modified.
- */
- const RoundRectClipState* roundRectClipState;
-
- /**
- * Current projection masking path - used exclusively to mask projected, tessellated circles.
- */
- const SkPath* projectionPathMask;
-
- void dump() const;
-
-private:
- struct ViewportData {
- ViewportData() : mWidth(0), mHeight(0) {}
- void initialize(int width, int height) {
- mWidth = width;
- mHeight = height;
- mOrthoMatrix.loadOrtho(0, width, height, 0, -1, 1);
- }
-
- /*
- * Width and height of current viewport.
- *
- * The viewport is always defined to be (0, 0, width, height).
- */
- int mWidth;
- int mHeight;
- /**
- * Contains the current orthographic, projection matrix.
- */
- mat4 mOrthoMatrix;
- };
-
- mat4 mTransformRoot;
-
- ClipArea mClipAreaRoot;
- ClipArea* mClipArea;
- Rect mLocalClip;
-
- ViewportData mViewportData;
- Vector3 mRelativeLightCenter;
-
-}; // class Snapshot
-
-}; // namespace uirenderer
-}; // namespace android
diff --git a/libs/hwui/Vertex.h b/libs/hwui/Vertex.h
index a6aae55b2ee8..f0912777e3d8 100644
--- a/libs/hwui/Vertex.h
+++ b/libs/hwui/Vertex.h
@@ -19,7 +19,6 @@
#include "Vector.h"
-#include "FloatColor.h"
#include "utils/Macros.h"
namespace android {
diff --git a/libs/hwui/hwui/Bitmap.cpp b/libs/hwui/hwui/Bitmap.cpp
index b04194f378bc..753557c2e120 100644
--- a/libs/hwui/hwui/Bitmap.cpp
+++ b/libs/hwui/hwui/Bitmap.cpp
@@ -224,6 +224,7 @@ Bitmap::~Bitmap() {
break;
case PixelStorageType::Heap:
free(mPixelStorage.heap.address);
+ mallopt(M_PURGE, 0);
break;
case PixelStorageType::Hardware:
auto buffer = mPixelStorage.hardware.buffer;
diff --git a/libs/hwui/tests/common/TestUtils.h b/libs/hwui/tests/common/TestUtils.h
index a00b8db3c617..c5db861d4f48 100644
--- a/libs/hwui/tests/common/TestUtils.h
+++ b/libs/hwui/tests/common/TestUtils.h
@@ -21,7 +21,6 @@
#include <Properties.h>
#include <Rect.h>
#include <RenderNode.h>
-#include <Snapshot.h>
#include <hwui/Bitmap.h>
#include <pipeline/skia/SkiaRecordingCanvas.h>
#include <private/hwui/DrawGlInfo.h>
@@ -141,14 +140,6 @@ public:
return true;
}
- static std::unique_ptr<Snapshot> makeSnapshot(const Matrix4& transform, const Rect& clip) {
- std::unique_ptr<Snapshot> snapshot(new Snapshot());
- // store clip first, so it isn't transformed
- snapshot->setClip(clip.left, clip.top, clip.right, clip.bottom);
- *(snapshot->transform) = transform;
- return snapshot;
- }
-
static sk_sp<Bitmap> createBitmap(int width, int height,
SkColorType colorType = kN32_SkColorType) {
SkImageInfo info = SkImageInfo::Make(width, height, colorType, kPremul_SkAlphaType);
diff --git a/libs/hwui/tests/microbench/DisplayListCanvasBench.cpp b/libs/hwui/tests/microbench/DisplayListCanvasBench.cpp
index 9388c2062736..70423a70157b 100644
--- a/libs/hwui/tests/microbench/DisplayListCanvasBench.cpp
+++ b/libs/hwui/tests/microbench/DisplayListCanvasBench.cpp
@@ -16,7 +16,6 @@
#include <benchmark/benchmark.h>
-#include "CanvasState.h"
#include "DisplayList.h"
#include "hwui/Canvas.h"
#include "pipeline/skia/SkiaDisplayList.h"
@@ -116,52 +115,6 @@ void BM_DisplayListCanvas_record_simpleBitmapView(benchmark::State& benchState)
}
BENCHMARK(BM_DisplayListCanvas_record_simpleBitmapView);
-class NullClient : public CanvasStateClient {
- void onViewportInitialized() override {}
- void onSnapshotRestored(const Snapshot& removed, const Snapshot& restored) {}
- GLuint getTargetFbo() const override { return 0; }
-};
-
-void BM_CanvasState_saverestore(benchmark::State& benchState) {
- NullClient client;
- CanvasState state(client);
- state.initializeSaveStack(100, 100, 0, 0, 100, 100, Vector3());
-
- while (benchState.KeepRunning()) {
- state.save(SaveFlags::MatrixClip);
- state.save(SaveFlags::MatrixClip);
- benchmark::DoNotOptimize(&state);
- state.restore();
- state.restore();
- }
-}
-BENCHMARK(BM_CanvasState_saverestore);
-
-void BM_CanvasState_init(benchmark::State& benchState) {
- NullClient client;
- CanvasState state(client);
- state.initializeSaveStack(100, 100, 0, 0, 100, 100, Vector3());
-
- while (benchState.KeepRunning()) {
- state.initializeSaveStack(100, 100, 0, 0, 100, 100, Vector3());
- benchmark::DoNotOptimize(&state);
- }
-}
-BENCHMARK(BM_CanvasState_init);
-
-void BM_CanvasState_translate(benchmark::State& benchState) {
- NullClient client;
- CanvasState state(client);
- state.initializeSaveStack(100, 100, 0, 0, 100, 100, Vector3());
-
- while (benchState.KeepRunning()) {
- state.translate(5, 5, 0);
- benchmark::DoNotOptimize(&state);
- state.translate(-5, -5, 0);
- }
-}
-BENCHMARK(BM_CanvasState_translate);
-
void BM_DisplayListCanvas_basicViewGroupDraw(benchmark::State& benchState) {
sp<RenderNode> child = TestUtils::createNode(50, 50, 100, 100, [](auto& props, auto& canvas) {
canvas.drawColor(0xFFFFFFFF, SkBlendMode::kSrcOver);
diff --git a/libs/hwui/tests/unit/CanvasStateTests.cpp b/libs/hwui/tests/unit/CanvasStateTests.cpp
deleted file mode 100644
index 4c03811b0c96..000000000000
--- a/libs/hwui/tests/unit/CanvasStateTests.cpp
+++ /dev/null
@@ -1,160 +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.
- */
-
-#include "CanvasState.h"
-
-#include "Matrix.h"
-#include "Rect.h"
-#include "hwui/Canvas.h"
-#include "utils/LinearAllocator.h"
-
-#include <SkClipOp.h>
-#include <SkPath.h>
-#include <gtest/gtest.h>
-
-namespace android {
-namespace uirenderer {
-
-class NullClient : public CanvasStateClient {
- void onViewportInitialized() override {}
- void onSnapshotRestored(const Snapshot& removed, const Snapshot& restored) {}
- GLuint getTargetFbo() const override { return 0; }
-};
-
-static NullClient sNullClient;
-
-static bool approxEqual(const Matrix4& a, const Matrix4& b) {
- for (int i = 0; i < 16; i++) {
- if (!MathUtils::areEqual(a[i], b[i])) {
- return false;
- }
- }
- return true;
-}
-
-TEST(CanvasState, gettersAndSetters) {
- CanvasState state(sNullClient);
- state.initializeSaveStack(200, 200, 0, 0, 200, 200, Vector3());
-
- ASSERT_EQ(state.getWidth(), 200);
- ASSERT_EQ(state.getHeight(), 200);
-
- Matrix4 simpleTranslate;
- simpleTranslate.loadTranslate(10, 20, 0);
- state.setMatrix(simpleTranslate);
-
- ASSERT_EQ(state.getRenderTargetClipBounds(), Rect(200, 200));
- ASSERT_EQ(state.getLocalClipBounds(), Rect(-10, -20, 190, 180));
- EXPECT_TRUE(approxEqual(*state.currentTransform(), simpleTranslate));
- EXPECT_TRUE(state.clipIsSimple());
-}
-
-TEST(CanvasState, simpleClipping) {
- CanvasState state(sNullClient);
- state.initializeSaveStack(200, 200, 0, 0, 200, 200, Vector3());
-
- state.clipRect(0, 0, 100, 100, SkClipOp::kIntersect);
- ASSERT_EQ(state.getRenderTargetClipBounds(), Rect(100, 100));
-
- state.clipRect(10, 10, 200, 200, SkClipOp::kIntersect);
- ASSERT_EQ(state.getRenderTargetClipBounds(), Rect(10, 10, 100, 100));
-
- state.clipRect(50, 50, 150, 150, SkClipOp::kReplace_deprecated);
- ASSERT_EQ(state.getRenderTargetClipBounds(), Rect(50, 50, 150, 150));
-}
-
-TEST(CanvasState, complexClipping) {
- CanvasState state(sNullClient);
- state.initializeSaveStack(200, 200, 0, 0, 200, 200, Vector3());
-
- state.save(SaveFlags::MatrixClip);
- {
- // rotated clip causes complex clip
- state.rotate(10);
- EXPECT_TRUE(state.clipIsSimple());
- state.clipRect(0, 0, 200, 200, SkClipOp::kIntersect);
- EXPECT_FALSE(state.clipIsSimple());
- }
- state.restore();
-
- state.save(SaveFlags::MatrixClip);
- {
- // subtracted clip causes complex clip
- EXPECT_TRUE(state.clipIsSimple());
- state.clipRect(50, 50, 150, 150, SkClipOp::kDifference);
- EXPECT_FALSE(state.clipIsSimple());
- }
- state.restore();
-
- state.save(SaveFlags::MatrixClip);
- {
- // complex path causes complex clip
- SkPath path;
- path.addOval(SkRect::MakeWH(200, 200));
- EXPECT_TRUE(state.clipIsSimple());
- state.clipPath(&path, SkClipOp::kDifference);
- EXPECT_FALSE(state.clipIsSimple());
- }
- state.restore();
-}
-
-TEST(CanvasState, saveAndRestore) {
- CanvasState state(sNullClient);
- state.initializeSaveStack(200, 200, 0, 0, 200, 200, Vector3());
-
- state.save(SaveFlags::Clip);
- {
- state.clipRect(0, 0, 10, 10, SkClipOp::kIntersect);
- ASSERT_EQ(state.getRenderTargetClipBounds(), Rect(10, 10));
- }
- state.restore();
- ASSERT_EQ(state.getRenderTargetClipBounds(), Rect(200, 200)); // verify restore
-
- Matrix4 simpleTranslate;
- simpleTranslate.loadTranslate(10, 10, 0);
- state.save(SaveFlags::Matrix);
- {
- state.translate(10, 10, 0);
- EXPECT_TRUE(approxEqual(*state.currentTransform(), simpleTranslate));
- }
- state.restore();
- EXPECT_FALSE(approxEqual(*state.currentTransform(), simpleTranslate));
-}
-
-TEST(CanvasState, saveAndRestoreButNotTooMuch) {
- CanvasState state(sNullClient);
- state.initializeSaveStack(200, 200, 0, 0, 200, 200, Vector3());
-
- state.save(SaveFlags::Matrix); // NOTE: clip not saved
- {
- state.clipRect(0, 0, 10, 10, SkClipOp::kIntersect);
- ASSERT_EQ(state.getRenderTargetClipBounds(), Rect(10, 10));
- }
- state.restore();
- ASSERT_EQ(state.getRenderTargetClipBounds(), Rect(10, 10)); // verify not restored
-
- Matrix4 simpleTranslate;
- simpleTranslate.loadTranslate(10, 10, 0);
- state.save(SaveFlags::Clip); // NOTE: matrix not saved
- {
- state.translate(10, 10, 0);
- EXPECT_TRUE(approxEqual(*state.currentTransform(), simpleTranslate));
- }
- state.restore();
- EXPECT_TRUE(approxEqual(*state.currentTransform(), simpleTranslate)); // verify not restored
-}
-}
-}
diff --git a/libs/hwui/tests/unit/ClipAreaTests.cpp b/libs/hwui/tests/unit/ClipAreaTests.cpp
deleted file mode 100644
index 450bb679a45f..000000000000
--- a/libs/hwui/tests/unit/ClipAreaTests.cpp
+++ /dev/null
@@ -1,353 +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.
- */
-
-#include <SkPath.h>
-#include <SkRegion.h>
-#include <gtest/gtest.h>
-
-#include "ClipArea.h"
-
-#include "Matrix.h"
-#include "Rect.h"
-#include "utils/LinearAllocator.h"
-
-namespace android {
-namespace uirenderer {
-
-static Rect kViewportBounds(2048, 2048);
-
-static ClipArea createClipArea() {
- ClipArea area;
- area.setViewportDimensions(kViewportBounds.getWidth(), kViewportBounds.getHeight());
- return area;
-}
-
-TEST(TransformedRectangle, basics) {
- Rect r(0, 0, 100, 100);
- Matrix4 minus90;
- minus90.loadRotate(-90);
- minus90.mapRect(r);
- Rect r2(20, 40, 120, 60);
-
- Matrix4 m90;
- m90.loadRotate(90);
- TransformedRectangle tr(r, m90);
- EXPECT_TRUE(tr.canSimplyIntersectWith(tr));
-
- Matrix4 m0;
- TransformedRectangle tr0(r2, m0);
- EXPECT_FALSE(tr.canSimplyIntersectWith(tr0));
-
- Matrix4 m45;
- m45.loadRotate(45);
- TransformedRectangle tr2(r, m45);
- EXPECT_FALSE(tr2.canSimplyIntersectWith(tr));
-}
-
-TEST(RectangleList, basics) {
- RectangleList list;
- EXPECT_TRUE(list.isEmpty());
-
- Rect r(0, 0, 100, 100);
- Matrix4 m45;
- m45.loadRotate(45);
- list.set(r, m45);
- EXPECT_FALSE(list.isEmpty());
-
- Rect r2(20, 20, 200, 200);
- list.intersectWith(r2, m45);
- EXPECT_FALSE(list.isEmpty());
- EXPECT_EQ(1, list.getTransformedRectanglesCount());
-
- Rect r3(20, 20, 200, 200);
- Matrix4 m30;
- m30.loadRotate(30);
- list.intersectWith(r2, m30);
- EXPECT_FALSE(list.isEmpty());
- EXPECT_EQ(2, list.getTransformedRectanglesCount());
-
- SkRegion clip;
- clip.setRect(0, 0, 2000, 2000);
- SkRegion rgn(list.convertToRegion(clip));
- EXPECT_FALSE(rgn.isEmpty());
-}
-
-TEST(ClipArea, basics) {
- ClipArea area(createClipArea());
- EXPECT_FALSE(area.isEmpty());
-}
-
-TEST(ClipArea, paths) {
- ClipArea area(createClipArea());
- SkPath path;
- SkScalar r = 100;
- path.addCircle(r, r, r);
- area.clipPathWithTransform(path, &Matrix4::identity(), SkRegion::kIntersect_Op);
- EXPECT_FALSE(area.isEmpty());
- EXPECT_FALSE(area.isSimple());
- EXPECT_FALSE(area.isRectangleList());
-
- Rect clipRect(area.getClipRect());
- Rect expected(0, 0, r * 2, r * 2);
- EXPECT_EQ(expected, clipRect);
- SkRegion clipRegion(area.getClipRegion());
- auto skRect(clipRegion.getBounds());
- Rect regionBounds;
- regionBounds.set(skRect);
- EXPECT_EQ(expected, regionBounds);
-}
-
-TEST(ClipArea, replaceNegative) {
- ClipArea area(createClipArea());
- area.setClip(0, 0, 100, 100);
-
- Rect expected(-50, -50, 50, 50);
- area.clipRectWithTransform(expected, &Matrix4::identity(), SkRegion::kReplace_Op);
- EXPECT_EQ(expected, area.getClipRect());
-}
-
-TEST(ClipArea, serializeClip) {
- ClipArea area(createClipArea());
- LinearAllocator allocator;
-
- // unset clip
- EXPECT_EQ(nullptr, area.serializeClip(allocator));
-
- // rect clip
- area.setClip(0, 0, 200, 200);
- {
- auto serializedClip = area.serializeClip(allocator);
- ASSERT_NE(nullptr, serializedClip);
- ASSERT_EQ(ClipMode::Rectangle, serializedClip->mode);
- ASSERT_FALSE(serializedClip->intersectWithRoot) << "No replace, so no intersectWithRoot";
- EXPECT_EQ(Rect(200, 200), serializedClip->rect);
- EXPECT_EQ(serializedClip, area.serializeClip(allocator))
- << "Requery of clip on unmodified ClipArea must return same pointer.";
- }
-
- // rect list
- Matrix4 rotate;
- rotate.loadRotate(5.0f);
- area.clipRectWithTransform(Rect(50, 50, 150, 150), &rotate, SkRegion::kIntersect_Op);
- {
- auto serializedClip = area.serializeClip(allocator);
- ASSERT_NE(nullptr, serializedClip);
- ASSERT_EQ(ClipMode::RectangleList, serializedClip->mode);
- ASSERT_FALSE(serializedClip->intersectWithRoot) << "No replace, so no intersectWithRoot";
- auto clipRectList = reinterpret_cast<const ClipRectList*>(serializedClip);
- EXPECT_EQ(2, clipRectList->rectList.getTransformedRectanglesCount());
- EXPECT_EQ(Rect(37, 54, 145, 163), clipRectList->rect);
- EXPECT_EQ(serializedClip, area.serializeClip(allocator))
- << "Requery of clip on unmodified ClipArea must return same pointer.";
- }
-
- // region
- SkPath circlePath;
- circlePath.addCircle(100, 100, 100);
- area.clipPathWithTransform(circlePath, &Matrix4::identity(), SkRegion::kReplace_Op);
- {
- auto serializedClip = area.serializeClip(allocator);
- ASSERT_NE(nullptr, serializedClip);
- ASSERT_EQ(ClipMode::Region, serializedClip->mode);
- ASSERT_TRUE(serializedClip->intersectWithRoot) << "Replace op, so expect intersectWithRoot";
- auto clipRegion = reinterpret_cast<const ClipRegion*>(serializedClip);
- EXPECT_EQ(SkIRect::MakeWH(200, 200), clipRegion->region.getBounds())
- << "Clip region should be 200x200";
- EXPECT_EQ(Rect(200, 200), clipRegion->rect);
- EXPECT_EQ(serializedClip, area.serializeClip(allocator))
- << "Requery of clip on unmodified ClipArea must return same pointer.";
- }
-}
-
-TEST(ClipArea, serializeClip_pathIntersectWithRoot) {
- ClipArea area(createClipArea());
- LinearAllocator allocator;
- SkPath circlePath;
- circlePath.addCircle(100, 100, 100);
- area.clipPathWithTransform(circlePath, &Matrix4::identity(), SkRegion::kIntersect_Op);
-
- auto serializedClip = area.serializeClip(allocator);
- ASSERT_NE(nullptr, serializedClip);
- EXPECT_FALSE(serializedClip->intersectWithRoot) << "No replace, so no intersectWithRoot";
-}
-
-TEST(ClipArea, serializeIntersectedClip) {
- ClipArea area(createClipArea());
- LinearAllocator allocator;
-
- // simple state;
- EXPECT_EQ(nullptr, area.serializeIntersectedClip(allocator, nullptr, Matrix4::identity()));
- area.setClip(0, 0, 200, 200);
- {
- auto origRectClip = area.serializeClip(allocator);
- ASSERT_NE(nullptr, origRectClip);
- EXPECT_EQ(origRectClip,
- area.serializeIntersectedClip(allocator, nullptr, Matrix4::identity()));
- }
-
- // rect
- {
- ClipRect recordedClip(Rect(100, 100));
- Matrix4 translateScale;
- translateScale.loadTranslate(100, 100, 0);
- translateScale.scale(2, 3, 1);
- auto resolvedClip = area.serializeIntersectedClip(allocator, &recordedClip, translateScale);
- ASSERT_NE(nullptr, resolvedClip);
- ASSERT_EQ(ClipMode::Rectangle, resolvedClip->mode);
- EXPECT_EQ(Rect(100, 100, 200, 200), resolvedClip->rect);
-
- EXPECT_EQ(resolvedClip,
- area.serializeIntersectedClip(allocator, &recordedClip, translateScale))
- << "Must return previous serialization, since input is same";
-
- ClipRect recordedClip2(Rect(100, 100));
- EXPECT_NE(resolvedClip,
- area.serializeIntersectedClip(allocator, &recordedClip2, translateScale))
- << "Shouldn't return previous serialization, since matrix location is different";
- }
-
- // rect list
- Matrix4 rotate;
- rotate.loadRotate(2.0f);
- area.clipRectWithTransform(Rect(200, 200), &rotate, SkRegion::kIntersect_Op);
- {
- ClipRect recordedClip(Rect(100, 100));
- auto resolvedClip =
- area.serializeIntersectedClip(allocator, &recordedClip, Matrix4::identity());
- ASSERT_NE(nullptr, resolvedClip);
- ASSERT_EQ(ClipMode::RectangleList, resolvedClip->mode);
- auto clipRectList = reinterpret_cast<const ClipRectList*>(resolvedClip);
- EXPECT_EQ(2, clipRectList->rectList.getTransformedRectanglesCount());
- }
-
- // region
- SkPath circlePath;
- circlePath.addCircle(100, 100, 100);
- area.clipPathWithTransform(circlePath, &Matrix4::identity(), SkRegion::kReplace_Op);
- {
- SkPath ovalPath;
- ovalPath.addOval(SkRect::MakeLTRB(50, 0, 150, 200));
-
- ClipRegion recordedClip;
- recordedClip.region.setPath(ovalPath, SkRegion(SkIRect::MakeWH(200, 200)));
- recordedClip.rect = Rect(200, 200);
-
- Matrix4 translate10x20;
- translate10x20.loadTranslate(10, 20, 0);
- auto resolvedClip = area.serializeIntersectedClip(
- allocator, &recordedClip,
- translate10x20); // Note: only translate for now, others not handled correctly
- ASSERT_NE(nullptr, resolvedClip);
- ASSERT_EQ(ClipMode::Region, resolvedClip->mode);
- auto clipRegion = reinterpret_cast<const ClipRegion*>(resolvedClip);
- EXPECT_EQ(SkIRect::MakeLTRB(60, 20, 160, 200), clipRegion->region.getBounds());
- }
-}
-
-TEST(ClipArea, serializeIntersectedClip_snap) {
- ClipArea area(createClipArea());
- area.setClip(100.2, 100.4, 500.6, 500.8);
- LinearAllocator allocator;
-
- {
- // no recorded clip case
- auto resolvedClip = area.serializeIntersectedClip(allocator, nullptr, Matrix4::identity());
- EXPECT_EQ(Rect(100, 100, 501, 501), resolvedClip->rect);
- }
- {
- // recorded clip case
- ClipRect recordedClip(Rect(100.12, 100.74));
- Matrix4 translateScale;
- translateScale.loadTranslate(100, 100, 0);
- translateScale.scale(2, 3,
- 1); // recorded clip will have non-int coords, even after transform
- auto resolvedClip = area.serializeIntersectedClip(allocator, &recordedClip, translateScale);
- ASSERT_NE(nullptr, resolvedClip);
- EXPECT_EQ(ClipMode::Rectangle, resolvedClip->mode);
- EXPECT_EQ(Rect(100, 100, 300, 402), resolvedClip->rect);
- }
-}
-
-TEST(ClipArea, serializeIntersectedClip_scale) {
- ClipArea area(createClipArea());
- area.setClip(0, 0, 400, 400);
- LinearAllocator allocator;
-
- SkPath circlePath;
- circlePath.addCircle(50, 50, 50);
-
- ClipRegion recordedClip;
- recordedClip.region.setPath(circlePath, SkRegion(SkIRect::MakeWH(100, 100)));
- recordedClip.rect = Rect(100, 100);
-
- Matrix4 translateScale;
- translateScale.loadTranslate(100, 100, 0);
- translateScale.scale(2, 2, 1);
- auto resolvedClip = area.serializeIntersectedClip(allocator, &recordedClip, translateScale);
-
- ASSERT_NE(nullptr, resolvedClip);
- EXPECT_EQ(ClipMode::Region, resolvedClip->mode);
- EXPECT_EQ(Rect(100, 100, 300, 300), resolvedClip->rect);
- auto clipRegion = reinterpret_cast<const ClipRegion*>(resolvedClip);
- EXPECT_EQ(SkIRect::MakeLTRB(100, 100, 300, 300), clipRegion->region.getBounds());
-}
-
-TEST(ClipArea, applyTransformToRegion_identity) {
- SkRegion region(SkIRect::MakeLTRB(1, 2, 3, 4));
- ClipArea::applyTransformToRegion(Matrix4::identity(), &region);
- EXPECT_TRUE(region.isRect());
- EXPECT_EQ(SkIRect::MakeLTRB(1, 2, 3, 4), region.getBounds());
-}
-
-TEST(ClipArea, applyTransformToRegion_translate) {
- SkRegion region(SkIRect::MakeLTRB(1, 2, 3, 4));
- Matrix4 transform;
- transform.loadTranslate(10, 20, 0);
- ClipArea::applyTransformToRegion(transform, &region);
- EXPECT_TRUE(region.isRect());
- EXPECT_EQ(SkIRect::MakeLTRB(11, 22, 13, 24), region.getBounds());
-}
-
-TEST(ClipArea, applyTransformToRegion_scale) {
- SkRegion region(SkIRect::MakeLTRB(1, 2, 3, 4));
- Matrix4 transform;
- transform.loadScale(2, 3, 1);
- ClipArea::applyTransformToRegion(transform, &region);
- EXPECT_TRUE(region.isRect());
- EXPECT_EQ(SkIRect::MakeLTRB(2, 6, 6, 12), region.getBounds());
-}
-
-TEST(ClipArea, applyTransformToRegion_translateScale) {
- SkRegion region(SkIRect::MakeLTRB(1, 2, 3, 4));
- Matrix4 transform;
- transform.translate(10, 20);
- transform.scale(2, 3, 1);
- ClipArea::applyTransformToRegion(transform, &region);
- EXPECT_TRUE(region.isRect());
- EXPECT_EQ(SkIRect::MakeLTRB(12, 26, 16, 32), region.getBounds());
-}
-
-TEST(ClipArea, applyTransformToRegion_rotate90) {
- SkRegion region(SkIRect::MakeLTRB(1, 2, 3, 4));
- Matrix4 transform;
- transform.loadRotate(90);
- ClipArea::applyTransformToRegion(transform, &region);
- EXPECT_TRUE(region.isRect());
- EXPECT_EQ(SkIRect::MakeLTRB(-4, 1, -2, 3), region.getBounds());
-}
-
-} // namespace uirenderer
-} // namespace android
diff --git a/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp b/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp
index 2926ef3a2d95..2c73940b9b9c 100644
--- a/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp
+++ b/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp
@@ -32,6 +32,7 @@
#include "pipeline/skia/SkiaRecordingCanvas.h"
#include "renderthread/CanvasContext.h"
#include "tests/common/TestUtils.h"
+#include "utils/Color.h"
using namespace android;
using namespace android::uirenderer;
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/SnapshotTests.cpp b/libs/hwui/tests/unit/SnapshotTests.cpp
deleted file mode 100644
index 9d673c82d4d0..000000000000
--- a/libs/hwui/tests/unit/SnapshotTests.cpp
+++ /dev/null
@@ -1,74 +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.
- */
-
-#include <gtest/gtest.h>
-
-#include <Snapshot.h>
-
-#include <tests/common/TestUtils.h>
-
-using namespace android::uirenderer;
-
-TEST(Snapshot, serializeIntersectedClip) {
- auto actualRoot = TestUtils::makeSnapshot(Matrix4::identity(), Rect(0, 0, 100, 100));
- auto root = TestUtils::makeSnapshot(Matrix4::identity(), Rect(10, 10, 90, 90));
- auto child = TestUtils::makeSnapshot(Matrix4::identity(), Rect(50, 50, 90, 90));
- root->previous = actualRoot.get();
- child->previous = root.get();
-
- LinearAllocator allocator;
- ClipRect rect(Rect(0, 0, 75, 75));
- {
- auto intersectWithChild =
- child->serializeIntersectedClip(allocator, &rect, Matrix4::identity());
- ASSERT_NE(nullptr, intersectWithChild);
- EXPECT_EQ(Rect(50, 50, 75, 75), intersectWithChild->rect) << "Expect intersect with child";
- }
-
- rect.intersectWithRoot = true;
- {
- auto intersectWithRoot =
- child->serializeIntersectedClip(allocator, &rect, Matrix4::identity());
- ASSERT_NE(nullptr, intersectWithRoot);
- EXPECT_EQ(Rect(10, 10, 75, 75), intersectWithRoot->rect) << "Expect intersect with root";
- }
-}
-
-TEST(Snapshot, applyClip) {
- auto actualRoot = TestUtils::makeSnapshot(Matrix4::identity(), Rect(0, 0, 100, 100));
- auto root = TestUtils::makeSnapshot(Matrix4::identity(), Rect(10, 10, 90, 90));
- root->previous = actualRoot.get();
-
- ClipRect rect(Rect(0, 0, 75, 75));
- {
- auto child = TestUtils::makeSnapshot(Matrix4::identity(), Rect(50, 50, 90, 90));
- child->previous = root.get();
- child->applyClip(&rect, Matrix4::identity());
-
- EXPECT_TRUE(child->getClipArea().isSimple());
- EXPECT_EQ(Rect(50, 50, 75, 75), child->getRenderTargetClip());
- }
-
- {
- rect.intersectWithRoot = true;
- auto child = TestUtils::makeSnapshot(Matrix4::identity(), Rect(50, 50, 90, 90));
- child->previous = root.get();
- child->applyClip(&rect, Matrix4::identity());
-
- EXPECT_TRUE(child->getClipArea().isSimple());
- EXPECT_EQ(Rect(10, 10, 75, 75), child->getRenderTargetClip());
- }
-}
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index fac4351bb71c..b37808f2279e 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -2397,10 +2397,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/OWNERS b/media/OWNERS
index 1ae2a7bd8dee..0abf9aeb6101 100644
--- a/media/OWNERS
+++ b/media/OWNERS
@@ -9,4 +9,4 @@ sungsoo@google.com
wjia@google.com
jaewan@google.com
chz@google.com
-
+dwkang@google.com
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index e4ec1e361713..ba6205274131 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -3960,18 +3960,31 @@ public class AudioManager {
}
/**
- * Indicate Hearing Aid connection state change.
+ * Indicate Hearing Aid connection state change and eventually suppress
+ * the {@link AudioManager.ACTION_AUDIO_BECOMING_NOISY} intent.
* @param device Bluetooth device connected/disconnected
* @param state new connection state (BluetoothProfile.STATE_xxx)
+ * @param musicDevice Default get system volume for the connecting device.
+ * (either {@link android.bluetooth.BluetoothProfile.hearingaid} or
+ * {@link android.bluetooth.BluetoothProfile.HEARING_AID})
+ * @param suppressNoisyIntent if true the
+ * {@link AudioManager.ACTION_AUDIO_BECOMING_NOISY} intent will not be sent.
+ * @return a delay in ms that the caller should wait before broadcasting
+ * BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED intent.
* {@hide}
*/
- public void setHearingAidDeviceConnectionState(BluetoothDevice device, int state) {
+ public int setBluetoothHearingAidDeviceConnectionState(
+ BluetoothDevice device, int state, boolean suppressNoisyIntent,
+ int musicDevice) {
final IAudioService service = getService();
+ int delay = 0;
try {
- service.setHearingAidDeviceConnectionState(device, state);
+ delay = service.setBluetoothHearingAidDeviceConnectionState(device,
+ state, suppressNoisyIntent, musicDevice);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
+ return delay;
}
/**
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/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index 569db16c312e..abd64119de61 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -151,8 +151,6 @@ interface IAudioService {
void setWiredDeviceConnectionState(int type, int state, String address, String name,
String caller);
- void setHearingAidDeviceConnectionState(in BluetoothDevice device, int state);
-
int setBluetoothA2dpDeviceConnectionState(in BluetoothDevice device, int state, int profile);
void handleBluetoothA2dpDeviceConfigChange(in BluetoothDevice device);
@@ -210,6 +208,9 @@ interface IAudioService {
oneway void playerHasOpPlayAudio(in int piid, in boolean hasOpPlayAudio);
+ int setBluetoothHearingAidDeviceConnectionState(in BluetoothDevice device,
+ int state, boolean suppressNoisyIntent, int musicDevice);
+
int setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(in BluetoothDevice device,
int state, int profile, boolean suppressNoisyIntent, int a2dpVolume);
diff --git a/media/java/android/media/MediaDrm.java b/media/java/android/media/MediaDrm.java
index 6d122d77a999..ee12b913765a 100644
--- a/media/java/android/media/MediaDrm.java
+++ b/media/java/android/media/MediaDrm.java
@@ -1192,15 +1192,17 @@ public final class MediaDrm implements AutoCloseable {
public static final int SECURITY_LEVEL_HW_SECURE_ALL = 5;
/**
- * The maximum security level supported by the device. This is the default
- * security level when a session is opened.
+ * Indicates that the maximum security level supported by the device should
+ * be used when opening a session. This is the default security level
+ * selected when a session is opened.
* @hide
*/
public static final int SECURITY_LEVEL_MAX = 6;
/**
- * The maximum security level supported by the device. This is the default
- * security level when a session is opened.
+ * Returns a value that may be passed as a parameter to {@link #openSession(int)}
+ * requesting that the session be opened at the maximum security level of
+ * the device.
*/
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 db6da8c590c3..e94413cd90fc 100644
--- a/media/java/android/media/MediaPlayer2.java
+++ b/media/java/android/media/MediaPlayer2.java
@@ -37,7 +37,6 @@ import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
-import java.util.Set;
import java.util.UUID;
import java.util.concurrent.Executor;
@@ -1025,50 +1024,6 @@ public abstract class MediaPlayer2 implements AutoCloseable
public abstract MediaTimestamp getTimestamp();
/**
- * Gets the media metadata.
- *
- * @param update_only controls whether the full set of available
- * metadata is returned or just the set that changed since the
- * last call. See {@see #METADATA_UPDATE_ONLY} and {@see
- * #METADATA_ALL}.
- *
- * @param apply_filter if true only metadata that matches the
- * filter is returned. See {@see #APPLY_METADATA_FILTER} and {@see
- * #BYPASS_METADATA_FILTER}.
- *
- * @return The metadata, possibly empty. null if an error occured.
- // FIXME: unhide.
- * {@hide}
- */
- public Metadata getMetadata(final boolean update_only,
- final boolean apply_filter) {
- return null;
- }
-
- /**
- * Set a filter for the metadata update notification and update
- * retrieval. The caller provides 2 set of metadata keys, allowed
- * and blocked. The blocked set always takes precedence over the
- * allowed one.
- * Metadata.MATCH_ALL and Metadata.MATCH_NONE are 2 sets available as
- * shorthands to allow/block all or no metadata.
- *
- * By default, there is no filter set.
- *
- * @param allow Is the set of metadata the client is interested
- * in receiving new notifications for.
- * @param block Is the set of metadata the client is not interested
- * in receiving new notifications for.
- * @return The call status code.
- *
- // FIXME: unhide.
- * {@hide}
- */
- public int setMetadataFilter(Set<Integer> allow, Set<Integer> block) {
- return 0;
- }
-
- /**
* Resets the MediaPlayer2 to its uninitialized state. After calling
* this method, you will have to initialize it again by setting the
* data source and calling prepare().
@@ -2266,38 +2221,4 @@ public abstract class MediaPlayer2 implements AutoCloseable
public static final String ERROR_CODE = "android.media.mediaplayer.errcode";
}
-
- /**
- Constant to retrieve only the new metadata since the last
- call.
- // FIXME: unhide.
- // FIXME: add link to getMetadata(boolean, boolean)
- {@hide}
- */
- public static final boolean METADATA_UPDATE_ONLY = true;
-
- /**
- Constant to retrieve all the metadata.
- // FIXME: unhide.
- // FIXME: add link to getMetadata(boolean, boolean)
- {@hide}
- */
- public static final boolean METADATA_ALL = false;
-
- /**
- Constant to enable the metadata filter during retrieval.
- // FIXME: unhide.
- // FIXME: add link to getMetadata(boolean, boolean)
- {@hide}
- */
- public static final boolean APPLY_METADATA_FILTER = true;
-
- /**
- Constant to disable the metadata filter during retrieval.
- // FIXME: unhide.
- // FIXME: add link to getMetadata(boolean, boolean)
- {@hide}
- */
- public static final boolean BYPASS_METADATA_FILTER = false;
-
}
diff --git a/media/java/android/media/MediaPlayer2Impl.java b/media/java/android/media/MediaPlayer2Impl.java
index 0e5cbe4e20b7..71df7dce5ea2 100644
--- a/media/java/android/media/MediaPlayer2Impl.java
+++ b/media/java/android/media/MediaPlayer2Impl.java
@@ -25,7 +25,6 @@ import android.content.Context;
import android.content.res.AssetFileDescriptor;
import android.graphics.SurfaceTexture;
import android.graphics.Rect;
-import android.media.MediaPlayer2Proto;
import android.media.MediaPlayer2Proto.PlayerMessage;
import android.media.MediaPlayer2Proto.Value;
import android.net.Uri;
@@ -461,12 +460,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.
@@ -683,7 +682,9 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
case DataSourceDesc.TYPE_CALLBACK:
handleDataSource(isCurrent,
srcId,
- dsd.getMedia2DataSource());
+ dsd.getMedia2DataSource(),
+ dsd.getStartPosition(),
+ dsd.getEndPosition());
break;
case DataSourceDesc.TYPE_FD:
@@ -691,7 +692,9 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
srcId,
dsd.getFileDescriptor(),
dsd.getFileDescriptorOffset(),
- dsd.getFileDescriptorLength());
+ dsd.getFileDescriptorLength(),
+ dsd.getStartPosition(),
+ dsd.getEndPosition());
break;
case DataSourceDesc.TYPE_URI:
@@ -700,7 +703,9 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
dsd.getUriContext(),
dsd.getUri(),
dsd.getUriHeaders(),
- dsd.getUriCookies());
+ dsd.getUriCookies(),
+ dsd.getStartPosition(),
+ dsd.getEndPosition());
break;
default:
@@ -730,67 +735,77 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
private void handleDataSource(
boolean isCurrent, long srcId,
@NonNull Context context, @NonNull Uri uri,
- @Nullable Map<String, String> headers, @Nullable List<HttpCookie> cookies)
+ @Nullable Map<String, String> headers, @Nullable List<HttpCookie> cookies,
+ long startPos, long endPos)
throws IOException {
- // The context and URI usually belong to the calling user. Get a resolver for that user
- // and strip out the userId from the URI if present.
+ // The context and URI usually belong to the calling user. Get a resolver for that user.
final ContentResolver resolver = context.getContentResolver();
final String scheme = uri.getScheme();
- final String authority = ContentProvider.getAuthorityWithoutUserId(uri.getAuthority());
if (ContentResolver.SCHEME_FILE.equals(scheme)) {
- handleDataSource(isCurrent, srcId, uri.getPath(), null, null);
+ handleDataSource(isCurrent, srcId, uri.getPath(), null, null, startPos, endPos);
return;
}
- if (ContentResolver.SCHEME_CONTENT.equals(scheme)
- && Settings.AUTHORITY.equals(authority)) {
- // Try cached ringtone first since the actual provider may not be
- // encryption aware, or it may be stored on CE media storage
- final int type = RingtoneManager.getDefaultType(uri);
- final Uri cacheUri = RingtoneManager.getCacheForType(type, context.getUserId());
- final Uri actualUri = RingtoneManager.getActualDefaultRingtoneUri(context, type);
- if (attemptDataSource(isCurrent, srcId, resolver, cacheUri)) {
- return;
- }
- if (attemptDataSource(isCurrent, srcId, resolver, actualUri)) {
- return;
+ final int ringToneType = RingtoneManager.getDefaultType(uri);
+ try {
+ AssetFileDescriptor afd;
+ // Try requested Uri locally first
+ if (ContentResolver.SCHEME_CONTENT.equals(scheme) && ringToneType != -1) {
+ afd = RingtoneManager.openDefaultRingtoneUri(context, uri);
+ if (attemptDataSource(isCurrent, srcId, afd, startPos, endPos)) {
+ return;
+ }
+ final Uri actualUri = RingtoneManager.getActualDefaultRingtoneUri(
+ context, ringToneType);
+ afd = resolver.openAssetFileDescriptor(actualUri, "r");
+ } else {
+ afd = resolver.openAssetFileDescriptor(uri, "r");
}
- handleDataSource(isCurrent, srcId, uri.toString(), headers, cookies);
- } else {
- // Try requested Uri locally first, or fallback to media server
- if (attemptDataSource(isCurrent, srcId, resolver, uri)) {
+ if (attemptDataSource(isCurrent, srcId, afd, startPos, endPos)) {
return;
}
- handleDataSource(isCurrent, srcId, uri.toString(), headers, cookies);
+ } catch (NullPointerException | SecurityException | IOException ex) {
+ Log.w(TAG, "Couldn't open " + uri + ": " + ex);
+ // Fallback to media server
}
+ handleDataSource(isCurrent, srcId, uri.toString(), headers, cookies, startPos, endPos);
}
- private boolean attemptDataSource(
- boolean isCurrent, long srcId, ContentResolver resolver, Uri uri) {
- try (AssetFileDescriptor afd = resolver.openAssetFileDescriptor(uri, "r")) {
+ private boolean attemptDataSource(boolean isCurrent, long srcId, AssetFileDescriptor afd,
+ long startPos, long endPos) throws IOException {
+ try {
if (afd.getDeclaredLength() < 0) {
handleDataSource(isCurrent,
- srcId,
- afd.getFileDescriptor(),
- 0,
- DataSourceDesc.LONG_MAX);
+ srcId,
+ afd.getFileDescriptor(),
+ 0,
+ DataSourceDesc.LONG_MAX,
+ startPos,
+ endPos);
} else {
handleDataSource(isCurrent,
- srcId,
- afd.getFileDescriptor(),
- afd.getStartOffset(),
- afd.getDeclaredLength());
+ srcId,
+ afd.getFileDescriptor(),
+ afd.getStartOffset(),
+ afd.getDeclaredLength(),
+ startPos,
+ endPos);
}
return true;
} catch (NullPointerException | SecurityException | IOException ex) {
- Log.w(TAG, "Couldn't open " + uri + ": " + ex);
+ Log.w(TAG, "Couldn't open srcId:" + srcId + ": " + ex);
return false;
+ } finally {
+ if (afd != null) {
+ afd.close();
+ }
}
}
private void handleDataSource(
boolean isCurrent, long srcId,
- String path, Map<String, String> headers, List<HttpCookie> cookies)
+ String path, Map<String, String> headers, List<HttpCookie> cookies,
+ long startPos, long endPos)
throws IOException {
String[] keys = null;
String[] values = null;
@@ -806,11 +821,12 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
++i;
}
}
- handleDataSource(isCurrent, srcId, path, keys, values, cookies);
+ handleDataSource(isCurrent, srcId, path, keys, values, cookies, startPos, endPos);
}
private void handleDataSource(boolean isCurrent, long srcId,
- String path, String[] keys, String[] values, List<HttpCookie> cookies)
+ String path, String[] keys, String[] values, List<HttpCookie> cookies,
+ long startPos, long endPos)
throws IOException {
final Uri uri = Uri.parse(path);
final String scheme = uri.getScheme();
@@ -824,7 +840,9 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
Media2HTTPService.createHTTPService(path, cookies),
path,
keys,
- values);
+ values,
+ startPos,
+ endPos);
return;
}
@@ -832,7 +850,7 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
if (file.exists()) {
FileInputStream is = new FileInputStream(file);
FileDescriptor fd = is.getFD();
- handleDataSource(isCurrent, srcId, fd, 0, DataSourceDesc.LONG_MAX);
+ handleDataSource(isCurrent, srcId, fd, 0, DataSourceDesc.LONG_MAX, startPos, endPos);
is.close();
} else {
throw new IOException("handleDataSource failed.");
@@ -841,7 +859,8 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
private native void nativeHandleDataSourceUrl(
boolean isCurrent, long srcId,
- Media2HTTPService httpService, String path, String[] keys, String[] values)
+ Media2HTTPService httpService, String path, String[] keys, String[] values,
+ long startPos, long endPos)
throws IOException;
/**
@@ -855,23 +874,27 @@ public final class MediaPlayer2Impl extends MediaPlayer2 {
*/
private void handleDataSource(
boolean isCurrent, long srcId,
- FileDescriptor fd, long offset, long length) throws IOException {
- nativeHandleDataSourceFD(isCurrent, srcId, fd, offset, length);
+ FileDescriptor fd, long offset, long length,
+ long startPos, long endPos) throws IOException {
+ nativeHandleDataSourceFD(isCurrent, srcId, fd, offset, length, startPos, endPos);
}
private native void nativeHandleDataSourceFD(boolean isCurrent, long srcId,
- FileDescriptor fd, long offset, long length) throws IOException;
+ FileDescriptor fd, long offset, long length,
+ long startPos, long endPos) throws IOException;
/**
* @throws IllegalStateException if it is called in an invalid state
* @throws IllegalArgumentException if dataSource is not a valid Media2DataSource
*/
- private void handleDataSource(boolean isCurrent, long srcId, Media2DataSource dataSource) {
- nativeHandleDataSourceCallback(isCurrent, srcId, dataSource);
+ private void handleDataSource(boolean isCurrent, long srcId, Media2DataSource dataSource,
+ long startPos, long endPos) {
+ nativeHandleDataSourceCallback(isCurrent, srcId, dataSource, startPos, endPos);
}
private native void nativeHandleDataSourceCallback(
- boolean isCurrent, long srcId, Media2DataSource dataSource);
+ boolean isCurrent, long srcId, Media2DataSource dataSource,
+ long startPos, long endPos);
/**
* @return true if there is a next data source, false otherwise.
@@ -3620,6 +3643,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/RingtoneManager.java b/media/java/android/media/RingtoneManager.java
index 66feb1ddf272..8664aa12343b 100644
--- a/media/java/android/media/RingtoneManager.java
+++ b/media/java/android/media/RingtoneManager.java
@@ -31,6 +31,7 @@ import android.content.Context;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.UserInfo;
+import android.content.res.AssetFileDescriptor;
import android.database.Cursor;
import android.media.MediaScannerConnection.MediaScannerConnectionClient;
import android.net.Uri;
@@ -1128,6 +1129,38 @@ public class RingtoneManager {
}
/**
+ * Opens a raw file descriptor to read the data under the given default URI.
+ *
+ * @param context the Context to use when resolving the Uri.
+ * @param uri The desired default URI to open.
+ * @return a new AssetFileDescriptor pointing to the file. You own this descriptor
+ * and are responsible for closing it when done. This value may be {@code null}.
+ * @throws FileNotFoundException if the provided URI could not be opened.
+ * @see #getDefaultUri
+ */
+ public static AssetFileDescriptor openDefaultRingtoneUri(
+ @NonNull Context context, @NonNull Uri uri) throws FileNotFoundException {
+ // Try cached ringtone first since the actual provider may not be
+ // encryption aware, or it may be stored on CE media storage
+ final int type = getDefaultType(uri);
+ final Uri cacheUri = getCacheForType(type, context.getUserId());
+ final Uri actualUri = getActualDefaultRingtoneUri(context, type);
+ final ContentResolver resolver = context.getContentResolver();
+
+ AssetFileDescriptor afd = null;
+ if (cacheUri != null) {
+ afd = resolver.openAssetFileDescriptor(cacheUri, "r");
+ if (afd != null) {
+ return afd;
+ }
+ }
+ if (actualUri != null) {
+ afd = resolver.openAssetFileDescriptor(actualUri, "r");
+ }
+ return afd;
+ }
+
+ /**
* Creates a {@link android.media.MediaScannerConnection} to scan a ringtone file and add its
* information to the internal database.
*
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 b52da362beff..61c28eddfeac 100644
--- a/media/jni/android_media_MediaPlayer2.cpp
+++ b/media/jni/android_media_MediaPlayer2.cpp
@@ -283,7 +283,8 @@ static void process_media_player_call(
static void
android_media_MediaPlayer2_handleDataSourceUrl(
JNIEnv *env, jobject thiz, jboolean isCurrent, jlong srcId,
- jobject httpServiceObj, jstring path, jobjectArray keys, jobjectArray values) {
+ jobject httpServiceObj, jstring path, jobjectArray keys, jobjectArray values,
+ jlong startPos, jlong endPos) {
sp<MediaPlayer2> mp = getMediaPlayer(env, thiz);
if (mp == NULL) {
@@ -300,7 +301,8 @@ android_media_MediaPlayer2_handleDataSourceUrl(
if (tmp == NULL) { // Out of memory
return;
}
- ALOGV("handleDataSourceUrl: path %s, srcId %lld", tmp, (long long)srcId);
+ ALOGV("handleDataSourceUrl: path %s, srcId %lld, start %lld, end %lld",
+ tmp, (long long)srcId, (long long)startPos, (long long)endPos);
if (strncmp(tmp, "content://", 10) == 0) {
ALOGE("handleDataSourceUrl: content scheme is not supported in native code");
@@ -313,6 +315,8 @@ android_media_MediaPlayer2_handleDataSourceUrl(
dsd->mId = srcId;
dsd->mType = DataSourceDesc::TYPE_URL;
dsd->mUrl = tmp;
+ dsd->mStartPositionMs = startPos;
+ dsd->mEndPositionMs = endPos;
env->ReleaseStringUTFChars(path, tmp);
tmp = NULL;
@@ -341,9 +345,9 @@ android_media_MediaPlayer2_handleDataSourceUrl(
static void
android_media_MediaPlayer2_handleDataSourceFD(
- JNIEnv *env, jobject thiz, jboolean isCurrent, jlong srcId,
- jobject fileDescriptor, jlong offset, jlong length)
-{
+ JNIEnv *env, jobject thiz, jboolean isCurrent, jlong srcId,
+ jobject fileDescriptor, jlong offset, jlong length,
+ jlong startPos, jlong endPos) {
sp<MediaPlayer2> mp = getMediaPlayer(env, thiz);
if (mp == NULL ) {
jniThrowException(env, "java/lang/IllegalStateException", NULL);
@@ -355,8 +359,10 @@ android_media_MediaPlayer2_handleDataSourceFD(
return;
}
int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
- ALOGV("handleDataSourceFD: srcId=%lld, fd=%d (%s), offset=%lld, length=%lld",
- (long long)srcId, fd, nameForFd(fd).c_str(), (long long)offset, (long long)length);
+ ALOGV("handleDataSourceFD: srcId=%lld, fd=%d (%s), offset=%lld, length=%lld, "
+ "start=%lld, end=%lld",
+ (long long)srcId, fd, nameForFd(fd).c_str(), (long long)offset, (long long)length,
+ (long long)startPos, (long long)endPos);
struct stat sb;
int ret = fstat(fd, &sb);
@@ -389,6 +395,8 @@ android_media_MediaPlayer2_handleDataSourceFD(
dsd->mFD = fd;
dsd->mFDOffset = offset;
dsd->mFDLength = length;
+ dsd->mStartPositionMs = startPos;
+ dsd->mEndPositionMs = endPos;
status_t err;
if (isCurrent) {
@@ -402,7 +410,8 @@ android_media_MediaPlayer2_handleDataSourceFD(
static void
android_media_MediaPlayer2_handleDataSourceCallback(
- JNIEnv *env, jobject thiz, jboolean isCurrent, jlong srcId, jobject dataSource)
+ JNIEnv *env, jobject thiz, jboolean isCurrent, jlong srcId, jobject dataSource,
+ jlong startPos, jlong endPos)
{
sp<MediaPlayer2> mp = getMediaPlayer(env, thiz);
if (mp == NULL ) {
@@ -419,6 +428,8 @@ android_media_MediaPlayer2_handleDataSourceCallback(
dsd->mId = srcId;
dsd->mType = DataSourceDesc::TYPE_CALLBACK;
dsd->mCallbackSource = callbackDataSource;
+ dsd->mStartPositionMs = startPos;
+ dsd->mEndPositionMs = endPos;
status_t err;
if (isCurrent) {
@@ -974,15 +985,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
@@ -1442,17 +1453,17 @@ static const JNINativeMethod gMethods[] = {
{
"nativeHandleDataSourceUrl",
"(ZJLandroid/media/Media2HTTPService;Ljava/lang/String;[Ljava/lang/String;"
- "[Ljava/lang/String;)V",
+ "[Ljava/lang/String;JJ)V",
(void *)android_media_MediaPlayer2_handleDataSourceUrl
},
{
"nativeHandleDataSourceFD",
- "(ZJLjava/io/FileDescriptor;JJ)V",
+ "(ZJLjava/io/FileDescriptor;JJJJ)V",
(void *)android_media_MediaPlayer2_handleDataSourceFD
},
{
"nativeHandleDataSourceCallback",
- "(ZJLandroid/media/Media2DataSource;)V",
+ "(ZJLandroid/media/Media2DataSource;JJ)V",
(void *)android_media_MediaPlayer2_handleDataSourceCallback
},
{"nativePlayNextDataSource", "(J)V", (void *)android_media_MediaPlayer2_playNextDataSource},
@@ -1481,7 +1492,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/opengl/java/android/opengl/EGL15.java b/opengl/java/android/opengl/EGL15.java
new file mode 100644
index 000000000000..9aae6ad0f080
--- /dev/null
+++ b/opengl/java/android/opengl/EGL15.java
@@ -0,0 +1,149 @@
+/*
+** 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.opengl;
+
+/**
+ * EGL 1.5
+ *
+ */
+public class EGL15 {
+
+ public static final int EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT = 0x00000001;
+ public static final int EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT = 0x00000002;
+ public static final int EGL_OPENGL_ES3_BIT = 0x00000040;
+ public static final int EGL_SYNC_FLUSH_COMMANDS_BIT = 0x0001;
+ public static final int EGL_GL_COLORSPACE_SRGB = 0x3089;
+ public static final int EGL_GL_COLORSPACE_LINEAR = 0x308A;
+ public static final int EGL_CONTEXT_MAJOR_VERSION = 0x3098;
+ public static final int EGL_CL_EVENT_HANDLE = 0x309C;
+ public static final int EGL_GL_COLORSPACE = 0x309D;
+ public static final int EGL_GL_TEXTURE_2D = 0x30B1;
+ public static final int EGL_GL_TEXTURE_3D = 0x30B2;
+ public static final int EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X = 0x30B3;
+ public static final int EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X = 0x30B4;
+ public static final int EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y = 0x30B5;
+ public static final int EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y = 0x30B6;
+ public static final int EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z = 0x30B7;
+ public static final int EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z = 0x30B8;
+ public static final int EGL_GL_RENDERBUFFER = 0x30B9;
+ public static final int EGL_GL_TEXTURE_LEVEL = 0x30BC;
+ public static final int EGL_GL_TEXTURE_ZOFFSET = 0x30BD;
+ public static final int EGL_IMAGE_PRESERVED = 0x30D2;
+ public static final int EGL_SYNC_PRIOR_COMMANDS_COMPLETE = 0x30F0;
+ public static final int EGL_SYNC_STATUS = 0x30F1;
+ public static final int EGL_SIGNALED = 0x30F2;
+ public static final int EGL_UNSIGNALED = 0x30F3;
+ public static final int EGL_TIMEOUT_EXPIRED = 0x30F5;
+ public static final int EGL_CONDITION_SATISFIED = 0x30F6;
+ public static final int EGL_SYNC_TYPE = 0x30F7;
+ public static final int EGL_SYNC_CONDITION = 0x30F8;
+ public static final int EGL_SYNC_FENCE = 0x30F9;
+ public static final int EGL_CONTEXT_MINOR_VERSION = 0x30FB;
+ public static final int EGL_CONTEXT_OPENGL_PROFILE_MASK = 0x30FD;
+ public static final int EGL_SYNC_CL_EVENT = 0x30FE;
+ public static final int EGL_SYNC_CL_EVENT_COMPLETE = 0x30FF;
+ public static final int EGL_CONTEXT_OPENGL_DEBUG = 0x31B0;
+ public static final int EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE = 0x31B1;
+ public static final int EGL_CONTEXT_OPENGL_ROBUST_ACCESS = 0x31B2;
+ public static final int EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY = 0x31BD;
+ public static final int EGL_NO_RESET_NOTIFICATION = 0x31BE;
+ public static final int EGL_LOSE_CONTEXT_ON_RESET = 0x31BF;
+ public static final int EGL_PLATFORM_ANDROID_KHR = 0x3141;
+ public static final long EGL_FOREVER = 0xFFFFFFFFFFFFFFFFL;
+ public static final EGLImage EGL_NO_IMAGE = null;
+ public static final EGLSync EGL_NO_SYNC = null;
+ public static final EGLContext EGL_NO_CONTEXT = null;
+ public static final EGLDisplay EGL_NO_DISPLAY = null;
+ public static final EGLSurface EGL_NO_SURFACE = null;
+
+ native private static void _nativeClassInit();
+ static {
+ _nativeClassInit();
+ }
+ // C function EGLSync eglCreateSync ( EGLDisplay dpy, EGLenum type, const EGLAttrib *attrib_list )
+
+ public static native EGLSync eglCreateSync(
+ EGLDisplay dpy,
+ int type,
+ long[] attrib_list,
+ int offset
+ );
+
+ // C function EGLBoolean eglDestroySync ( EGLDisplay dpy, EGLSync sync )
+
+ public static native boolean eglDestroySync(
+ EGLDisplay dpy,
+ EGLSync sync
+ );
+
+ // C function EGLint eglClientWaitSync ( EGLDisplay dpy, EGLSync sync, EGLint flags, EGLTime timeout )
+
+ public static native int eglClientWaitSync(
+ EGLDisplay dpy,
+ EGLSync sync,
+ int flags,
+ long timeout
+ );
+
+ // C function EGLBoolean eglGetSyncAttrib ( EGLDisplay dpy, EGLSync sync, EGLint attribute, EGLAttrib *value )
+
+ public static native boolean eglGetSyncAttrib(
+ EGLDisplay dpy,
+ EGLSync sync,
+ int attribute,
+ long[] value,
+ int offset
+ );
+
+ // C function EGLDisplay eglGetPlatformDisplay ( EGLenum platform, EGLAttrib native_display, const EGLAttrib *attrib_list )
+
+ public static native EGLDisplay eglGetPlatformDisplay(
+ int platform,
+ long native_display,
+ long[] attrib_list,
+ int offset
+ );
+
+ // C function EGLSurface eglCreatePlatformWindowSurface ( EGLDisplay dpy, EGLConfig config, void *native_window, const EGLAttrib *attrib_list )
+
+ public static native EGLSurface eglCreatePlatformWindowSurface(
+ EGLDisplay dpy,
+ EGLConfig config,
+ java.nio.Buffer native_window,
+ long[] attrib_list,
+ int offset
+ );
+
+ // C function EGLSurface eglCreatePlatformPixmapSurface ( EGLDisplay dpy, EGLConfig config, void *native_pixmap, const EGLAttrib *attrib_list )
+
+ public static native EGLSurface eglCreatePlatformPixmapSurface(
+ EGLDisplay dpy,
+ EGLConfig config,
+ java.nio.Buffer native_pixmap,
+ long[] attrib_list,
+ int offset
+ );
+
+ // C function EGLBoolean eglWaitSync ( EGLDisplay dpy, EGLSync sync, EGLint flags )
+
+ public static native boolean eglWaitSync(
+ EGLDisplay dpy,
+ EGLSync sync,
+ int flags
+ );
+
+}
diff --git a/opengl/java/android/opengl/EGLImage.java b/opengl/java/android/opengl/EGLImage.java
new file mode 100644
index 000000000000..731ce72aa043
--- /dev/null
+++ b/opengl/java/android/opengl/EGLImage.java
@@ -0,0 +1,37 @@
+/*
+**
+** 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.opengl;
+
+/**
+ * Wrapper class for native EGLImage objects.
+ *
+ */
+public class EGLImage extends EGLObjectHandle {
+ private EGLImage(long handle) {
+ super(handle);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof EGLImage)) return false;
+
+ EGLImage that = (EGLImage) o;
+ return getNativeHandle() == that.getNativeHandle();
+ }
+}
diff --git a/opengl/java/android/opengl/EGLSync.java b/opengl/java/android/opengl/EGLSync.java
new file mode 100644
index 000000000000..472f9e71254f
--- /dev/null
+++ b/opengl/java/android/opengl/EGLSync.java
@@ -0,0 +1,37 @@
+/*
+**
+** 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.opengl;
+
+/**
+ * Wrapper class for native EGLSync objects.
+ *
+ */
+public class EGLSync extends EGLObjectHandle {
+ private EGLSync(long handle) {
+ super(handle);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof EGLSync)) return false;
+
+ EGLSync that = (EGLSync) o;
+ return getNativeHandle() == that.getNativeHandle();
+ }
+}
diff --git a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CarrierActionUtils.java b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CarrierActionUtils.java
index 33cb596415d5..4518d79ff611 100644
--- a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CarrierActionUtils.java
+++ b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CarrierActionUtils.java
@@ -30,7 +30,7 @@ import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.Log;
import com.android.internal.telephony.PhoneConstants;
-import com.android.carrierdefaultapp.R;
+
/**
* This util class provides common logic for carrier actions
*/
@@ -102,7 +102,7 @@ public class CarrierActionUtils {
SubscriptionManager.getDefaultVoiceSubscriptionId());
logd("onDisableAllMeteredApns subId: " + subId);
final TelephonyManager telephonyMgr = context.getSystemService(TelephonyManager.class);
- telephonyMgr.carrierActionSetMeteredApnsEnabled(subId, !ENABLE);
+ telephonyMgr.createForSubscriptionId(subId).setCarrierDataEnabled(!ENABLE);
}
private static void onEnableAllMeteredApns(Intent intent, Context context) {
@@ -110,7 +110,7 @@ public class CarrierActionUtils {
SubscriptionManager.getDefaultVoiceSubscriptionId());
logd("onEnableAllMeteredApns subId: " + subId);
final TelephonyManager telephonyMgr = context.getSystemService(TelephonyManager.class);
- telephonyMgr.carrierActionSetMeteredApnsEnabled(subId, ENABLE);
+ telephonyMgr.createForSubscriptionId(subId).setCarrierDataEnabled(ENABLE);
}
private static void onEnableDefaultURLHandler(Context context) {
diff --git a/packages/CarrierDefaultApp/tests/unit/src/com/android/carrierdefaultapp/CarrierDefaultReceiverTest.java b/packages/CarrierDefaultApp/tests/unit/src/com/android/carrierdefaultapp/CarrierDefaultReceiverTest.java
index f9dbcd45b19b..5d84d6450574 100644
--- a/packages/CarrierDefaultApp/tests/unit/src/com/android/carrierdefaultapp/CarrierDefaultReceiverTest.java
+++ b/packages/CarrierDefaultApp/tests/unit/src/com/android/carrierdefaultapp/CarrierDefaultReceiverTest.java
@@ -104,6 +104,6 @@ public class CarrierDefaultReceiverTest extends InstrumentationTestCase {
assertNotNull(pendingIntent);
Rlog.d(TAG, "verify carrier action: disable all metered apns");
- verify(mTelephonyMgr).carrierActionSetMeteredApnsEnabled(eq(subId), eq(false));
+ verify(mTelephonyMgr).setCarrierDataEnabled(eq(false));
}
}
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/src/com/android/packageinstaller/InstallStart.java b/packages/PackageInstaller/src/com/android/packageinstaller/InstallStart.java
index 8fed367f3773..f2de9ecd8f5d 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/InstallStart.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/InstallStart.java
@@ -54,9 +54,14 @@ public class InstallStart extends Activity {
Intent intent = getIntent();
String callingPackage = getCallingPackage();
+ final boolean isSessionInstall =
+ PackageInstaller.ACTION_CONFIRM_INSTALL.equals(intent.getAction());
+
// If the activity was started via a PackageInstaller session, we retrieve the calling
// package from that session
- int sessionId = intent.getIntExtra(PackageInstaller.EXTRA_SESSION_ID, -1);
+ final int sessionId = (isSessionInstall
+ ? intent.getIntExtra(PackageInstaller.EXTRA_SESSION_ID, -1)
+ : -1);
if (callingPackage == null && sessionId != -1) {
PackageInstaller packageInstaller = getPackageManager().getPackageInstaller();
PackageInstaller.SessionInfo sessionInfo = packageInstaller.getSessionInfo(sessionId);
@@ -99,7 +104,7 @@ public class InstallStart extends Activity {
nextActivity.putExtra(PackageInstallerActivity.EXTRA_ORIGINAL_SOURCE_INFO, sourceInfo);
nextActivity.putExtra(Intent.EXTRA_ORIGINATING_UID, originatingUid);
- if (PackageInstaller.ACTION_CONFIRM_INSTALL.equals(intent.getAction())) {
+ if (isSessionInstall) {
nextActivity.setClass(this, PackageInstallerActivity.class);
} else {
Uri packageUri = intent.getData();
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/Android.bp b/packages/SettingsLib/Android.bp
index d60dbe783fcd..5161344a4946 100644
--- a/packages/SettingsLib/Android.bp
+++ b/packages/SettingsLib/Android.bp
@@ -2,16 +2,14 @@ android_library {
name: "SettingsLib",
- libs: [
+ static_libs: [
"androidx.annotation_annotation",
"androidx.legacy_legacy-support-v4",
"androidx.recyclerview_recyclerview",
"androidx.preference_preference",
"androidx.appcompat_appcompat",
"androidx.lifecycle_lifecycle-runtime",
- ],
- static_libs: [
"SettingsLibHelpUtils",
"SettingsLibRestrictedLockUtils",
"SettingsLibAppPreference",
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 b87c9e8de1b2..8529e3ef8420 100644
--- a/packages/SettingsLib/RestrictedLockUtils/src/com/android/settingslib/RestrictedLockUtils.java
+++ b/packages/SettingsLib/RestrictedLockUtils/src/com/android/settingslib/RestrictedLockUtils.java
@@ -80,24 +80,17 @@ public class RestrictedLockUtils {
if (admin.component != null) {
intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, admin.component);
}
- int adminUserId = UserHandle.myUserId();
- if (admin.user != null) {
- adminUserId = admin.user.getIdentifier();
- }
- intent.putExtra(Intent.EXTRA_USER_ID, adminUserId);
+ final UserHandle adminUser = admin.user != null
+ ? admin.user
+ : UserHandle.of(UserHandle.myUserId());
+ intent.putExtra(Intent.EXTRA_USER, adminUser);
}
return intent;
}
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 {
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 f57122e6708d..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);
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 71cf1d404ed9..6f1492eac756 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
@@ -62,11 +62,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/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 d3d0cce261ff..577b1513be36 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -35,6 +35,13 @@ class SettingsProtoDumpUtil {
static void dumpProtoLocked(SettingsProvider.SettingsRegistry settingsRegistry,
ProtoOutputStream proto) {
+ // Config settings
+ SettingsState configSettings = settingsRegistry.getSettingsLocked(
+ SettingsProvider.SETTINGS_TYPE_CONFIG, UserHandle.USER_SYSTEM);
+ if (configSettings != null) {
+ // TODO(b/113100523): dump configuration settings after they are added
+ }
+
// Global settings
SettingsState globalSettings = settingsRegistry.getSettingsLocked(
SettingsProvider.SETTINGS_TYPE_GLOBAL, UserHandle.USER_SYSTEM);
@@ -662,6 +669,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/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index d3dd97b8064d..d8fb741f3c0d 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -180,6 +180,7 @@ public class SettingsProvider extends ContentProvider {
public static final int SETTINGS_TYPE_SYSTEM = SettingsState.SETTINGS_TYPE_SYSTEM;
public static final int SETTINGS_TYPE_SECURE = SettingsState.SETTINGS_TYPE_SECURE;
public static final int SETTINGS_TYPE_SSAID = SettingsState.SETTINGS_TYPE_SSAID;
+ public static final int SETTINGS_TYPE_CONFIG = SettingsState.SETTINGS_TYPE_CONFIG;
private static final Bundle NULL_SETTING_BUNDLE = Bundle.forPair(
Settings.NameValueTable.VALUE, null);
@@ -189,6 +190,13 @@ public class SettingsProvider extends ContentProvider {
private static final Set<String> OVERLAY_ALLOWED_SYSTEM_INSTANT_APP_SETTINGS = new ArraySet<>();
private static final Set<String> OVERLAY_ALLOWED_SECURE_INSTANT_APP_SETTINGS = new ArraySet<>();
+ /**
+ * TODO(b/113100523): Move this to DeviceConfig.java when it is added, and expose it as a System
+ * API.
+ */
+ private static final Uri CONFIG_CONTENT_URI =
+ Uri.parse("content://" + Settings.AUTHORITY + "/config");
+
static {
for (String name : Resources.getSystem().getStringArray(
com.android.internal.R.array.config_allowedGlobalInstantAppSettings)) {
@@ -380,6 +388,11 @@ public class SettingsProvider extends ContentProvider {
public Bundle call(String method, String name, Bundle args) {
final int requestingUserId = getRequestingUserId(args);
switch (method) {
+ case Settings.CALL_METHOD_GET_CONFIG: {
+ Setting setting = getConfigSetting(name);
+ return packageValueForCallResult(setting, isTrackingGeneration(args));
+ }
+
case Settings.CALL_METHOD_GET_GLOBAL: {
Setting setting = getGlobalSetting(name);
return packageValueForCallResult(setting, isTrackingGeneration(args));
@@ -396,6 +409,14 @@ public class SettingsProvider extends ContentProvider {
return packageValueForCallResult(setting, isTrackingGeneration(args));
}
+ case Settings.CALL_METHOD_PUT_CONFIG: {
+ String value = getSettingValue(args);
+ String tag = getSettingTag(args);
+ final boolean makeDefault = getSettingMakeDefault(args);
+ insertConfigSetting(name, value, tag, makeDefault, requestingUserId, false);
+ break;
+ }
+
case Settings.CALL_METHOD_PUT_GLOBAL: {
String value = getSettingValue(args);
String tag = getSettingTag(args);
@@ -418,6 +439,13 @@ public class SettingsProvider extends ContentProvider {
break;
}
+ case Settings.CALL_METHOD_RESET_CONFIG: {
+ final int mode = getResetModeEnforcingPermission(args);
+ String tag = getSettingTag(args);
+ resetConfigSetting(requestingUserId, mode, tag);
+ break;
+ }
+
case Settings.CALL_METHOD_RESET_GLOBAL: {
final int mode = getResetModeEnforcingPermission(args);
String tag = getSettingTag(args);
@@ -725,6 +753,15 @@ public class SettingsProvider extends ContentProvider {
@GuardedBy("mLock")
private void dumpForUserLocked(int userId, PrintWriter pw) {
if (userId == UserHandle.USER_SYSTEM) {
+ pw.println("CONFIG SETTINGS (user " + userId + ")");
+ SettingsState configSettings = mSettingsRegistry.getSettingsLocked(
+ SETTINGS_TYPE_CONFIG, UserHandle.USER_SYSTEM);
+ if (configSettings != null) {
+ dumpSettingsLocked(configSettings, pw);
+ pw.println();
+ configSettings.dumpHistoricalOperations(pw);
+ }
+
pw.println("GLOBAL SETTINGS (user " + userId + ")");
SettingsState globalSettings = mSettingsRegistry.getSettingsLocked(
SETTINGS_TYPE_GLOBAL, UserHandle.USER_SYSTEM);
@@ -939,6 +976,69 @@ public class SettingsProvider extends ContentProvider {
});
}
+ private Setting getConfigSetting(String name) {
+ if (DEBUG) {
+ Slog.v(LOG_TAG, "getConfigSetting(" + name + ")");
+ }
+
+ // TODO(b/117663715): Ensure the caller can access the setting.
+ // enforceSettingReadable(name, SETTINGS_TYPE_CONFIG, UserHandle.getCallingUserId());
+
+ // Get the value.
+ synchronized (mLock) {
+ return mSettingsRegistry.getSettingLocked(SETTINGS_TYPE_CONFIG,
+ UserHandle.USER_SYSTEM, name);
+ }
+ }
+
+ private boolean insertConfigSetting(String name, String value, String tag,
+ boolean makeDefault, int requestingUserId, boolean forceNotify) {
+ if (DEBUG) {
+ Slog.v(LOG_TAG, "insertConfigSetting(" + name + ", " + value + ", "
+ + ", " + tag + ", " + makeDefault + ", " + requestingUserId
+ + ", " + forceNotify + ")");
+ }
+ return mutateConfigSetting(name, value, tag, makeDefault, requestingUserId,
+ MUTATION_OPERATION_INSERT, forceNotify, 0);
+ }
+
+ private void resetConfigSetting(int requestingUserId, int mode, String tag) {
+ if (DEBUG) {
+ Slog.v(LOG_TAG, "resetConfigSetting(" + requestingUserId + ", "
+ + mode + ", " + tag + ")");
+ }
+ mutateConfigSetting(null, null, tag, false, requestingUserId,
+ MUTATION_OPERATION_RESET, false, mode);
+ }
+
+ private boolean mutateConfigSetting(String name, String value, String tag,
+ boolean makeDefault, int requestingUserId, int operation, boolean forceNotify,
+ int mode) {
+ // TODO(b/117663715): check the new permission when it's added.
+ // enforceWritePermission(Manifest.permission.WRITE_SECURE_SETTINGS);
+
+ // Resolve the userId on whose behalf the call is made.
+ final int callingUserId = resolveCallingUserIdEnforcingPermissionsLocked(requestingUserId);
+
+ // Perform the mutation.
+ synchronized (mLock) {
+ switch (operation) {
+ case MUTATION_OPERATION_INSERT: {
+ return mSettingsRegistry.insertSettingLocked(SETTINGS_TYPE_CONFIG,
+ UserHandle.USER_SYSTEM, name, value, tag, makeDefault,
+ getCallingPackage(), forceNotify, null);
+ }
+
+ case MUTATION_OPERATION_RESET: {
+ mSettingsRegistry.resetSettingsLocked(SETTINGS_TYPE_CONFIG,
+ UserHandle.USER_SYSTEM, getCallingPackage(), mode, tag);
+ } return true;
+ }
+ }
+
+ return false;
+ }
+
private Cursor getAllGlobalSettings(String[] projection) {
if (DEBUG) {
Slog.v(LOG_TAG, "getAllGlobalSettings()");
@@ -2132,6 +2232,7 @@ public class SettingsProvider extends ContentProvider {
private static final String SETTINGS_FILE_SYSTEM = "settings_system.xml";
private static final String SETTINGS_FILE_SECURE = "settings_secure.xml";
private static final String SETTINGS_FILE_SSAID = "settings_ssaid.xml";
+ private static final String SETTINGS_FILE_CONFIG = "settings_config.xml";
private static final String SSAID_USER_KEY = "userkey";
@@ -2303,6 +2404,13 @@ public class SettingsProvider extends ContentProvider {
// Migrate the setting for this user if needed.
migrateLegacySettingsForUserIfNeededLocked(userId);
+ // Ensure config settings loaded if owner.
+ if (userId == UserHandle.USER_SYSTEM) {
+ final int configKey
+ = makeKey(SETTINGS_TYPE_CONFIG, UserHandle.USER_SYSTEM);
+ ensureSettingsStateLocked(configKey);
+ }
+
// Ensure global settings loaded if owner.
if (userId == UserHandle.USER_SYSTEM) {
final int globalKey = makeKey(SETTINGS_TYPE_GLOBAL, UserHandle.USER_SYSTEM);
@@ -2853,6 +2961,10 @@ public class SettingsProvider extends ContentProvider {
}
}
+ private boolean isConfigSettingsKey(int key) {
+ return getTypeFromKey(key) == SETTINGS_TYPE_CONFIG;
+ }
+
private boolean isGlobalSettingsKey(int key) {
return getTypeFromKey(key) == SETTINGS_TYPE_GLOBAL;
}
@@ -2870,7 +2982,11 @@ public class SettingsProvider extends ContentProvider {
}
private File getSettingsFile(int key) {
- if (isGlobalSettingsKey(key)) {
+ if (isConfigSettingsKey(key)) {
+ final int userId = getUserIdFromKey(key);
+ return new File(Environment.getUserSystemDirectory(userId),
+ SETTINGS_FILE_CONFIG);
+ } else if (isGlobalSettingsKey(key)) {
final int userId = getUserIdFromKey(key);
return new File(Environment.getUserSystemDirectory(userId),
SETTINGS_FILE_GLOBAL);
@@ -2892,7 +3008,10 @@ public class SettingsProvider extends ContentProvider {
}
private Uri getNotificationUriFor(int key, String name) {
- if (isGlobalSettingsKey(key)) {
+ if (isConfigSettingsKey(key)) {
+ return (name != null) ? Uri.withAppendedPath(CONFIG_CONTENT_URI, name)
+ : CONFIG_CONTENT_URI;
+ } else if (isGlobalSettingsKey(key)) {
return (name != null) ? Uri.withAppendedPath(Settings.Global.CONTENT_URI, name)
: Settings.Global.CONTENT_URI;
} else if (isSecureSettingsKey(key)) {
@@ -2908,6 +3027,7 @@ public class SettingsProvider extends ContentProvider {
private int getMaxBytesPerPackageForType(int type) {
switch (type) {
+ case SETTINGS_TYPE_CONFIG:
case SETTINGS_TYPE_GLOBAL:
case SETTINGS_TYPE_SECURE:
case SETTINGS_TYPE_SSAID: {
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
index 389d627a9bd6..ae2ca3f87ae7 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
@@ -34,7 +34,6 @@ import android.os.SystemClock;
import android.os.UserHandle;
import android.provider.Settings;
import android.provider.Settings.Global;
-import android.providers.settings.GlobalSettingsProto;
import android.providers.settings.SettingsOperationProto;
import android.text.TextUtils;
import android.util.ArrayMap;
@@ -67,7 +66,6 @@ import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
-import java.util.Set;
/**
* This class contains the state for one type of settings. It is responsible
@@ -205,6 +203,7 @@ final class SettingsState {
public static final int SETTINGS_TYPE_SYSTEM = 1;
public static final int SETTINGS_TYPE_SECURE = 2;
public static final int SETTINGS_TYPE_SSAID = 3;
+ public static final int SETTINGS_TYPE_CONFIG = 4;
public static final int SETTINGS_TYPE_MASK = 0xF0000000;
public static final int SETTINGS_TYPE_SHIFT = 28;
@@ -223,6 +222,9 @@ final class SettingsState {
public static String settingTypeToString(int type) {
switch (type) {
+ case SETTINGS_TYPE_CONFIG: {
+ return "SETTINGS_CONFIG";
+ }
case SETTINGS_TYPE_GLOBAL: {
return "SETTINGS_GLOBAL";
}
diff --git a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsProviderTest.java b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsProviderTest.java
index 95569dc6d1b7..572a92452291 100644
--- a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsProviderTest.java
+++ b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsProviderTest.java
@@ -645,7 +645,7 @@ public class SettingsProviderTest extends BaseSettingsProviderTest {
return;
}
final long elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis;
- if (elapsedTimeMillis > WAIT_FOR_SETTING_URI_CHANGE_TIMEOUT_MILLIS) {
+ if (elapsedTimeMillis >= WAIT_FOR_SETTING_URI_CHANGE_TIMEOUT_MILLIS) {
fail("Could not change setting for "
+ WAIT_FOR_SETTING_URI_CHANGE_TIMEOUT_MILLIS + " ms");
}
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
index d1181445be43..ba4eb5f48528 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/SensorManagerPlugin.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/SensorManagerPlugin.java
@@ -16,6 +16,9 @@
package com.android.systemui.plugins;
+import android.hardware.Sensor;
+import android.hardware.TriggerEventListener;
+
import com.android.systemui.plugins.annotations.ProvidesInterface;
/**
@@ -28,10 +31,12 @@ public interface SensorManagerPlugin extends Plugin {
int VERSION = 1;
/**
- * Registers for trigger events from the sensor. The client will receive trigger events until
- * {@link #unregisterTriggerEvent(Sensor, TriggerEventListener)} is called.
+ * 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);
@@ -62,9 +67,25 @@ public interface SensorManagerPlugin extends Plugin {
class TriggerEvent {
Sensor mSensor;
+ int mVendorType;
- public TriggerEvent(Sensor sensor) {
+ /**
+ * 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/config.xml b/packages/SystemUI/res/values/config.xml
index d78054aec8b5..946d8917c00c 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -137,9 +137,6 @@
<integer name="quick_settings_brightness_dialog_short_timeout">2000</integer>
<integer name="quick_settings_brightness_dialog_long_timeout">4000</integer>
- <!-- Should "4G" be shown instead of "LTE" when the network is NETWORK_TYPE_LTE? -->
- <bool name="config_show4GForLTE">true</bool>
-
<!-- Show indicator for Wifi on but not connected. -->
<bool name="config_showWifiIndicatorWhenEnabled">false</bool>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 40810a33cb0d..cde493e0c907 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -763,6 +763,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] -->
@@ -2001,6 +2003,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/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/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/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java
index d351c4f3e3e6..1bf87506ab0c 100644
--- a/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java
@@ -259,6 +259,7 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mHandler.removeCallbacks(mDeferredConnectionCallback);
+ mCurrentBoundedUserId = mDeviceProvisionedController.getCurrentUser();
mConnectionBackoffAttempts = 0;
mOverviewProxy = IOverviewProxy.Stub.asInterface(service);
// Listen for launcher's death
@@ -269,7 +270,6 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis
}
try {
mOverviewProxy.onBind(mSysUiProxy);
- mCurrentBoundedUserId = mDeviceProvisionedController.getCurrentUser();
} catch (RemoteException e) {
mCurrentBoundedUserId = -1;
Log.e(TAG_OPS, "Failed to call onBind()", e);
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/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
index 0215fda81485..3fe99445f49d 100644
--- a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
@@ -87,6 +87,8 @@ public class SwipeHelper implements Gefingerpoken {
private Runnable mWatchLongPress;
private final long mLongPressTimeout;
+ protected boolean mSwipingInProgress;
+
final private int[] mTmpPos = new int[2];
private final int mFalsingThreshold;
private boolean mTouchAboveFalsingThreshold;
@@ -127,6 +129,10 @@ public class SwipeHelper implements Gefingerpoken {
mDisableHwLayers = disableHwLayers;
}
+ public boolean isSwipingInProgress() {
+ return mSwipingInProgress;
+ }
+
private float getPos(MotionEvent ev) {
return mSwipeDirection == X ? ev.getX() : ev.getY();
}
@@ -318,6 +324,7 @@ public class SwipeHelper implements Gefingerpoken {
if (Math.abs(delta) > mPagingTouchSlop
&& Math.abs(delta) > Math.abs(deltaPerpendicular)) {
if (mCallback.canChildBeDragged(mCurrView)) {
+ mSwipingInProgress = true;
mCallback.onBeginDrag(mCurrView);
mDragging = true;
mInitialTouchPos = getPos(ev);
@@ -437,6 +444,7 @@ public class SwipeHelper implements Gefingerpoken {
wasRemoved = row.isRemoved();
}
if (!mCancelled || wasRemoved) {
+ mSwipingInProgress = false;
mCallback.onChildDismissed(animView);
}
if (endAction != null) {
@@ -626,6 +634,7 @@ public class SwipeHelper implements Gefingerpoken {
!swipedFastEnough() /* useAccelerateInterpolator */);
} else {
// snappity
+ mSwipingInProgress = false;
mCallback.onDragCancelled(mCurrView);
snapChild(mCurrView, 0 /* leftTarget */, velocity);
}
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 774567ef8bb1..95029c013ab6 100644
--- a/packages/SystemUI/src/com/android/systemui/plugins/PluginInitializerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/plugins/PluginInitializerImpl.java
@@ -26,6 +26,10 @@ 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
@@ -52,7 +56,7 @@ public class PluginInitializerImpl implements PluginInitializer {
@Override
public void handleWtfs() {
- if (!mWtfsSet) {
+ if (WTFS_SHOULD_CRASH && !mWtfsSet) {
mWtfsSet = true;
Log.setWtfHandler(new Log.TerribleFailureHandler() {
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
index 92f5cae4e165..15d2e66a82ce 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
@@ -308,6 +308,7 @@ public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileSta
@Override
public void onClick(View v) {
int position = holder.getAdapterPosition();
+ if (position == RecyclerView.NO_POSITION) return;
if (mAccessibilityAction != ACTION_NONE) {
selectPosition(position, v);
} else {
@@ -561,6 +562,7 @@ public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileSta
if (viewHolder == mCurrentDrag) return;
if (mCurrentDrag != null) {
int position = mCurrentDrag.getAdapterPosition();
+ if (position == RecyclerView.NO_POSITION) return;
TileInfo info = mTiles.get(position);
mCurrentDrag.mTileView.setShowAppLabel(
position > mEditIndex && !info.isSystem);
@@ -582,13 +584,14 @@ public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileSta
@Override
public boolean canDropOver(RecyclerView recyclerView, ViewHolder current,
ViewHolder target) {
- if (target.getAdapterPosition() == 0){
+ final int position = target.getAdapterPosition();
+ if (position == 0 || position == RecyclerView.NO_POSITION){
return false;
}
if (!canRemoveTiles() && current.getAdapterPosition() < mEditIndex) {
- return target.getAdapterPosition() < mEditIndex;
+ return position < mEditIndex;
}
- return target.getAdapterPosition() <= mEditIndex + 1;
+ return position <= mEditIndex + 1;
}
@Override
@@ -610,6 +613,10 @@ public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileSta
public boolean onMove(RecyclerView recyclerView, ViewHolder viewHolder, ViewHolder target) {
int from = viewHolder.getAdapterPosition();
int to = target.getAdapterPosition();
+ if (from == 0 || from == RecyclerView.NO_POSITION ||
+ to == 0 || to == RecyclerView.NO_POSITION) {
+ return false;
+ }
return move(from, to, target.itemView);
}
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/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/NotificationViewHierarchyManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
index f69ad43ed79c..5b3082b04d58 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
@@ -327,6 +327,17 @@ public class NotificationViewHierarchyManager {
entry.notification) && !entry.row.isRemoved();
boolean showOnKeyguard = mLockscreenUserManager.shouldShowOnKeyguard(entry
.notification);
+ if (!showOnKeyguard) {
+ // min priority notifications should show if their summary is showing
+ if (mGroupManager.isChildInGroupWithSummary(entry.notification)) {
+ ExpandableNotificationRow summary = mGroupManager.getLogicalGroupSummary(
+ entry.notification);
+ if (summary != null && mLockscreenUserManager.shouldShowOnKeyguard(
+ summary.getStatusBarNotification())) {
+ showOnKeyguard = true;
+ }
+ }
+ }
if (suppressedSummary
|| mLockscreenUserManager.shouldHideNotifications(userId)
|| (isLocked && !showOnKeyguard)) {
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/VisibilityLocationProvider.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/VisibilityLocationProvider.java
index 81208c4330c5..53ebe747c2e9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/VisibilityLocationProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/VisibilityLocationProvider.java
@@ -24,7 +24,10 @@ import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
public interface VisibilityLocationProvider {
/**
- * @return whether the view is in a visible location right now.
+ * Returns whether an ExpandableNotificationRow is in a visible location or not.
+ *
+ * @param row
+ * @return true if row is in a visible location
*/
boolean isInVisibleLocation(ExpandableNotificationRow row);
}
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..8110c1c98dec 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;
@@ -94,6 +102,9 @@ import com.android.systemui.statusbar.notification.stack.ExpandableViewState;
import com.android.systemui.statusbar.notification.stack.NotificationChildrenContainer;
import com.android.systemui.statusbar.notification.stack.StackScrollState;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.function.BooleanSupplier;
@@ -429,12 +440,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 +639,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 +2674,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);
@@ -3017,6 +3079,36 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
boolean onClick(View v, int x, int y, MenuItem item);
}
+ @Override
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ super.dump(fd, pw, args);
+ pw.println(" Notification: " + getStatusBarNotification().getKey());
+ pw.print(" visibility: " + getVisibility());
+ pw.print(", alpha: " + getAlpha());
+ pw.print(", translation: " + getTranslation());
+ pw.print(", removed: " + isRemoved());
+ pw.print(", privateShowing: " + (getShowingLayout() == mPrivateLayout));
+ pw.println();
+ pw.print(" ");
+ if (mNotificationViewState != null) {
+ mNotificationViewState.dump(fd, pw, args);
+ } else {
+ pw.print("no viewState!!!");
+ }
+ pw.println();
+ pw.println();
+ if (mIsSummaryWithChildren) {
+ List<ExpandableNotificationRow> notificationChildren = getNotificationChildren();
+ pw.println(" Children: " + notificationChildren.size());
+ pw.println(" {");
+ for(ExpandableNotificationRow child : notificationChildren) {
+ child.dump(fd, pw, args);
+ }
+ pw.println(" }");
+ pw.println();
+ }
+ }
+
/**
* Background task for executing IPCs to check if the notification is a system notification. The
* output is used for both the blocking helper and the notification info.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
index 46019e3b48ea..38d657b967a0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
@@ -25,16 +25,19 @@ import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
+import com.android.systemui.Dumpable;
import com.android.systemui.statusbar.notification.stack.ExpandableViewState;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
import com.android.systemui.statusbar.notification.stack.StackScrollState;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
import java.util.ArrayList;
/**
* An abstract view for expandable views.
*/
-public abstract class ExpandableView extends FrameLayout {
+public abstract class ExpandableView extends FrameLayout implements Dumpable {
public static final float NO_ROUNDNESS = -1;
protected OnHeightChangedListener mOnHeightChangedListener;
@@ -559,6 +562,10 @@ public abstract class ExpandableView extends FrameLayout {
return false;
}
+ @Override
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ }
+
/**
* A listener notifying when {@link #getActualHeight} changes.
*/
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 4ef8dbb19318..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,6 +23,7 @@ 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;
@@ -108,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() {
@@ -517,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);
@@ -1163,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) {
@@ -1620,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/NotificationListContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationListContainer.java
index fa75c7131e09..cfb6d990a9a7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationListContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationListContainer.java
@@ -22,6 +22,7 @@ import android.view.View;
import android.view.ViewGroup;
import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper;
+import com.android.systemui.statusbar.notification.VisibilityLocationProvider;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.ExpandableView;
import com.android.systemui.statusbar.notification.NotificationData;
@@ -31,7 +32,8 @@ import com.android.systemui.statusbar.notification.logging.NotificationLogger;
* Interface representing the entity that contains notifications. It can have
* notification views added and removed from it, and will manage displaying them to the user.
*/
-public interface NotificationListContainer {
+public interface NotificationListContainer extends ExpandableView.OnHeightChangedListener,
+ VisibilityLocationProvider {
/**
* Called when a child is being transferred.
@@ -128,14 +130,6 @@ public interface NotificationListContainer {
ViewGroup getViewParentForNotification(NotificationData.Entry entry);
/**
- * Called when the height of an expandable view changes.
- *
- * @param view view whose height changed
- * @param animate whether this change should be animated
- */
- void onHeightChanged(ExpandableView view, boolean animate);
-
- /**
* Resets the currently exposed menu view.
*
* @param animate whether to animate the closing/change of menu view
@@ -158,13 +152,6 @@ public interface NotificationListContainer {
*/
void cleanUpViewState(View view);
- /**
- * Returns whether an ExpandableNotificationRow is in a visible location or not.
- *
- * @param row
- * @return true if row is in a visible location
- */
- boolean isInVisibleLocation(ExpandableNotificationRow row);
/**
* Sets a listener to listen for changes in notification locations.
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 33ac390de29f..0bc54a33347c 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
@@ -25,6 +25,8 @@ import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
import android.animation.TimeAnimator;
import android.animation.ValueAnimator;
+import android.animation.ValueAnimator.AnimatorUpdateListener;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.WallpaperManager;
import android.content.Context;
@@ -43,10 +45,6 @@ import android.os.ServiceManager;
import android.provider.Settings;
import android.service.notification.StatusBarNotification;
-import androidx.annotation.NonNull;
-import androidx.annotation.VisibleForTesting;
-import androidx.core.graphics.ColorUtils;
-
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
@@ -69,6 +67,8 @@ import android.view.animation.Interpolator;
import android.widget.OverScroller;
import android.widget.ScrollView;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.graphics.ColorUtils;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.statusbar.IStatusBarService;
@@ -84,6 +84,7 @@ import com.android.systemui.classifier.FalsingManager;
import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.MenuItem;
+import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.OnMenuEventListener;
import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.DragDownHelper.DragDownCallback;
@@ -117,7 +118,7 @@ import com.android.systemui.statusbar.notification.VisibilityLocationProvider;
import com.android.systemui.statusbar.phone.DozeParameters;
import com.android.systemui.statusbar.phone.HeadsUpAppearanceController;
import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
-import com.android.systemui.statusbar.phone.HeadsUpManagerPhone.AnimationStateHandler;
+import com.android.systemui.statusbar.phone.HeadsUpTouchHelper;
import com.android.systemui.statusbar.phone.LockscreenGestureLogger;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.phone.NotificationGroupManager.OnGroupChangeListener;
@@ -142,10 +143,8 @@ import java.util.function.BiConsumer;
/**
* A layout which handles a dynamic amount of notifications and presents them in a scrollable stack.
*/
-public class NotificationStackScrollLayout extends ViewGroup
- implements ExpandHelper.Callback, ScrollAdapter, OnHeightChangedListener,
- OnGroupChangeListener, VisibilityLocationProvider, NotificationListContainer,
- ConfigurationListener, DragDownCallback, AnimationStateHandler, Dumpable {
+public class NotificationStackScrollLayout extends ViewGroup implements ScrollAdapter,
+ NotificationListContainer, ConfigurationListener, Dumpable {
public static final float BACKGROUND_ALPHA_DIMMED = 0.7f;
private static final String TAG = "StackScroller";
@@ -160,7 +159,6 @@ public class NotificationStackScrollLayout extends ViewGroup
private ExpandHelper mExpandHelper;
private final NotificationSwipeHelper mSwipeHelper;
- private boolean mSwipingInProgress;
private int mCurrentStackHeight = Integer.MAX_VALUE;
private final Paint mBackgroundPaint = new Paint();
private final boolean mShouldDrawNotificationBackground;
@@ -344,7 +342,7 @@ public class NotificationStackScrollLayout extends ViewGroup
private float mDimAmount;
private ValueAnimator mDimAnimator;
private ArrayList<ExpandableView> mTmpSortedChildren = new ArrayList<>();
- private Animator.AnimatorListener mDimEndListener = new AnimatorListenerAdapter() {
+ private final Animator.AnimatorListener mDimEndListener = new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
mDimAnimator = null;
@@ -485,12 +483,12 @@ public class NotificationStackScrollLayout extends ViewGroup
mBgColor = context.getColor(R.color.notification_shade_background_color);
int minHeight = res.getDimensionPixelSize(R.dimen.notification_min_height);
int maxHeight = res.getDimensionPixelSize(R.dimen.notification_max_height);
- mExpandHelper = new ExpandHelper(getContext(), this,
+ mExpandHelper = new ExpandHelper(getContext(), mExpandHelperCallback,
minHeight, maxHeight);
mExpandHelper.setEventSource(this);
mExpandHelper.setScrollAdapter(this);
- mSwipeHelper = new NotificationSwipeHelper(SwipeHelper.X, new SwipeHelperCallback(),
- getContext(), new NotificationMenuListener());
+ mSwipeHelper = new NotificationSwipeHelper(SwipeHelper.X, mNotificationCallback,
+ getContext(), mMenuEventListener);
mStackScrollAlgorithm = createStackScrollAlgorithm(context);
initView(context);
mFalsingManager = FalsingManager.getInstance(context);
@@ -530,7 +528,7 @@ public class NotificationStackScrollLayout extends ViewGroup
inflateEmptyShadeView();
inflateFooterView();
- mVisualStabilityManager.setVisibilityLocationProvider(this);
+ mVisualStabilityManager.setVisibilityLocationProvider(this::isInVisibleLocation);
setLongPressListener(mEntryManager.getNotificationLongClicker());
}
@@ -589,7 +587,7 @@ public class NotificationStackScrollLayout extends ViewGroup
return false;
}
- @ShadeViewRefactor(RefactorComponent.INPUT)
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public RemoteInputController.Delegate createDelegate() {
return new RemoteInputController.Delegate() {
public void setRemoteInputActive(NotificationData.Entry entry,
@@ -628,7 +626,7 @@ public class NotificationStackScrollLayout extends ViewGroup
}
@Override
- @ShadeViewRefactor(RefactorComponent.INPUT)
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public NotificationSwipeActionHelper getSwipeActionHelper() {
return mSwipeHelper;
}
@@ -1245,11 +1243,6 @@ public class NotificationStackScrollLayout extends ViewGroup
return firstChild != null ? firstChild.getMinHeight() : mCollapsedSize;
}
- @ShadeViewRefactor(RefactorComponent.INPUT)
- public void setLongPressListener(ExpandableNotificationRow.LongPressListener listener) {
- mLongPressListener = listener;
- }
-
@ShadeViewRefactor(RefactorComponent.ADAPTER)
public void setQsContainer(ViewGroup qsContainer) {
mQsContainer = qsContainer;
@@ -1273,7 +1266,7 @@ public class NotificationStackScrollLayout extends ViewGroup
return false;
}
- @ShadeViewRefactor(RefactorComponent.INPUT)
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
public ExpandableView getClosestChildAtRawPosition(float touchX, float touchY) {
getLocationOnScreen(mTempInt2);
float localTouchY = touchY - mTempInt2[1];
@@ -1303,16 +1296,8 @@ public class NotificationStackScrollLayout extends ViewGroup
return closestChild;
}
- @Override
- @ShadeViewRefactor(RefactorComponent.INPUT)
- public ExpandableView getChildAtRawPosition(float touchX, float touchY) {
- getLocationOnScreen(mTempInt2);
- return getChildAtPosition(touchX - mTempInt2[0], touchY - mTempInt2[1]);
- }
-
- @Override
- @ShadeViewRefactor(RefactorComponent.INPUT)
- public ExpandableView getChildAtPosition(float touchX, float touchY) {
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
+ private ExpandableView getChildAtPosition(float touchX, float touchY) {
return getChildAtPosition(touchX, touchY, true /* requireMinHeight */);
}
@@ -1325,7 +1310,7 @@ public class NotificationStackScrollLayout extends ViewGroup
* @param requireMinHeight Whether a minimum height is required for a child to be returned.
* @return the child at the given location.
*/
- @ShadeViewRefactor(RefactorComponent.INPUT)
+ @ShadeViewRefactor(RefactorComponent.COORDINATOR)
private ExpandableView getChildAtPosition(float touchX, float touchY,
boolean requireMinHeight) {
// find the view under the pointer, accounting for GONE views
@@ -1365,71 +1350,9 @@ public class NotificationStackScrollLayout extends ViewGroup
return null;
}
- @Override
- @ShadeViewRefactor(RefactorComponent.ADAPTER)
- public boolean canChildBeExpanded(View v) {
- return v instanceof ExpandableNotificationRow
- && ((ExpandableNotificationRow) v).isExpandable()
- && !((ExpandableNotificationRow) v).areGutsExposed()
- && (mIsExpanded || !((ExpandableNotificationRow) v).isPinned());
- }
-
- /* Only ever called as a consequence of an expansion gesture in the shade. */
- @Override
- @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
- public void setUserExpandedChild(View v, boolean userExpanded) {
- if (v instanceof ExpandableNotificationRow) {
- ExpandableNotificationRow row = (ExpandableNotificationRow) v;
- if (userExpanded && onKeyguard()) {
- // Due to a race when locking the screen while touching, a notification may be
- // expanded even after we went back to keyguard. An example of this happens if
- // you click in the empty space while expanding a group.
-
- // We also need to un-user lock it here, since otherwise the content height
- // calculated might be wrong. We also can't invert the two calls since
- // un-userlocking it will trigger a layout switch in the content view.
- row.setUserLocked(false);
- updateContentHeight();
- notifyHeightChangeListener(row);
- return;
- }
- row.setUserExpanded(userExpanded, true /* allowChildrenExpansion */);
- row.onExpandedByGesture(userExpanded);
- }
- }
-
- @Override
- @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
- public void setExpansionCancelled(View v) {
- if (v instanceof ExpandableNotificationRow) {
- ((ExpandableNotificationRow) v).setGroupExpansionChanging(false);
- }
- }
-
- @Override
- @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
- public void setUserLockedChild(View v, boolean userLocked) {
- if (v instanceof ExpandableNotificationRow) {
- ((ExpandableNotificationRow) v).setUserLocked(userLocked);
- }
- cancelLongPress();
- requestDisallowInterceptTouchEvent(true);
- }
-
- @Override
- @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
- public void expansionStateChanged(boolean isExpanding) {
- mExpandingNotification = isExpanding;
- if (!mExpandedInThisMotion) {
- mMaxScrollAfterExpand = mOwnScrollY;
- mExpandedInThisMotion = true;
- }
- }
-
- @Override
- @ShadeViewRefactor(RefactorComponent.COORDINATOR)
- public int getMaxExpandHeight(ExpandableView view) {
- return view.getMaxContentHeight();
+ private ExpandableView getChildAtRawPosition(float touchX, float touchY) {
+ getLocationOnScreen(mTempInt2);
+ return getChildAtPosition(touchX - mTempInt2[0], touchY - mTempInt2[1]);
}
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
@@ -1526,14 +1449,6 @@ public class NotificationStackScrollLayout extends ViewGroup
return mStatusBarState == StatusBarState.KEYGUARD;
}
- @ShadeViewRefactor(RefactorComponent.INPUT)
- private void setSwipingInProgress(boolean isSwiped) {
- mSwipingInProgress = isSwiped;
- if (isSwiped) {
- requestDisallowInterceptTouchEvent(true);
- }
- }
-
@Override
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
protected void onConfigurationChanged(Configuration newConfig) {
@@ -1567,249 +1482,6 @@ public class NotificationStackScrollLayout extends ViewGroup
return this;
}
- @Override
- @ShadeViewRefactor(RefactorComponent.INPUT)
- public boolean onTouchEvent(MotionEvent ev) {
- boolean isCancelOrUp = ev.getActionMasked() == MotionEvent.ACTION_CANCEL
- || ev.getActionMasked() == MotionEvent.ACTION_UP;
- handleEmptySpaceClick(ev);
- boolean expandWantsIt = false;
- if (mIsExpanded && !mSwipingInProgress && !mOnlyScrollingInThisMotion) {
- if (isCancelOrUp) {
- mExpandHelper.onlyObserveMovements(false);
- }
- boolean wasExpandingBefore = mExpandingNotification;
- expandWantsIt = mExpandHelper.onTouchEvent(ev);
- if (mExpandedInThisMotion && !mExpandingNotification && wasExpandingBefore
- && !mDisallowScrollingInThisMotion) {
- dispatchDownEventToScroller(ev);
- }
- }
- boolean scrollerWantsIt = false;
- if (mIsExpanded && !mSwipingInProgress && !mExpandingNotification
- && !mDisallowScrollingInThisMotion) {
- scrollerWantsIt = onScrollTouch(ev);
- }
- boolean horizontalSwipeWantsIt = false;
- if (!mIsBeingDragged
- && !mExpandingNotification
- && !mExpandedInThisMotion
- && !mOnlyScrollingInThisMotion
- && !mDisallowDismissInThisMotion) {
- horizontalSwipeWantsIt = mSwipeHelper.onTouchEvent(ev);
- }
-
- // Check if we need to clear any snooze leavebehinds
- NotificationGuts guts = mNotificationGutsManager.getExposedGuts();
- if (guts != null && !NotificationSwipeHelper.isTouchInView(ev, guts)
- && guts.getGutsContent() instanceof NotificationSnooze) {
- NotificationSnooze ns = (NotificationSnooze) guts.getGutsContent();
- if ((ns.isExpanded() && isCancelOrUp)
- || (!horizontalSwipeWantsIt && scrollerWantsIt)) {
- // If the leavebehind is expanded we clear it on the next up event, otherwise we
- // clear it on the next non-horizontal swipe or expand event.
- checkSnoozeLeavebehind();
- }
- }
- if (ev.getActionMasked() == MotionEvent.ACTION_UP) {
- mCheckForLeavebehind = true;
- }
- return horizontalSwipeWantsIt || scrollerWantsIt || expandWantsIt || super.onTouchEvent(ev);
- }
-
- @ShadeViewRefactor(RefactorComponent.INPUT)
- private void dispatchDownEventToScroller(MotionEvent ev) {
- MotionEvent downEvent = MotionEvent.obtain(ev);
- downEvent.setAction(MotionEvent.ACTION_DOWN);
- onScrollTouch(downEvent);
- downEvent.recycle();
- }
-
- @Override
- @ShadeViewRefactor(RefactorComponent.INPUT)
- public boolean onGenericMotionEvent(MotionEvent event) {
- if (!isScrollingEnabled() || !mIsExpanded || mSwipingInProgress || mExpandingNotification
- || mDisallowScrollingInThisMotion) {
- return false;
- }
- if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) {
- switch (event.getAction()) {
- case MotionEvent.ACTION_SCROLL: {
- if (!mIsBeingDragged) {
- final float vscroll = event.getAxisValue(MotionEvent.AXIS_VSCROLL);
- if (vscroll != 0) {
- final int delta = (int) (vscroll * getVerticalScrollFactor());
- final int range = getScrollRange();
- int oldScrollY = mOwnScrollY;
- int newScrollY = oldScrollY - delta;
- if (newScrollY < 0) {
- newScrollY = 0;
- } else if (newScrollY > range) {
- newScrollY = range;
- }
- if (newScrollY != oldScrollY) {
- setOwnScrollY(newScrollY);
- return true;
- }
- }
- }
- }
- }
- }
- return super.onGenericMotionEvent(event);
- }
-
- @ShadeViewRefactor(RefactorComponent.INPUT)
- private boolean onScrollTouch(MotionEvent ev) {
- if (!isScrollingEnabled()) {
- return false;
- }
- if (isInsideQsContainer(ev) && !mIsBeingDragged) {
- return false;
- }
- mForcedScroll = null;
- initVelocityTrackerIfNotExists();
- mVelocityTracker.addMovement(ev);
-
- final int action = ev.getAction();
-
- switch (action & MotionEvent.ACTION_MASK) {
- case MotionEvent.ACTION_DOWN: {
- if (getChildCount() == 0 || !isInContentBounds(ev)) {
- return false;
- }
- boolean isBeingDragged = !mScroller.isFinished();
- setIsBeingDragged(isBeingDragged);
- /*
- * If being flinged and user touches, stop the fling. isFinished
- * will be false if being flinged.
- */
- if (!mScroller.isFinished()) {
- mScroller.forceFinished(true);
- }
-
- // Remember where the motion event started
- mLastMotionY = (int) ev.getY();
- mDownX = (int) ev.getX();
- mActivePointerId = ev.getPointerId(0);
- break;
- }
- case MotionEvent.ACTION_MOVE:
- final int activePointerIndex = ev.findPointerIndex(mActivePointerId);
- if (activePointerIndex == -1) {
- Log.e(TAG, "Invalid pointerId=" + mActivePointerId + " in onTouchEvent");
- break;
- }
-
- final int y = (int) ev.getY(activePointerIndex);
- final int x = (int) ev.getX(activePointerIndex);
- int deltaY = mLastMotionY - y;
- final int xDiff = Math.abs(x - mDownX);
- final int yDiff = Math.abs(deltaY);
- if (!mIsBeingDragged && yDiff > mTouchSlop && yDiff > xDiff) {
- setIsBeingDragged(true);
- if (deltaY > 0) {
- deltaY -= mTouchSlop;
- } else {
- deltaY += mTouchSlop;
- }
- }
- if (mIsBeingDragged) {
- // Scroll to follow the motion event
- mLastMotionY = y;
- int range = getScrollRange();
- if (mExpandedInThisMotion) {
- range = Math.min(range, mMaxScrollAfterExpand);
- }
-
- float scrollAmount;
- if (deltaY < 0) {
- scrollAmount = overScrollDown(deltaY);
- } else {
- scrollAmount = overScrollUp(deltaY, range);
- }
-
- // Calling customOverScrollBy will call onCustomOverScrolled, which
- // sets the scrolling if applicable.
- if (scrollAmount != 0.0f) {
- // The scrolling motion could not be compensated with the
- // existing overScroll, we have to scroll the view
- customOverScrollBy((int) scrollAmount, mOwnScrollY,
- range, getHeight() / 2);
- // If we're scrolling, leavebehinds should be dismissed
- checkSnoozeLeavebehind();
- }
- }
- break;
- case MotionEvent.ACTION_UP:
- if (mIsBeingDragged) {
- final VelocityTracker velocityTracker = mVelocityTracker;
- velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
- int initialVelocity = (int) velocityTracker.getYVelocity(mActivePointerId);
-
- if (shouldOverScrollFling(initialVelocity)) {
- onOverScrollFling(true, initialVelocity);
- } else {
- if (getChildCount() > 0) {
- if ((Math.abs(initialVelocity) > mMinimumVelocity)) {
- float currentOverScrollTop = getCurrentOverScrollAmount(true);
- if (currentOverScrollTop == 0.0f || initialVelocity > 0) {
- fling(-initialVelocity);
- } else {
- onOverScrollFling(false, initialVelocity);
- }
- } else {
- if (mScroller.springBack(mScrollX, mOwnScrollY, 0, 0, 0,
- getScrollRange())) {
- animateScroll();
- }
- }
- }
- }
- mActivePointerId = INVALID_POINTER;
- endDrag();
- }
-
- break;
- case MotionEvent.ACTION_CANCEL:
- if (mIsBeingDragged && getChildCount() > 0) {
- if (mScroller.springBack(mScrollX, mOwnScrollY, 0, 0, 0, getScrollRange())) {
- animateScroll();
- }
- mActivePointerId = INVALID_POINTER;
- endDrag();
- }
- break;
- case MotionEvent.ACTION_POINTER_DOWN: {
- final int index = ev.getActionIndex();
- mLastMotionY = (int) ev.getY(index);
- mDownX = (int) ev.getX(index);
- mActivePointerId = ev.getPointerId(index);
- break;
- }
- case MotionEvent.ACTION_POINTER_UP:
- onSecondaryPointerUp(ev);
- mLastMotionY = (int) ev.getY(ev.findPointerIndex(mActivePointerId));
- mDownX = (int) ev.getX(ev.findPointerIndex(mActivePointerId));
- break;
- }
- return true;
- }
-
- @ShadeViewRefactor(RefactorComponent.INPUT)
- protected boolean isInsideQsContainer(MotionEvent ev) {
- return ev.getY() < mQsContainer.getBottom();
- }
-
- @ShadeViewRefactor(RefactorComponent.INPUT)
- private void onOverScrollFling(boolean open, int initialVelocity) {
- if (mOverscrollTopChangedListener != null) {
- mOverscrollTopChangedListener.flingTopOverscroll(initialVelocity, open);
- }
- mDontReportNextOverScroll = true;
- setOverScrollAmount(0.0f, true, false);
- }
-
/**
* Perform a scroll upwards and adapt the overscroll amounts accordingly
*
@@ -1817,7 +1489,7 @@ public class NotificationStackScrollLayout extends ViewGroup
* @return The amount of scrolling to be performed by the scroller,
* not handled by the overScroll amount.
*/
- @ShadeViewRefactor(RefactorComponent.INPUT)
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
private float overScrollUp(int deltaY, int range) {
deltaY = Math.max(deltaY, 0);
float currentTopAmount = getCurrentOverScrollAmount(true);
@@ -1876,24 +1548,6 @@ public class NotificationStackScrollLayout extends ViewGroup
return scrollAmount;
}
- @ShadeViewRefactor(RefactorComponent.INPUT)
- private void onSecondaryPointerUp(MotionEvent ev) {
- final int pointerIndex = (ev.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK) >>
- MotionEvent.ACTION_POINTER_INDEX_SHIFT;
- final int pointerId = ev.getPointerId(pointerIndex);
- if (pointerId == mActivePointerId) {
- // This was our active pointer going up. Choose a new
- // active pointer and adjust accordingly.
- // TODO: Make this decision more intelligent.
- final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
- mLastMotionY = (int) ev.getY(newPointerIndex);
- mActivePointerId = ev.getPointerId(newPointerIndex);
- if (mVelocityTracker != null) {
- mVelocityTracker.clear();
- }
- }
- }
-
@ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void initVelocityTrackerIfNotExists() {
if (mVelocityTracker == null) {
@@ -2636,7 +2290,7 @@ public class NotificationStackScrollLayout extends ViewGroup
* numbers mean that the finger/cursor is moving down the screen,
* which means we want to scroll towards the top.
*/
- @ShadeViewRefactor(RefactorComponent.INPUT)
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
protected void fling(int velocityY) {
if (getChildCount() > 0) {
int scrollRange = getScrollRange();
@@ -2674,7 +2328,7 @@ public class NotificationStackScrollLayout extends ViewGroup
* @return Whether a fling performed on the top overscroll edge lead to the expanded
* overScroll view (i.e QS).
*/
- @ShadeViewRefactor(RefactorComponent.INPUT)
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
private boolean shouldOverScrollFling(int initialVelocity) {
float topOverScroll = getCurrentOverScrollAmount(true);
return mScrolledToTopOnFirstDown
@@ -2757,7 +2411,7 @@ public class NotificationStackScrollLayout extends ViewGroup
return Math.max(desiredPadding, mIntrinsicPadding);
}
- @ShadeViewRefactor(RefactorComponent.INPUT)
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
private float getRubberBandFactor(boolean onTop) {
if (!onTop) {
return RUBBER_BAND_FACTOR_NORMAL;
@@ -2777,99 +2431,13 @@ public class NotificationStackScrollLayout extends ViewGroup
* rubberbanded, false if it is technically an overscroll but rather a motion to expand the
* overscroll view (e.g. expand QS).
*/
- @ShadeViewRefactor(RefactorComponent.INPUT)
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
private boolean isRubberbanded(boolean onTop) {
return !onTop || mExpandedInThisMotion || mIsExpansionChanging || mPanelTracking
|| !mScrolledToTopOnFirstDown;
}
- @ShadeViewRefactor(RefactorComponent.INPUT)
- private void endDrag() {
- setIsBeingDragged(false);
-
- recycleVelocityTracker();
-
- if (getCurrentOverScrollAmount(true /* onTop */) > 0) {
- setOverScrollAmount(0, true /* onTop */, true /* animate */);
- }
- if (getCurrentOverScrollAmount(false /* onTop */) > 0) {
- setOverScrollAmount(0, false /* onTop */, true /* animate */);
- }
- }
-
- @ShadeViewRefactor(RefactorComponent.INPUT)
- private void transformTouchEvent(MotionEvent ev, View sourceView, View targetView) {
- ev.offsetLocation(sourceView.getX(), sourceView.getY());
- ev.offsetLocation(-targetView.getX(), -targetView.getY());
- }
-
- @Override
- @ShadeViewRefactor(RefactorComponent.INPUT)
- public boolean onInterceptTouchEvent(MotionEvent ev) {
- initDownStates(ev);
- handleEmptySpaceClick(ev);
- boolean expandWantsIt = false;
- if (!mSwipingInProgress && !mOnlyScrollingInThisMotion) {
- expandWantsIt = mExpandHelper.onInterceptTouchEvent(ev);
- }
- boolean scrollWantsIt = false;
- if (!mSwipingInProgress && !mExpandingNotification) {
- scrollWantsIt = onInterceptTouchEventScroll(ev);
- }
- boolean swipeWantsIt = false;
- if (!mIsBeingDragged
- && !mExpandingNotification
- && !mExpandedInThisMotion
- && !mOnlyScrollingInThisMotion
- && !mDisallowDismissInThisMotion) {
- swipeWantsIt = mSwipeHelper.onInterceptTouchEvent(ev);
- }
- // Check if we need to clear any snooze leavebehinds
- boolean isUp = ev.getActionMasked() == MotionEvent.ACTION_UP;
- NotificationGuts guts = mNotificationGutsManager.getExposedGuts();
- if (!NotificationSwipeHelper.isTouchInView(ev, guts) && isUp && !swipeWantsIt &&
- !expandWantsIt && !scrollWantsIt) {
- mCheckForLeavebehind = false;
- mNotificationGutsManager.closeAndSaveGuts(true /* removeLeavebehind */,
- false /* force */, false /* removeControls */, -1 /* x */, -1 /* y */,
- false /* resetMenu */);
- }
- if (ev.getActionMasked() == MotionEvent.ACTION_UP) {
- mCheckForLeavebehind = true;
- }
- return swipeWantsIt || scrollWantsIt || expandWantsIt || super.onInterceptTouchEvent(ev);
- }
-
- @ShadeViewRefactor(RefactorComponent.INPUT)
- private void handleEmptySpaceClick(MotionEvent ev) {
- switch (ev.getActionMasked()) {
- case MotionEvent.ACTION_MOVE:
- if (mTouchIsClick && (Math.abs(ev.getY() - mInitialTouchY) > mTouchSlop
- || Math.abs(ev.getX() - mInitialTouchX) > mTouchSlop)) {
- mTouchIsClick = false;
- }
- break;
- case MotionEvent.ACTION_UP:
- if (mStatusBarState != StatusBarState.KEYGUARD && mTouchIsClick &&
- isBelowLastNotification(mInitialTouchX, mInitialTouchY)) {
- mOnEmptySpaceClickListener.onEmptySpaceClicked(mInitialTouchX, mInitialTouchY);
- }
- break;
- }
- }
- @ShadeViewRefactor(RefactorComponent.INPUT)
- private void initDownStates(MotionEvent ev) {
- if (ev.getAction() == MotionEvent.ACTION_DOWN) {
- mExpandedInThisMotion = false;
- mOnlyScrollingInThisMotion = !mScroller.isFinished();
- mDisallowScrollingInThisMotion = false;
- mDisallowDismissInThisMotion = false;
- mTouchIsClick = true;
- mInitialTouchX = ev.getX();
- mInitialTouchY = ev.getY();
- }
- }
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void setChildTransferInProgress(boolean childTransferInProgress) {
@@ -2896,15 +2464,6 @@ public class NotificationStackScrollLayout extends ViewGroup
mCurrentStackScrollState.removeViewStateForView(child);
}
- @Override
- @ShadeViewRefactor(RefactorComponent.INPUT)
- public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
- super.requestDisallowInterceptTouchEvent(disallowIntercept);
- if (disallowIntercept) {
- cancelLongPress();
- }
- }
-
@ShadeViewRefactor(RefactorComponent.COORDINATOR)
private void onViewRemovedInternal(View child, ViewGroup container) {
if (mChangePositionInProgress) {
@@ -3600,6 +3159,385 @@ public class NotificationStackScrollLayout extends ViewGroup
mGoToFullShadeNeedsAnimation = false;
}
+ @ShadeViewRefactor(RefactorComponent.LAYOUT_ALGORITHM)
+ protected StackScrollAlgorithm createStackScrollAlgorithm(Context context) {
+ return new StackScrollAlgorithm(context);
+ }
+
+ /**
+ * @return Whether a y coordinate is inside the content.
+ */
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
+ public boolean isInContentBounds(float y) {
+ return y < getHeight() - getEmptyBottomMargin();
+ }
+
+ @ShadeViewRefactor(RefactorComponent.INPUT)
+ public void setLongPressListener(ExpandableNotificationRow.LongPressListener listener) {
+ mLongPressListener = listener;
+ }
+
+ @Override
+ @ShadeViewRefactor(RefactorComponent.INPUT)
+ public boolean onTouchEvent(MotionEvent ev) {
+ boolean isCancelOrUp = ev.getActionMasked() == MotionEvent.ACTION_CANCEL
+ || ev.getActionMasked() == MotionEvent.ACTION_UP;
+ handleEmptySpaceClick(ev);
+ boolean expandWantsIt = false;
+ boolean swipingInProgress = mSwipeHelper.isSwipingInProgress();
+ if (mIsExpanded && !swipingInProgress && !mOnlyScrollingInThisMotion) {
+ if (isCancelOrUp) {
+ mExpandHelper.onlyObserveMovements(false);
+ }
+ boolean wasExpandingBefore = mExpandingNotification;
+ expandWantsIt = mExpandHelper.onTouchEvent(ev);
+ if (mExpandedInThisMotion && !mExpandingNotification && wasExpandingBefore
+ && !mDisallowScrollingInThisMotion) {
+ dispatchDownEventToScroller(ev);
+ }
+ }
+ boolean scrollerWantsIt = false;
+ if (mIsExpanded && !swipingInProgress && !mExpandingNotification
+ && !mDisallowScrollingInThisMotion) {
+ scrollerWantsIt = onScrollTouch(ev);
+ }
+ boolean horizontalSwipeWantsIt = false;
+ if (!mIsBeingDragged
+ && !mExpandingNotification
+ && !mExpandedInThisMotion
+ && !mOnlyScrollingInThisMotion
+ && !mDisallowDismissInThisMotion) {
+ horizontalSwipeWantsIt = mSwipeHelper.onTouchEvent(ev);
+ }
+
+ // Check if we need to clear any snooze leavebehinds
+ NotificationGuts guts = mNotificationGutsManager.getExposedGuts();
+ if (guts != null && !NotificationSwipeHelper.isTouchInView(ev, guts)
+ && guts.getGutsContent() instanceof NotificationSnooze) {
+ NotificationSnooze ns = (NotificationSnooze) guts.getGutsContent();
+ if ((ns.isExpanded() && isCancelOrUp)
+ || (!horizontalSwipeWantsIt && scrollerWantsIt)) {
+ // If the leavebehind is expanded we clear it on the next up event, otherwise we
+ // clear it on the next non-horizontal swipe or expand event.
+ checkSnoozeLeavebehind();
+ }
+ }
+ if (ev.getActionMasked() == MotionEvent.ACTION_UP) {
+ mCheckForLeavebehind = true;
+ }
+ return horizontalSwipeWantsIt || scrollerWantsIt || expandWantsIt || super.onTouchEvent(ev);
+ }
+
+ @ShadeViewRefactor(RefactorComponent.INPUT)
+ private void dispatchDownEventToScroller(MotionEvent ev) {
+ MotionEvent downEvent = MotionEvent.obtain(ev);
+ downEvent.setAction(MotionEvent.ACTION_DOWN);
+ onScrollTouch(downEvent);
+ downEvent.recycle();
+ }
+
+ @Override
+ @ShadeViewRefactor(RefactorComponent.INPUT)
+ public boolean onGenericMotionEvent(MotionEvent event) {
+ if (!isScrollingEnabled() || !mIsExpanded || mSwipeHelper.isSwipingInProgress() || mExpandingNotification
+ || mDisallowScrollingInThisMotion) {
+ return false;
+ }
+ if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) {
+ switch (event.getAction()) {
+ case MotionEvent.ACTION_SCROLL: {
+ if (!mIsBeingDragged) {
+ final float vscroll = event.getAxisValue(MotionEvent.AXIS_VSCROLL);
+ if (vscroll != 0) {
+ final int delta = (int) (vscroll * getVerticalScrollFactor());
+ final int range = getScrollRange();
+ int oldScrollY = mOwnScrollY;
+ int newScrollY = oldScrollY - delta;
+ if (newScrollY < 0) {
+ newScrollY = 0;
+ } else if (newScrollY > range) {
+ newScrollY = range;
+ }
+ if (newScrollY != oldScrollY) {
+ setOwnScrollY(newScrollY);
+ return true;
+ }
+ }
+ }
+ }
+ }
+ }
+ return super.onGenericMotionEvent(event);
+ }
+
+ @ShadeViewRefactor(RefactorComponent.INPUT)
+ private boolean onScrollTouch(MotionEvent ev) {
+ if (!isScrollingEnabled()) {
+ return false;
+ }
+ if (isInsideQsContainer(ev) && !mIsBeingDragged) {
+ return false;
+ }
+ mForcedScroll = null;
+ initVelocityTrackerIfNotExists();
+ mVelocityTracker.addMovement(ev);
+
+ final int action = ev.getAction();
+
+ switch (action & MotionEvent.ACTION_MASK) {
+ case MotionEvent.ACTION_DOWN: {
+ if (getChildCount() == 0 || !isInContentBounds(ev)) {
+ return false;
+ }
+ boolean isBeingDragged = !mScroller.isFinished();
+ setIsBeingDragged(isBeingDragged);
+ /*
+ * If being flinged and user touches, stop the fling. isFinished
+ * will be false if being flinged.
+ */
+ if (!mScroller.isFinished()) {
+ mScroller.forceFinished(true);
+ }
+
+ // Remember where the motion event started
+ mLastMotionY = (int) ev.getY();
+ mDownX = (int) ev.getX();
+ mActivePointerId = ev.getPointerId(0);
+ break;
+ }
+ case MotionEvent.ACTION_MOVE:
+ final int activePointerIndex = ev.findPointerIndex(mActivePointerId);
+ if (activePointerIndex == -1) {
+ Log.e(TAG, "Invalid pointerId=" + mActivePointerId + " in onTouchEvent");
+ break;
+ }
+
+ final int y = (int) ev.getY(activePointerIndex);
+ final int x = (int) ev.getX(activePointerIndex);
+ int deltaY = mLastMotionY - y;
+ final int xDiff = Math.abs(x - mDownX);
+ final int yDiff = Math.abs(deltaY);
+ if (!mIsBeingDragged && yDiff > mTouchSlop && yDiff > xDiff) {
+ setIsBeingDragged(true);
+ if (deltaY > 0) {
+ deltaY -= mTouchSlop;
+ } else {
+ deltaY += mTouchSlop;
+ }
+ }
+ if (mIsBeingDragged) {
+ // Scroll to follow the motion event
+ mLastMotionY = y;
+ int range = getScrollRange();
+ if (mExpandedInThisMotion) {
+ range = Math.min(range, mMaxScrollAfterExpand);
+ }
+
+ float scrollAmount;
+ if (deltaY < 0) {
+ scrollAmount = overScrollDown(deltaY);
+ } else {
+ scrollAmount = overScrollUp(deltaY, range);
+ }
+
+ // Calling customOverScrollBy will call onCustomOverScrolled, which
+ // sets the scrolling if applicable.
+ if (scrollAmount != 0.0f) {
+ // The scrolling motion could not be compensated with the
+ // existing overScroll, we have to scroll the view
+ customOverScrollBy((int) scrollAmount, mOwnScrollY,
+ range, getHeight() / 2);
+ // If we're scrolling, leavebehinds should be dismissed
+ checkSnoozeLeavebehind();
+ }
+ }
+ break;
+ case MotionEvent.ACTION_UP:
+ if (mIsBeingDragged) {
+ final VelocityTracker velocityTracker = mVelocityTracker;
+ velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
+ int initialVelocity = (int) velocityTracker.getYVelocity(mActivePointerId);
+
+ if (shouldOverScrollFling(initialVelocity)) {
+ onOverScrollFling(true, initialVelocity);
+ } else {
+ if (getChildCount() > 0) {
+ if ((Math.abs(initialVelocity) > mMinimumVelocity)) {
+ float currentOverScrollTop = getCurrentOverScrollAmount(true);
+ if (currentOverScrollTop == 0.0f || initialVelocity > 0) {
+ fling(-initialVelocity);
+ } else {
+ onOverScrollFling(false, initialVelocity);
+ }
+ } else {
+ if (mScroller.springBack(mScrollX, mOwnScrollY, 0, 0, 0,
+ getScrollRange())) {
+ animateScroll();
+ }
+ }
+ }
+ }
+ mActivePointerId = INVALID_POINTER;
+ endDrag();
+ }
+
+ break;
+ case MotionEvent.ACTION_CANCEL:
+ if (mIsBeingDragged && getChildCount() > 0) {
+ if (mScroller.springBack(mScrollX, mOwnScrollY, 0, 0, 0, getScrollRange())) {
+ animateScroll();
+ }
+ mActivePointerId = INVALID_POINTER;
+ endDrag();
+ }
+ break;
+ case MotionEvent.ACTION_POINTER_DOWN: {
+ final int index = ev.getActionIndex();
+ mLastMotionY = (int) ev.getY(index);
+ mDownX = (int) ev.getX(index);
+ mActivePointerId = ev.getPointerId(index);
+ break;
+ }
+ case MotionEvent.ACTION_POINTER_UP:
+ onSecondaryPointerUp(ev);
+ mLastMotionY = (int) ev.getY(ev.findPointerIndex(mActivePointerId));
+ mDownX = (int) ev.getX(ev.findPointerIndex(mActivePointerId));
+ break;
+ }
+ return true;
+ }
+
+ @ShadeViewRefactor(RefactorComponent.INPUT)
+ protected boolean isInsideQsContainer(MotionEvent ev) {
+ return ev.getY() < mQsContainer.getBottom();
+ }
+
+ @ShadeViewRefactor(RefactorComponent.INPUT)
+ private void onOverScrollFling(boolean open, int initialVelocity) {
+ if (mOverscrollTopChangedListener != null) {
+ mOverscrollTopChangedListener.flingTopOverscroll(initialVelocity, open);
+ }
+ mDontReportNextOverScroll = true;
+ setOverScrollAmount(0.0f, true, false);
+ }
+
+
+ @ShadeViewRefactor(RefactorComponent.INPUT)
+ private void onSecondaryPointerUp(MotionEvent ev) {
+ final int pointerIndex = (ev.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK) >>
+ MotionEvent.ACTION_POINTER_INDEX_SHIFT;
+ final int pointerId = ev.getPointerId(pointerIndex);
+ if (pointerId == mActivePointerId) {
+ // This was our active pointer going up. Choose a new
+ // active pointer and adjust accordingly.
+ // TODO: Make this decision more intelligent.
+ final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
+ mLastMotionY = (int) ev.getY(newPointerIndex);
+ mActivePointerId = ev.getPointerId(newPointerIndex);
+ if (mVelocityTracker != null) {
+ mVelocityTracker.clear();
+ }
+ }
+ }
+
+ @ShadeViewRefactor(RefactorComponent.INPUT)
+ private void endDrag() {
+ setIsBeingDragged(false);
+
+ recycleVelocityTracker();
+
+ if (getCurrentOverScrollAmount(true /* onTop */) > 0) {
+ setOverScrollAmount(0, true /* onTop */, true /* animate */);
+ }
+ if (getCurrentOverScrollAmount(false /* onTop */) > 0) {
+ setOverScrollAmount(0, false /* onTop */, true /* animate */);
+ }
+ }
+
+ @ShadeViewRefactor(RefactorComponent.INPUT)
+ private void transformTouchEvent(MotionEvent ev, View sourceView, View targetView) {
+ ev.offsetLocation(sourceView.getX(), sourceView.getY());
+ ev.offsetLocation(-targetView.getX(), -targetView.getY());
+ }
+
+ @Override
+ @ShadeViewRefactor(RefactorComponent.INPUT)
+ public boolean onInterceptTouchEvent(MotionEvent ev) {
+ initDownStates(ev);
+ handleEmptySpaceClick(ev);
+ boolean expandWantsIt = false;
+ boolean swipingInProgress = mSwipeHelper.isSwipingInProgress();
+ if (!swipingInProgress && !mOnlyScrollingInThisMotion) {
+ expandWantsIt = mExpandHelper.onInterceptTouchEvent(ev);
+ }
+ boolean scrollWantsIt = false;
+ if (!swipingInProgress && !mExpandingNotification) {
+ scrollWantsIt = onInterceptTouchEventScroll(ev);
+ }
+ boolean swipeWantsIt = false;
+ if (!mIsBeingDragged
+ && !mExpandingNotification
+ && !mExpandedInThisMotion
+ && !mOnlyScrollingInThisMotion
+ && !mDisallowDismissInThisMotion) {
+ swipeWantsIt = mSwipeHelper.onInterceptTouchEvent(ev);
+ }
+ // Check if we need to clear any snooze leavebehinds
+ boolean isUp = ev.getActionMasked() == MotionEvent.ACTION_UP;
+ NotificationGuts guts = mNotificationGutsManager.getExposedGuts();
+ if (!NotificationSwipeHelper.isTouchInView(ev, guts) && isUp && !swipeWantsIt &&
+ !expandWantsIt && !scrollWantsIt) {
+ mCheckForLeavebehind = false;
+ mNotificationGutsManager.closeAndSaveGuts(true /* removeLeavebehind */,
+ false /* force */, false /* removeControls */, -1 /* x */, -1 /* y */,
+ false /* resetMenu */);
+ }
+ if (ev.getActionMasked() == MotionEvent.ACTION_UP) {
+ mCheckForLeavebehind = true;
+ }
+ return swipeWantsIt || scrollWantsIt || expandWantsIt || super.onInterceptTouchEvent(ev);
+ }
+
+ @ShadeViewRefactor(RefactorComponent.INPUT)
+ private void handleEmptySpaceClick(MotionEvent ev) {
+ switch (ev.getActionMasked()) {
+ case MotionEvent.ACTION_MOVE:
+ if (mTouchIsClick && (Math.abs(ev.getY() - mInitialTouchY) > mTouchSlop
+ || Math.abs(ev.getX() - mInitialTouchX) > mTouchSlop)) {
+ mTouchIsClick = false;
+ }
+ break;
+ case MotionEvent.ACTION_UP:
+ if (mStatusBarState != StatusBarState.KEYGUARD && mTouchIsClick &&
+ isBelowLastNotification(mInitialTouchX, mInitialTouchY)) {
+ mOnEmptySpaceClickListener.onEmptySpaceClicked(mInitialTouchX, mInitialTouchY);
+ }
+ break;
+ }
+ }
+
+ @ShadeViewRefactor(RefactorComponent.INPUT)
+ private void initDownStates(MotionEvent ev) {
+ if (ev.getAction() == MotionEvent.ACTION_DOWN) {
+ mExpandedInThisMotion = false;
+ mOnlyScrollingInThisMotion = !mScroller.isFinished();
+ mDisallowScrollingInThisMotion = false;
+ mDisallowDismissInThisMotion = false;
+ mTouchIsClick = true;
+ mInitialTouchX = ev.getX();
+ mInitialTouchY = ev.getY();
+ }
+ }
+
+ @Override
+ @ShadeViewRefactor(RefactorComponent.INPUT)
+ public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
+ super.requestDisallowInterceptTouchEvent(disallowIntercept);
+ if (disallowIntercept) {
+ cancelLongPress();
+ }
+ }
+
@ShadeViewRefactor(RefactorComponent.INPUT)
private boolean onInterceptTouchEventScroll(MotionEvent ev) {
if (!isScrollingEnabled()) {
@@ -3710,11 +3648,6 @@ public class NotificationStackScrollLayout extends ViewGroup
return mIsBeingDragged;
}
- @ShadeViewRefactor(RefactorComponent.LAYOUT_ALGORITHM)
- protected StackScrollAlgorithm createStackScrollAlgorithm(Context context) {
- return new StackScrollAlgorithm(context);
- }
-
/**
* @return Whether the specified motion event is actually happening over the content.
*/
@@ -3723,13 +3656,6 @@ public class NotificationStackScrollLayout extends ViewGroup
return isInContentBounds(event.getY());
}
- /**
- * @return Whether a y coordinate is inside the content.
- */
- @ShadeViewRefactor(RefactorComponent.INPUT)
- public boolean isInContentBounds(float y) {
- return y < getHeight() - getEmptyBottomMargin();
- }
@VisibleForTesting
@ShadeViewRefactor(RefactorComponent.INPUT)
@@ -3742,6 +3668,83 @@ public class NotificationStackScrollLayout extends ViewGroup
}
}
+ @ShadeViewRefactor(RefactorComponent.INPUT)
+ public void requestDisallowLongPress() {
+ cancelLongPress();
+ }
+
+ @ShadeViewRefactor(RefactorComponent.INPUT)
+ public void requestDisallowDismiss() {
+ mDisallowDismissInThisMotion = true;
+ }
+
+ @ShadeViewRefactor(RefactorComponent.INPUT)
+ public void cancelLongPress() {
+ mSwipeHelper.cancelLongPress();
+ }
+
+ @ShadeViewRefactor(RefactorComponent.INPUT)
+ public void setOnEmptySpaceClickListener(OnEmptySpaceClickListener listener) {
+ mOnEmptySpaceClickListener = listener;
+ }
+
+ /** @hide */
+ @Override
+ @ShadeViewRefactor(RefactorComponent.INPUT)
+ public boolean performAccessibilityActionInternal(int action, Bundle arguments) {
+ if (super.performAccessibilityActionInternal(action, arguments)) {
+ return true;
+ }
+ if (!isEnabled()) {
+ return false;
+ }
+ int direction = -1;
+ switch (action) {
+ case AccessibilityNodeInfo.ACTION_SCROLL_FORWARD:
+ // fall through
+ case android.R.id.accessibilityActionScrollDown:
+ direction = 1;
+ // fall through
+ case AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD:
+ // fall through
+ case android.R.id.accessibilityActionScrollUp:
+ final int viewportHeight = getHeight() - mPaddingBottom - mTopPadding - mPaddingTop
+ - mShelf.getIntrinsicHeight();
+ final int targetScrollY = Math.max(0,
+ Math.min(mOwnScrollY + direction * viewportHeight, getScrollRange()));
+ if (targetScrollY != mOwnScrollY) {
+ mScroller.startScroll(mScrollX, mOwnScrollY, 0, targetScrollY - mOwnScrollY);
+ animateScroll();
+ return true;
+ }
+ break;
+ }
+ return false;
+ }
+
+ @ShadeViewRefactor(RefactorComponent.INPUT)
+ public void closeControlsIfOutsideTouch(MotionEvent ev) {
+ NotificationGuts guts = mNotificationGutsManager.getExposedGuts();
+ NotificationMenuRowPlugin menuRow = mSwipeHelper.getCurrentMenuRow();
+ View translatingParentView = mSwipeHelper.getTranslatingParentView();
+ View view = null;
+ if (guts != null && !guts.getGutsContent().isLeavebehind()) {
+ // Only close visible guts if they're not a leavebehind.
+ view = guts;
+ } else if (menuRow != null && menuRow.isMenuVisible()
+ && translatingParentView != null) {
+ // Checking menu
+ view = translatingParentView;
+ }
+ if (view != null && !NotificationSwipeHelper.isTouchInView(ev, view)) {
+ // Touch was outside visible guts / menu notification, close what's visible
+ mNotificationGutsManager.closeAndSaveGuts(false /* removeLeavebehind */,
+ false /* force */, true /* removeControls */, -1 /* x */, -1 /* y */,
+ false /* resetMenu */);
+ resetExposedMenuView(true /* animate */, true /* force */);
+ }
+ }
+
@Override
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void onWindowFocusChanged(boolean hasWindowFocus) {
@@ -3760,21 +3763,6 @@ public class NotificationStackScrollLayout extends ViewGroup
}
}
- @ShadeViewRefactor(RefactorComponent.INPUT)
- public void requestDisallowLongPress() {
- cancelLongPress();
- }
-
- @ShadeViewRefactor(RefactorComponent.INPUT)
- public void requestDisallowDismiss() {
- mDisallowDismissInThisMotion = true;
- }
-
- @ShadeViewRefactor(RefactorComponent.INPUT)
- public void cancelLongPress() {
- mSwipeHelper.cancelLongPress();
- }
-
@Override
@ShadeViewRefactor(RefactorComponent.COORDINATOR)
public boolean isScrolledToTop() {
@@ -3916,7 +3904,6 @@ public class NotificationStackScrollLayout extends ViewGroup
}
@Override
- @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
public void onHeightChanged(ExpandableView view, boolean needsAnimation) {
updateContentHeight();
updateScrollPositionOnExpandInBottom(view);
@@ -3936,7 +3923,6 @@ public class NotificationStackScrollLayout extends ViewGroup
}
@Override
- @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void onReset(ExpandableView view) {
updateAnimationState(view);
updateChronometerForChild(view);
@@ -3969,13 +3955,8 @@ public class NotificationStackScrollLayout extends ViewGroup
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void setOnHeightChangedListener(
- ExpandableView.OnHeightChangedListener mOnHeightChangedListener) {
- this.mOnHeightChangedListener = mOnHeightChangedListener;
- }
-
- @ShadeViewRefactor(RefactorComponent.INPUT)
- public void setOnEmptySpaceClickListener(OnEmptySpaceClickListener listener) {
- mOnEmptySpaceClickListener = listener;
+ ExpandableView.OnHeightChangedListener onHeightChangedListener) {
+ this.mOnHeightChangedListener = onHeightChangedListener;
}
@ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
@@ -4465,7 +4446,7 @@ public class NotificationStackScrollLayout extends ViewGroup
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void setGroupManager(NotificationGroupManager groupManager) {
this.mGroupManager = groupManager;
- mGroupManager.setOnGroupChangeListener(this);
+ mGroupManager.setOnGroupChangeListener(mOnGroupChangeListener);
}
@ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
@@ -4508,33 +4489,6 @@ public class NotificationStackScrollLayout extends ViewGroup
return touchY > mTopPadding + mStackTranslation;
}
- @Override
- @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
- public void onGroupExpansionChanged(ExpandableNotificationRow changedRow, boolean expanded) {
- boolean animated = !mGroupExpandedForMeasure && mAnimationsEnabled
- && (mIsExpanded || changedRow.isPinned());
- if (animated) {
- mExpandedGroupView = changedRow;
- mNeedsAnimation = true;
- }
- changedRow.setChildrenExpanded(expanded, animated);
- if (!mGroupExpandedForMeasure) {
- onHeightChanged(changedRow, false /* needsAnimation */);
- }
- runAfterAnimationFinished(new Runnable() {
- @Override
- public void run() {
- changedRow.onFinishedExpansionChange();
- }
- });
- }
-
- @Override
- @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
- public void onGroupCreatedFromChildren(NotificationGroupManager.NotificationGroup group) {
- mStatusBar.requestNotificationUpdate();
- }
-
/** @hide */
@Override
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
@@ -4567,46 +4521,6 @@ public class NotificationStackScrollLayout extends ViewGroup
info.setClassName(ScrollView.class.getName());
}
- /** @hide */
- @Override
- @ShadeViewRefactor(RefactorComponent.INPUT)
- public boolean performAccessibilityActionInternal(int action, Bundle arguments) {
- if (super.performAccessibilityActionInternal(action, arguments)) {
- return true;
- }
- if (!isEnabled()) {
- return false;
- }
- int direction = -1;
- switch (action) {
- case AccessibilityNodeInfo.ACTION_SCROLL_FORWARD:
- // fall through
- case android.R.id.accessibilityActionScrollDown:
- direction = 1;
- // fall through
- case AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD:
- // fall through
- case android.R.id.accessibilityActionScrollUp:
- final int viewportHeight = getHeight() - mPaddingBottom - mTopPadding - mPaddingTop
- - mShelf.getIntrinsicHeight();
- final int targetScrollY = Math.max(0,
- Math.min(mOwnScrollY + direction * viewportHeight, getScrollRange()));
- if (targetScrollY != mOwnScrollY) {
- mScroller.startScroll(mScrollX, mOwnScrollY, 0, targetScrollY - mOwnScrollY);
- animateScroll();
- return true;
- }
- break;
- }
- return false;
- }
-
- @Override
- @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
- public void onGroupsChanged() {
- mStatusBar.requestNotificationUpdate();
- }
-
@ShadeViewRefactor(RefactorComponent.COORDINATOR)
public void generateChildOrderChangedEvent() {
if (mIsExpanded && mAnimationsEnabled) {
@@ -4649,7 +4563,7 @@ public class NotificationStackScrollLayout extends ViewGroup
public void setHeadsUpManager(HeadsUpManagerPhone headsUpManager) {
mHeadsUpManager = headsUpManager;
mHeadsUpManager.addListener(mRoundnessManager);
- mHeadsUpManager.setAnimationStateHandler(this);
+ mHeadsUpManager.setAnimationStateHandler(this::setHeadsUpGoingAwayAnimationsAllowed);
}
@ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
@@ -4912,6 +4826,34 @@ public class NotificationStackScrollLayout extends ViewGroup
mMaxTopPadding,
mShouldShowShelfOnly ? "T" : "f",
mQsExpansionFraction));
+ int childCount = getChildCount();
+ pw.println(" Number of children: " + childCount);
+ pw.println();
+
+ for (int i = 0; i < childCount; i++) {
+ ExpandableView child = (ExpandableView) getChildAt(i);
+ child.dump(fd, pw, args);
+ if (!(child instanceof ExpandableNotificationRow)) {
+ pw.println(" " + child.getClass().getSimpleName());
+ // Notifications dump it's viewstate as part of their dump to support children
+ ExpandableViewState viewState = mCurrentStackScrollState.getViewStateForView(
+ child);
+ if (viewState == null) {
+ pw.println(" no viewState!!!");
+ } else {
+ pw.print(" ");
+ viewState.dump(fd, pw, args);
+ pw.println();
+ pw.println();
+ }
+ }
+ }
+ pw.println(" Transient Views: " + childCount);
+ int transientViewCount = getTransientViewCount();
+ for (int i = 0; i < transientViewCount; i++) {
+ ExpandableView child = (ExpandableView) getTransientView(i);
+ child.dump(fd, pw, args);
+ }
}
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
@@ -5140,67 +5082,7 @@ public class NotificationStackScrollLayout extends ViewGroup
return !mEntryManager.getNotificationData().getActiveNotifications().isEmpty();
}
- // ---------------------- DragDownHelper.OnDragDownListener ------------------------------------
-
-
- /* Only ever called as a consequence of a lockscreen expansion gesture. */
- @Override
- @ShadeViewRefactor(RefactorComponent.INPUT)
- public boolean onDraggedDown(View startingChild, int dragLengthY) {
- if (mStatusBarState == StatusBarState.KEYGUARD
- && hasActiveNotifications() && (!mStatusBar.isDozing() || mStatusBar.isPulsing())) {
- mLockscreenGestureLogger.write(
- MetricsEvent.ACTION_LS_SHADE,
- (int) (dragLengthY / mDisplayMetrics.density),
- 0 /* velocityDp - N/A */);
-
- // We have notifications, go to locked shade.
- mStatusBar.goToLockedShade(startingChild);
- if (startingChild instanceof ExpandableNotificationRow) {
- ExpandableNotificationRow row = (ExpandableNotificationRow) startingChild;
- row.onExpandedByGesture(true /* drag down is always an open */);
- }
- return true;
- } else {
- // abort gesture.
- return false;
- }
- }
-
- @Override
- @ShadeViewRefactor(RefactorComponent.INPUT)
- public void onDragDownReset() {
- setDimmed(true /* dimmed */, true /* animated */);
- resetScrollPosition();
- resetCheckSnoozeLeavebehind();
- }
-
- @Override
- @ShadeViewRefactor(RefactorComponent.INPUT)
- public void onCrossedThreshold(boolean above) {
- setDimmed(!above /* dimmed */, true /* animate */);
- }
-
- @Override
- @ShadeViewRefactor(RefactorComponent.INPUT)
- public void onTouchSlopExceeded() {
- cancelLongPress();
- checkSnoozeLeavebehind();
- }
-
- @Override
- @ShadeViewRefactor(RefactorComponent.INPUT)
- public void setEmptyDragAmount(float amount) {
- mNotificationPanel.setEmptyDragAmount(amount);
- }
-
- @Override
- @ShadeViewRefactor(RefactorComponent.INPUT)
- public boolean isFalsingCheckNeeded() {
- return mStatusBarState == StatusBarState.KEYGUARD;
- }
-
- @ShadeViewRefactor(RefactorComponent.INPUT)
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void updateSpeedBumpIndex() {
int speedBumpIndex = 0;
int currentIndex = 0;
@@ -5241,30 +5123,6 @@ public class NotificationStackScrollLayout extends ViewGroup
mSwipeHelper.resetExposedMenuView(animate, force);
}
-
- @ShadeViewRefactor(RefactorComponent.INPUT)
- public void closeControlsIfOutsideTouch(MotionEvent ev) {
- NotificationGuts guts = mNotificationGutsManager.getExposedGuts();
- NotificationMenuRowPlugin menuRow = mSwipeHelper.getCurrentMenuRow();
- View translatingParentView = mSwipeHelper.getTranslatingParentView();
- View view = null;
- if (guts != null && !guts.getGutsContent().isLeavebehind()) {
- // Only close visible guts if they're not a leavebehind.
- view = guts;
- } else if (menuRow != null && menuRow.isMenuVisible()
- && translatingParentView != null) {
- // Checking menu
- view = translatingParentView;
- }
- if (view != null && !NotificationSwipeHelper.isTouchInView(ev, view)) {
- // Touch was outside visible guts / menu notification, close what's visible
- mNotificationGutsManager.closeAndSaveGuts(false /* removeLeavebehind */,
- false /* force */, true /* removeControls */, -1 /* x */, -1 /* y */,
- false /* resetMenu */);
- resetExposedMenuView(true /* animate */, true /* force */);
- }
- }
-
@ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
static class AnimationEvent {
@@ -5586,9 +5444,9 @@ public class NotificationStackScrollLayout extends ViewGroup
}
};
- class NotificationMenuListener implements NotificationMenuRowPlugin.OnMenuEventListener {
+ @ShadeViewRefactor(RefactorComponent.INPUT)
+ private final OnMenuEventListener mMenuEventListener = new OnMenuEventListener() {
@Override
- @ShadeViewRefactor(RefactorComponent.INPUT)
public void onMenuClicked(View view, int x, int y, MenuItem item) {
if (mLongPressListener == null) {
return;
@@ -5602,7 +5460,6 @@ public class NotificationStackScrollLayout extends ViewGroup
}
@Override
- @ShadeViewRefactor(RefactorComponent.INPUT)
public void onMenuReset(View row) {
View translatingParentView = mSwipeHelper.getTranslatingParentView();
if (translatingParentView != null && row == translatingParentView) {
@@ -5612,7 +5469,6 @@ public class NotificationStackScrollLayout extends ViewGroup
}
@Override
- @ShadeViewRefactor(RefactorComponent.INPUT)
public void onMenuShown(View row) {
if (row instanceof ExpandableNotificationRow) {
MetricsLogger.action(mContext, MetricsEvent.ACTION_REVEAL_GEAR,
@@ -5621,9 +5477,11 @@ public class NotificationStackScrollLayout extends ViewGroup
}
mSwipeHelper.onMenuShown(row);
}
- }
+ };
- class SwipeHelperCallback implements NotificationSwipeHelper.NotificationCallback {
+ @ShadeViewRefactor(RefactorComponent.INPUT)
+ private final NotificationSwipeHelper.NotificationCallback mNotificationCallback =
+ new NotificationSwipeHelper.NotificationCallback() {
@Override
public void onDismiss() {
mNotificationGutsManager.closeAndSaveGuts(true /* removeLeavebehind */,
@@ -5643,10 +5501,8 @@ public class NotificationStackScrollLayout extends ViewGroup
}
@Override
- @ShadeViewRefactor(RefactorComponent.INPUT)
public void onDragCancelled(View v) {
mFalsingManager.onNotificatonStopDismissing();
- setSwipingInProgress(false);
}
/**
@@ -5654,7 +5510,6 @@ public class NotificationStackScrollLayout extends ViewGroup
* re-invoking dismiss logic in case the notification has not made its way out yet).
*/
@Override
- @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void onChildDismissed(View view) {
ExpandableNotificationRow row = (ExpandableNotificationRow) view;
if (!row.isDismissed()) {
@@ -5673,7 +5528,6 @@ public class NotificationStackScrollLayout extends ViewGroup
* @param view view (e.g. notification) to dismiss from the layout
*/
- @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void handleChildViewDismissed(View view) {
if (mDismissAllInProgress) {
return;
@@ -5681,7 +5535,6 @@ public class NotificationStackScrollLayout extends ViewGroup
boolean isBlockingHelperShown = false;
- setSwipingInProgress(false);
if (mDragAnimPendingChildren.contains(view)) {
// We start the swipe and finish it in the same frame; we don't want a drag
// animation.
@@ -5715,13 +5568,11 @@ public class NotificationStackScrollLayout extends ViewGroup
}
@Override
- @ShadeViewRefactor(RefactorComponent.INPUT)
public boolean isAntiFalsingNeeded() {
return onKeyguard();
}
@Override
- @ShadeViewRefactor(RefactorComponent.INPUT)
public View getChildAtPosition(MotionEvent ev) {
View child = NotificationStackScrollLayout.this.getChildAtPosition(ev.getX(),
ev.getY());
@@ -5744,10 +5595,8 @@ public class NotificationStackScrollLayout extends ViewGroup
}
@Override
- @ShadeViewRefactor(RefactorComponent.INPUT)
public void onBeginDrag(View v) {
mFalsingManager.onNotificatonStartDismissing();
- setSwipingInProgress(true);
mAmbientState.onBeginDrag(v);
updateContinuousShadowDrawing();
if (mAnimationsEnabled && (mIsExpanded || !isPinnedHeadsUp(v))) {
@@ -5758,7 +5607,6 @@ public class NotificationStackScrollLayout extends ViewGroup
}
@Override
- @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void onChildSnappedBack(View animView, float targetLeft) {
mAmbientState.onDragFinished(animView);
updateContinuousShadowDrawing();
@@ -5780,7 +5628,6 @@ public class NotificationStackScrollLayout extends ViewGroup
}
@Override
- @ShadeViewRefactor(RefactorComponent.INPUT)
public boolean updateSwipeProgress(View animView, boolean dismissable,
float swipeProgress) {
// Returning true prevents alpha fading.
@@ -5788,7 +5635,6 @@ public class NotificationStackScrollLayout extends ViewGroup
}
@Override
- @ShadeViewRefactor(RefactorComponent.INPUT)
public float getFalsingThresholdFactor() {
return mStatusBar.isWakeUpComingFromTouch() ? 1.5f : 1.0f;
}
@@ -5797,5 +5643,197 @@ public class NotificationStackScrollLayout extends ViewGroup
public boolean canChildBeDismissed(View v) {
return NotificationStackScrollLayout.this.canChildBeDismissed(v);
}
+ };
+
+ // ---------------------- DragDownHelper.OnDragDownListener ------------------------------------
+
+ @ShadeViewRefactor(RefactorComponent.INPUT)
+ private final DragDownCallback mDragDownCallback = new DragDownCallback() {
+
+ /* Only ever called as a consequence of a lockscreen expansion gesture. */
+ @Override
+ public boolean onDraggedDown(View startingChild, int dragLengthY) {
+ if (mStatusBarState == StatusBarState.KEYGUARD
+ && hasActiveNotifications() && (!mStatusBar.isDozing()
+ || mStatusBar.isPulsing())) {
+ mLockscreenGestureLogger.write(
+ MetricsEvent.ACTION_LS_SHADE,
+ (int) (dragLengthY / mDisplayMetrics.density),
+ 0 /* velocityDp - N/A */);
+
+ // We have notifications, go to locked shade.
+ mStatusBar.goToLockedShade(startingChild);
+ if (startingChild instanceof ExpandableNotificationRow) {
+ ExpandableNotificationRow row = (ExpandableNotificationRow) startingChild;
+ row.onExpandedByGesture(true /* drag down is always an open */);
+ }
+ return true;
+ } else {
+ // abort gesture.
+ return false;
+ }
+ }
+
+ @Override
+ public void onDragDownReset() {
+ setDimmed(true /* dimmed */, true /* animated */);
+ resetScrollPosition();
+ resetCheckSnoozeLeavebehind();
+ }
+
+ @Override
+ public void onCrossedThreshold(boolean above) {
+ setDimmed(!above /* dimmed */, true /* animate */);
+ }
+
+ @Override
+ public void onTouchSlopExceeded() {
+ cancelLongPress();
+ checkSnoozeLeavebehind();
+ }
+
+ @Override
+ public void setEmptyDragAmount(float amount) {
+ mNotificationPanel.setEmptyDragAmount(amount);
+ }
+
+ @Override
+ public boolean isFalsingCheckNeeded() {
+ return mStatusBarState == StatusBarState.KEYGUARD;
+ }
+ };
+
+ public DragDownCallback getDragDownCallback() { return mDragDownCallback; }
+
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
+ private final HeadsUpTouchHelper.Callback mHeadsUpCallback = new HeadsUpTouchHelper.Callback() {
+ @Override
+ public ExpandableView getChildAtRawPosition(float touchX, float touchY) {
+ return NotificationStackScrollLayout.this.getChildAtRawPosition(touchX, touchY);
+ }
+
+ @Override
+ public boolean isExpanded() {
+ return mIsExpanded;
+ }
+
+ @Override
+ public Context getContext() {
+ return mContext;
+ }
+ };
+
+ public HeadsUpTouchHelper.Callback getHeadsUpCallback() { return mHeadsUpCallback; }
+
+
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
+ private final OnGroupChangeListener mOnGroupChangeListener = new OnGroupChangeListener() {
+ @Override
+ public void onGroupExpansionChanged(ExpandableNotificationRow changedRow, boolean expanded) {
+ boolean animated = !mGroupExpandedForMeasure && mAnimationsEnabled
+ && (mIsExpanded || changedRow.isPinned());
+ if (animated) {
+ mExpandedGroupView = changedRow;
+ mNeedsAnimation = true;
+ }
+ changedRow.setChildrenExpanded(expanded, animated);
+ if (!mGroupExpandedForMeasure) {
+ onHeightChanged(changedRow, false /* needsAnimation */);
+ }
+ runAfterAnimationFinished(new Runnable() {
+ @Override
+ public void run() {
+ changedRow.onFinishedExpansionChange();
+ }
+ });
+ }
+
+ @Override
+ public void onGroupCreatedFromChildren(NotificationGroupManager.NotificationGroup group) {
+ mStatusBar.requestNotificationUpdate();
+ }
+
+ @Override
+ public void onGroupsChanged() {
+ mStatusBar.requestNotificationUpdate();
+ }
+ };
+
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
+ private ExpandHelper.Callback mExpandHelperCallback = new ExpandHelper.Callback() {
+ @Override
+ public ExpandableView getChildAtPosition(float touchX, float touchY) {
+ return NotificationStackScrollLayout.this.getChildAtPosition(touchX, touchY);
+ }
+
+ @Override
+ public ExpandableView getChildAtRawPosition(float touchX, float touchY) {
+ return NotificationStackScrollLayout.this.getChildAtRawPosition(touchX, touchY);
+ }
+
+ @Override
+ public boolean canChildBeExpanded(View v) {
+ return v instanceof ExpandableNotificationRow
+ && ((ExpandableNotificationRow) v).isExpandable()
+ && !((ExpandableNotificationRow) v).areGutsExposed()
+ && (mIsExpanded || !((ExpandableNotificationRow) v).isPinned());
+ }
+
+ /* Only ever called as a consequence of an expansion gesture in the shade. */
+ @Override
+ public void setUserExpandedChild(View v, boolean userExpanded) {
+ if (v instanceof ExpandableNotificationRow) {
+ ExpandableNotificationRow row = (ExpandableNotificationRow) v;
+ if (userExpanded && onKeyguard()) {
+ // Due to a race when locking the screen while touching, a notification may be
+ // expanded even after we went back to keyguard. An example of this happens if
+ // you click in the empty space while expanding a group.
+
+ // We also need to un-user lock it here, since otherwise the content height
+ // calculated might be wrong. We also can't invert the two calls since
+ // un-userlocking it will trigger a layout switch in the content view.
+ row.setUserLocked(false);
+ updateContentHeight();
+ notifyHeightChangeListener(row);
+ return;
+ }
+ row.setUserExpanded(userExpanded, true /* allowChildrenExpansion */);
+ row.onExpandedByGesture(userExpanded);
+ }
+ }
+
+ @Override
+ public void setExpansionCancelled(View v) {
+ if (v instanceof ExpandableNotificationRow) {
+ ((ExpandableNotificationRow) v).setGroupExpansionChanging(false);
+ }
+ }
+
+ @Override
+ public void setUserLockedChild(View v, boolean userLocked) {
+ if (v instanceof ExpandableNotificationRow) {
+ ((ExpandableNotificationRow) v).setUserLocked(userLocked);
+ }
+ cancelLongPress();
+ requestDisallowInterceptTouchEvent(true);
+ }
+
+ @Override
+ public void expansionStateChanged(boolean isExpanding) {
+ mExpandingNotification = isExpanding;
+ if (!mExpandedInThisMotion) {
+ mMaxScrollAfterExpand = mOwnScrollY;
+ mExpandedInThisMotion = true;
+ }
+ }
+
+ @Override
+ public int getMaxExpandHeight(ExpandableView view) {
+ return view.getMaxContentHeight();
+ }
+ };
+
+ public ExpandHelper.Callback getExpandHelperCallback() {
+ return mExpandHelperCallback;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java
index 028957d233ff..599da3b280be 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java
@@ -31,11 +31,9 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.SwipeHelper;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper;
-import com.android.systemui.statusbar.notification.ShadeViewRefactor;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.ExpandableView;
-@ShadeViewRefactor(ShadeViewRefactor.RefactorComponent.INPUT)
class NotificationSwipeHelper extends SwipeHelper
implements NotificationSwipeActionHelper {
@VisibleForTesting
@@ -229,6 +227,7 @@ class NotificationSwipeHelper extends SwipeHelper
if (mCallback.isExpanded()) {
// We don't want to quick-dismiss when it's a heads up as this might lead to closing
// of the panel early.
+ mSwipingInProgress = false;
mCallback.handleChildViewDismissed(view);
}
mCallback.onDismiss();
@@ -248,6 +247,7 @@ class NotificationSwipeHelper extends SwipeHelper
@Override
public void snapChild(final View animView, final float targetLeft, float velocity) {
superSnapChild(animView, targetLeft, velocity);
+ mSwipingInProgress = false;
mCallback.onDragCancelled(animView);
if (targetLeft == 0) {
handleMenuCoveredOrDismissed();
@@ -354,6 +354,7 @@ class NotificationSwipeHelper extends SwipeHelper
public void onMenuShown(View animView) {
setExposedMenuView(getTranslatingParentView());
+ mSwipingInProgress = false;
mCallback.onDragCancelled(animView);
Handler handler = getHandler();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ViewState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ViewState.java
index 1f3244f2177d..a15fd7083017 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ViewState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ViewState.java
@@ -25,6 +25,7 @@ import android.util.Property;
import android.view.View;
import android.view.animation.Interpolator;
+import com.android.systemui.Dumpable;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.statusbar.notification.row.ExpandableView;
@@ -32,12 +33,17 @@ import com.android.systemui.statusbar.notification.AnimatableProperty;
import com.android.systemui.statusbar.notification.PropertyAnimator;
import com.android.systemui.statusbar.policy.HeadsUpUtil;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+
/**
* A state of a view. This can be used to apply a set of view properties to a view with
* {@link com.android.systemui.statusbar.notification.stack.StackScrollState} or start
* animations with {@link com.android.systemui.statusbar.notification.stack.StackStateAnimator}.
*/
-public class ViewState {
+public class ViewState implements Dumpable {
/**
* Some animation properties that can be used to update running animations but not creating
@@ -710,4 +716,39 @@ public class ViewState {
animator.cancel();
}
}
+
+ @Override
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ StringBuilder result = new StringBuilder();
+ result.append("ViewState { ");
+
+ boolean first = true;
+ Class currentClass = this.getClass();
+ while (currentClass != null) {
+ Field[] fields = currentClass.getDeclaredFields();
+ // Print field names paired with their values
+ for (Field field : fields) {
+ int modifiers = field.getModifiers();
+ if (Modifier.isStatic(modifiers) || field.isSynthetic()
+ || Modifier.isTransient(modifiers)) {
+ continue;
+ }
+ if (!first) {
+ result.append(", ");
+ }
+ try {
+ result.append(field.getName());
+ result.append(": ");
+ //requires access to private field:
+ field.setAccessible(true);
+ result.append(field.get(this));
+ } catch (IllegalAccessException ex) {
+ }
+ first = false;
+ }
+ currentClass = currentClass.getSuperclass();
+ }
+ result.append(" }");
+ pw.print(result);
+ }
}
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/HeadsUpTouchHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java
index 4df1e3bda1a5..e4a5caaf7d71 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java
@@ -32,7 +32,7 @@ import com.android.systemui.statusbar.notification.stack.NotificationStackScroll
public class HeadsUpTouchHelper implements Gefingerpoken {
private HeadsUpManagerPhone mHeadsUpManager;
- private NotificationStackScrollLayout mStackScroller;
+ private Callback mCallback;
private int mTrackingPointer;
private float mTouchSlop;
private float mInitialTouchX;
@@ -44,12 +44,12 @@ public class HeadsUpTouchHelper implements Gefingerpoken {
private ExpandableNotificationRow mPickedChild;
public HeadsUpTouchHelper(HeadsUpManagerPhone headsUpManager,
- NotificationStackScrollLayout stackScroller,
+ Callback callback,
NotificationPanelView notificationPanelView) {
mHeadsUpManager = headsUpManager;
- mStackScroller = stackScroller;
+ mCallback = callback;
mPanel = notificationPanelView;
- Context context = stackScroller.getContext();
+ Context context = mCallback.getContext();
final ViewConfiguration configuration = ViewConfiguration.get(context);
mTouchSlop = configuration.getScaledTouchSlop();
}
@@ -75,13 +75,13 @@ public class HeadsUpTouchHelper implements Gefingerpoken {
mInitialTouchY = y;
mInitialTouchX = x;
setTrackingHeadsUp(false);
- ExpandableView child = mStackScroller.getChildAtRawPosition(x, y);
+ ExpandableView child = mCallback.getChildAtRawPosition(x, y);
mTouchingHeadsUpView = false;
if (child instanceof ExpandableNotificationRow) {
mPickedChild = (ExpandableNotificationRow) child;
- mTouchingHeadsUpView = !mStackScroller.isExpanded()
+ mTouchingHeadsUpView = !mCallback.isExpanded()
&& mPickedChild.isHeadsUp() && mPickedChild.isPinned();
- } else if (child == null && !mStackScroller.isExpanded()) {
+ } else if (child == null && !mCallback.isExpanded()) {
// We might touch above the visible heads up child, but then we still would
// like to capture it.
NotificationData.Entry topEntry = mHeadsUpManager.getTopEntry();
@@ -174,4 +174,10 @@ public class HeadsUpTouchHelper implements Gefingerpoken {
mPickedChild = null;
mTouchingHeadsUpView = false;
}
+
+ public interface Callback {
+ ExpandableView getChildAtRawPosition(float touchX, float touchY);
+ boolean isExpanded();
+ Context getContext();
+ }
}
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 087753afb68c..46bf8cb62dc0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -565,7 +565,7 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
return;
}
mDarkAmount = darkAmount;
- mIndicationArea.setAlpha(1f - darkAmount);
+ mIndicationController.setDarkAmount(darkAmount);
mLockIcon.setDarkAmount(darkAmount);
}
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/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
index 6bccf31b04a6..80f35060b737 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();
}
@@ -284,8 +284,8 @@ public class NavigationBarFragment extends Fragment implements Callbacks {
super.onViewCreated(view, savedInstanceState);
mNavigationBarView = (NavigationBarView) view;
- mNavigationBarView.setDisabledFlags(mDisabledFlags1);
mNavigationBarView.setComponents(mStatusBar.getPanel());
+ mNavigationBarView.setDisabledFlags(mDisabledFlags1);
mNavigationBarView.setOnVerticalChangedListener(this::onVerticalChanged);
mNavigationBarView.setOnTouchListener(this::onNavigationTouch);
if (savedInstanceState != null) {
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..e92656ae0c02 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -60,7 +60,6 @@ import com.android.systemui.DockedStackExistsListener;
import com.android.systemui.Interpolators;
import com.android.systemui.OverviewProxyService;
import com.android.systemui.R;
-import com.android.systemui.RecentsComponent;
import com.android.systemui.SysUiServiceProvider;
import com.android.systemui.plugins.PluginListener;
import com.android.systemui.shared.plugins.PluginManager;
@@ -71,7 +70,6 @@ import com.android.systemui.recents.RecentsOnboarding;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.NavigationBarCompat;
import com.android.systemui.shared.system.WindowManagerWrapper;
-import com.android.systemui.stackdivider.Divider;
import com.android.systemui.statusbar.policy.DeadZone;
import com.android.systemui.statusbar.policy.KeyButtonDrawable;
@@ -140,6 +138,7 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav
private final SparseArray<ButtonDispatcher> mButtonDispatchers = new SparseArray<>();
private final ContextualButtonGroup mContextualButtonGroup;
private Configuration mConfiguration;
+ private Configuration mTmpLastConfiguration;
private NavigationBarInflaterView mNavigationInflaterView;
private RecentsOnboarding mRecentsOnboarding;
@@ -286,6 +285,7 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav
mRecentsOnboarding = new RecentsOnboarding(context, mOverviewProxyService);
mConfiguration = new Configuration();
+ mTmpLastConfiguration = new Configuration();
mConfiguration.updateFrom(context.getResources().getConfiguration());
mScreenPinningNotify = new ScreenPinningNotify(mContext);
@@ -445,13 +445,13 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav
}
private void reloadNavIcons() {
- updateIcons(Configuration.EMPTY, mConfiguration);
+ updateIcons(Configuration.EMPTY);
}
- private void updateIcons(Configuration oldConfig, Configuration newConfig) {
- final boolean orientationChange = oldConfig.orientation != newConfig.orientation;
- final boolean densityChange = oldConfig.densityDpi != newConfig.densityDpi;
- final boolean dirChange = oldConfig.getLayoutDirection() != newConfig.getLayoutDirection();
+ private void updateIcons(Configuration oldConfig) {
+ final boolean orientationChange = oldConfig.orientation != mConfiguration.orientation;
+ final boolean densityChange = oldConfig.densityDpi != mConfiguration.densityDpi;
+ final boolean dirChange = oldConfig.getLayoutDirection() != mConfiguration.getLayoutDirection();
if (orientationChange || densityChange) {
mDockedIcon = getDrawable(R.drawable.ic_sysbar_docked);
@@ -485,7 +485,7 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav
private void orientBackButton(KeyButtonDrawable drawable) {
final boolean useAltBack =
(mNavigationIconHints & StatusBarManager.NAVIGATION_HINT_BACK_ALT) != 0;
- final boolean isRtl = getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
+ final boolean isRtl = mConfiguration.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
float degrees = useAltBack
? (isRtl ? 270 : -90)
: (isRtl ? 180 : 0);
@@ -946,26 +946,27 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav
@Override
protected void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
- boolean uiCarModeChanged = updateCarMode(newConfig);
+ mTmpLastConfiguration.updateFrom(mConfiguration);
+ mConfiguration.updateFrom(newConfig);
+ boolean uiCarModeChanged = updateCarMode();
updateTaskSwitchHelper();
- updateIcons(mConfiguration, newConfig);
+ updateIcons(mTmpLastConfiguration);
updateRecentsIcon();
- mRecentsOnboarding.onConfigurationChanged(newConfig);
- if (uiCarModeChanged || mConfiguration.densityDpi != newConfig.densityDpi
- || mConfiguration.getLayoutDirection() != newConfig.getLayoutDirection()) {
+ mRecentsOnboarding.onConfigurationChanged(mConfiguration);
+ if (uiCarModeChanged || mTmpLastConfiguration.densityDpi != mConfiguration.densityDpi
+ || mTmpLastConfiguration.getLayoutDirection() != mConfiguration.getLayoutDirection()) {
// If car mode or density changes, we need to reset the icons.
updateNavButtonIcons();
}
- mConfiguration.updateFrom(newConfig);
}
/**
* If the configuration changed, update the carmode and return that it was updated.
*/
- private boolean updateCarMode(Configuration newConfig) {
+ private boolean updateCarMode() {
boolean uiCarModeChanged = false;
- if (newConfig != null) {
- int uiMode = newConfig.uiMode & Configuration.UI_MODE_TYPE_MASK;
+ if (mConfiguration != null) {
+ int uiMode = mConfiguration.uiMode & Configuration.UI_MODE_TYPE_MASK;
final boolean isCarMode = (uiMode == Configuration.UI_MODE_TYPE_CAR);
if (isCarMode != mInCarMode) {
@@ -1100,10 +1101,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/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 6d53cd373d05..75077029c16b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -2521,8 +2521,8 @@ public class NotificationPanelView extends PanelView implements
@Override
public void setHeadsUpManager(HeadsUpManagerPhone headsUpManager) {
super.setHeadsUpManager(headsUpManager);
- mHeadsUpTouchHelper = new HeadsUpTouchHelper(headsUpManager, mNotificationStackScroller,
- this);
+ mHeadsUpTouchHelper = new HeadsUpTouchHelper(headsUpManager,
+ mNotificationStackScroller.getHeadsUpCallback(), this);
}
public void setTrackedHeadsUp(ExpandableNotificationRow pickedChild) {
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 56bef2e8ea59..cc9adb86a6b4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -3756,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());
@@ -3790,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);
@@ -4341,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");
@@ -5267,8 +5277,7 @@ public class StatusBar extends SystemUI implements DemoMode,
(Runnable saveImportance, StatusBarNotification sbn) -> {
// If the user has security enabled, show challenge if the setting is changed.
if (mLockscreenUserManager.isLockscreenPublicMode(sbn.getUser().getIdentifier())
- && (mState == StatusBarState.KEYGUARD ||
- mState == StatusBarState.SHADE_LOCKED)) {
+ && mKeyguardManager.isKeyguardLocked()) {
onLockedNotificationImportanceChange(() -> {
saveImportance.run();
return true;
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/phone/StatusBarWindowView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
index 45b32c7abae0..ad9b9b30fafc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
@@ -58,6 +58,7 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.view.FloatingActionMode;
import com.android.internal.widget.FloatingToolbar;
import com.android.systemui.Dependency;
+import com.android.systemui.ExpandHelper;
import com.android.systemui.R;
import com.android.systemui.classifier.FalsingManager;
import com.android.systemui.statusbar.DragDownHelper;
@@ -182,6 +183,11 @@ public class StatusBarWindowView extends FrameLayout {
}
}
+ @VisibleForTesting
+ protected NotificationStackScrollLayout getStackScrollLayout() {
+ return mStackScrollLayout;
+ }
+
@Override
public FrameLayout.LayoutParams generateLayoutParams(AttributeSet attrs) {
return new LayoutParams(getContext(), attrs);
@@ -215,8 +221,11 @@ public class StatusBarWindowView extends FrameLayout {
public void setService(StatusBar service) {
mService = service;
- setDragDownHelper(new DragDownHelper(getContext(), this, mStackScrollLayout,
- mStackScrollLayout));
+ NotificationStackScrollLayout stackScrollLayout = getStackScrollLayout();
+ ExpandHelper.Callback expandHelperCallback = stackScrollLayout.getExpandHelperCallback();
+ DragDownHelper.DragDownCallback dragDownCallback = stackScrollLayout.getDragDownCallback();
+ setDragDownHelper(new DragDownHelper(getContext(), this, expandHelperCallback,
+ dragDownCallback));
}
@VisibleForTesting
@@ -309,7 +318,7 @@ public class StatusBarWindowView extends FrameLayout {
}
}
if (isDown) {
- mStackScrollLayout.closeControlsIfOutsideTouch(ev);
+ getStackScrollLayout().closeControlsIfOutsideTouch(ev);
}
if (mService.isDozing()) {
mService.mDozeScrimController.extendPulse();
@@ -331,13 +340,14 @@ public class StatusBarWindowView extends FrameLayout {
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
- if (mService.isDozing() && !mStackScrollLayout.hasPulsingNotifications()) {
+ NotificationStackScrollLayout stackScrollLayout = getStackScrollLayout();
+ if (mService.isDozing() && !stackScrollLayout.hasPulsingNotifications()) {
// Capture all touch events in always-on.
return true;
}
boolean intercept = false;
if (mNotificationPanel.isFullyExpanded()
- && mStackScrollLayout.getVisibility() == View.VISIBLE
+ && stackScrollLayout.getVisibility() == View.VISIBLE
&& mStatusBarStateController.getState() == StatusBarState.KEYGUARD
&& !mService.isBouncerShowing()
&& !mService.isDozing()) {
@@ -349,7 +359,7 @@ public class StatusBarWindowView extends FrameLayout {
if (intercept) {
MotionEvent cancellation = MotionEvent.obtain(ev);
cancellation.setAction(MotionEvent.ACTION_CANCEL);
- mStackScrollLayout.onInterceptTouchEvent(cancellation);
+ stackScrollLayout.onInterceptTouchEvent(cancellation);
mNotificationPanel.onInterceptTouchEvent(cancellation);
cancellation.recycle();
}
@@ -391,8 +401,9 @@ public class StatusBarWindowView extends FrameLayout {
}
public void cancelExpandHelper() {
- if (mStackScrollLayout != null) {
- mStackScrollLayout.cancelExpandHelper();
+ NotificationStackScrollLayout stackScrollLayout = getStackScrollLayout();
+ if (stackScrollLayout != null) {
+ stackScrollLayout.cancelExpandHelper();
}
}
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/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
index 59dd56066652..846c0cd96229 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -465,6 +465,8 @@ public class NetworkControllerImpl extends BroadcastReceiver
MobileSignalController controller = mMobileSignalControllers.valueAt(i);
controller.handleBroadcast(intent);
}
+ mConfig = Config.readConfig(mContext);
+ mReceiverHandler.post(this::handleConfigurationChanged);
break;
case TelephonyIntents.ACTION_SIM_STATE_CHANGED:
// Avoid rebroadcast because SysUI is direct boot aware.
@@ -1051,18 +1053,23 @@ public class NetworkControllerImpl extends BroadcastReceiver
config.showAtLeast3G = res.getBoolean(R.bool.config_showMin3G);
config.alwaysShowCdmaRssi =
res.getBoolean(com.android.internal.R.bool.config_alwaysUseCdmaRssi);
- config.show4gForLte = res.getBoolean(R.bool.config_show4GForLTE);
config.hspaDataDistinguishable =
res.getBoolean(R.bool.config_hspa_data_distinguishable);
- config.hideLtePlus = res.getBoolean(R.bool.config_hideLtePlus);
config.inflateSignalStrengths = res.getBoolean(R.bool.config_inflateSignalStrength);
CarrierConfigManager configMgr = (CarrierConfigManager)
context.getSystemService(Context.CARRIER_CONFIG_SERVICE);
- PersistableBundle b = configMgr.getConfig();
+ // Handle specific carrier config values for the default data SIM
+ int defaultDataSubId = SubscriptionManager.from(context)
+ .getDefaultDataSubscriptionId();
+ PersistableBundle b = configMgr.getConfigForSubId(defaultDataSubId);
if (b != null) {
config.alwaysShowDataRatIcon = b.getBoolean(
CarrierConfigManager.KEY_ALWAYS_SHOW_DATA_RAT_ICON_BOOL);
+ config.show4gForLte = b.getBoolean(
+ CarrierConfigManager.KEY_SHOW_4G_FOR_LTE_DATA_ICON_BOOL);
+ config.hideLtePlus = b.getBoolean(
+ CarrierConfigManager.KEY_HIDE_LTE_PLUS_DATA_ICON_BOOL);
}
config.readIconsFromXml = res.getBoolean(R.bool.config_read_icons_from_xml);
config.showRsrpSignalLevelforLTE =
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/volume/VolumeDialogControllerImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
index a97effd3a023..e20e267336ea 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
@@ -956,11 +956,13 @@ public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpa
changed |= onVolumeChangedW(stream, 0);
} else if (action.equals(AudioManager.RINGER_MODE_CHANGED_ACTION)) {
final int rm = intent.getIntExtra(AudioManager.EXTRA_RINGER_MODE, -1);
+ if (isInitialStickyBroadcast()) mState.ringerModeExternal = rm;
if (D.BUG) Log.d(TAG, "onReceive RINGER_MODE_CHANGED_ACTION rm="
+ Util.ringerModeToString(rm));
changed = updateRingerModeExternalW(rm);
} else if (action.equals(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION)) {
final int rm = intent.getIntExtra(AudioManager.EXTRA_RINGER_MODE, -1);
+ if (isInitialStickyBroadcast()) mState.ringerModeInternal = rm;
if (D.BUG) Log.d(TAG, "onReceive INTERNAL_RINGER_MODE_CHANGED_ACTION rm="
+ Util.ringerModeToString(rm));
changed = updateRingerModeInternalW(rm);
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index 4810b0b91c10..798f8bcd7938 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -135,10 +135,6 @@ public class VolumeDialogImpl implements VolumeDialog {
private final AccessibilityManagerWrapper mAccessibilityMgr;
private final Object mSafetyWarningLock = new Object();
private final Accessibility mAccessibility = new Accessibility();
- private ColorStateList mActiveTint;
- private int mActiveAlpha;
- private ColorStateList mInactiveTint;
- private int mInactiveAlpha;
private boolean mShowing;
private boolean mShowA11yStream;
@@ -238,11 +234,6 @@ public class VolumeDialogImpl implements VolumeDialog {
lp.gravity = ((FrameLayout.LayoutParams) mDialogView.getLayoutParams()).gravity;
mWindow.setAttributes(lp);
- mActiveTint = Utils.getColorAccent(mContext);
- mActiveAlpha = Color.alpha(mActiveTint.getDefaultColor());
- mInactiveTint = Utils.getColorAttr(mContext, android.R.attr.colorForeground);
- mInactiveAlpha = getAlphaAttr(android.R.attr.secondaryContentAlpha);
-
mDialogRowsView = mDialog.findViewById(R.id.volume_dialog_rows);
mRinger = mDialog.findViewById(R.id.ringer);
if (mRinger != null) {
@@ -556,14 +547,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);
@@ -941,8 +933,12 @@ public class VolumeDialogImpl implements VolumeDialog {
row.slider.requestFocus();
}
boolean useActiveColoring = isActive && row.slider.isEnabled();
- final ColorStateList tint = useActiveColoring ? mActiveTint : mInactiveTint;
- final int alpha = useActiveColoring ? mActiveAlpha : mInactiveAlpha;
+ final ColorStateList tint = useActiveColoring
+ ? Utils.getColorAccent(mContext)
+ : Utils.getColorAttr(mContext, android.R.attr.colorForeground);
+ final int alpha = useActiveColoring
+ ? Color.alpha(tint.getDefaultColor())
+ : getAlphaAttr(android.R.attr.secondaryContentAlpha);
if (tint == row.cachedTint) return;
row.slider.setProgressTintList(tint);
row.slider.setThumbTintList(tint);
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/NotificationViewHierarchyManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java
index 15c18e96d709..6b4ccc4a80b5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java
@@ -218,6 +218,9 @@ public class NotificationViewHierarchyManagerTest extends SysuiTestCase {
public void generateChildOrderChangedEvent() {}
@Override
+ public void onReset(ExpandableView view) {}
+
+ @Override
public int getContainerChildCount() {
return mRows.size();
}
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/statusbar/phone/StatusBarWindowViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowViewTest.java
index 445a194155bb..46335dc3b5ec 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowViewTest.java
@@ -17,11 +17,11 @@
package com.android.systemui.statusbar.phone;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.os.SystemClock;
-import android.support.test.InstrumentationRegistry;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import android.view.MotionEvent;
@@ -31,6 +31,7 @@ import com.android.systemui.SysuiTestCase;
import com.android.systemui.statusbar.DragDownHelper;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
import org.junit.Before;
import org.junit.Test;
@@ -43,11 +44,14 @@ public class StatusBarWindowViewTest extends SysuiTestCase {
private StatusBarWindowView mView;
private StatusBar mStatusBar;
private DragDownHelper mDragDownHelper;
+ private NotificationStackScrollLayout mStackScrollLayout;
@Before
public void setUp() {
mDependency.injectMockDependency(StatusBarStateController.class);
- mView = new StatusBarWindowView(getContext(), null);
+ mView = spy(new StatusBarWindowView(getContext(), null));
+ mStackScrollLayout = mock(NotificationStackScrollLayout.class);
+ when(mView.getStackScrollLayout()).thenReturn(mStackScrollLayout);
mStatusBar = mock(StatusBar.class);
mView.setService(mStatusBar);
mDragDownHelper = mock(DragDownHelper.class);
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/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/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
index af33bd02c745..d3842b74990c 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
@@ -182,9 +182,7 @@ public final class AutofillManagerService extends SystemService {
final int userId = users.get(i).id;
final boolean disabled = umi.getUserRestriction(userId, UserManager.DISALLOW_AUTOFILL);
if (disabled) {
- if (disabled) {
- Slog.i(TAG, "Disabling Autofill for user " + userId);
- }
+ Slog.i(TAG, "Disabling Autofill for user " + userId);
mDisabledUsers.put(userId, disabled);
}
}
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index 78facf84b03c..14d68cb853d6 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -185,23 +185,6 @@ final class AutofillManagerServiceImpl {
updateLocked(disabled);
}
- @Nullable
- CharSequence getServiceName() {
- final String packageName = getServicePackageName();
- if (packageName == null) {
- return null;
- }
-
- try {
- final PackageManager pm = mContext.getPackageManager();
- final ApplicationInfo info = pm.getApplicationInfo(packageName, 0);
- return pm.getApplicationLabel(info);
- } catch (Exception e) {
- Slog.e(TAG, "Could not get label for " + packageName + ": " + e);
- return packageName;
- }
- }
-
@GuardedBy("mLock")
private int getServiceUidLocked() {
if (mInfo == null) {
@@ -226,6 +209,7 @@ final class AutofillManagerServiceImpl {
return null;
}
+ @Nullable
ComponentName getServiceComponentName() {
synchronized (mLock) {
if (mInfo == null) {
@@ -706,17 +690,27 @@ final class AutofillManagerServiceImpl {
}
}
- @NonNull
- CharSequence getServiceLabel() {
- final CharSequence label = mInfo.getServiceInfo().loadSafeLabel(
+ /**
+ * Gets the user-visibile name of the service this service binds to, or {@code null} if the
+ * service is disabled.
+ */
+ @Nullable
+ @GuardedBy("mLock")
+ public CharSequence getServiceLabelLocked() {
+ return mInfo == null ? null : mInfo.getServiceInfo().loadSafeLabel(
mContext.getPackageManager(), 0 /* do not ellipsize */,
PackageItemInfo.SAFE_LABEL_FLAG_FIRST_LINE | PackageItemInfo.SAFE_LABEL_FLAG_TRIM);
- return label;
}
+ /**
+ * Gets the icon of the service this service binds to, or {@code null} if the service is
+ * disabled.
+ */
@NonNull
- Drawable getServiceIcon() {
- return mInfo.getServiceInfo().loadIcon(mContext.getPackageManager());
+ @Nullable
+ @GuardedBy("mLock")
+ Drawable getServiceIconLocked() {
+ return mInfo == null ? null : mInfo.getServiceInfo().loadIcon(mContext.getPackageManager());
}
/**
@@ -959,7 +953,7 @@ final class AutofillManagerServiceImpl {
} else {
pw.println();
mInfo.dump(prefix2, pw);
- pw.print(prefix); pw.print("Service Label: "); pw.println(getServiceLabel());
+ pw.print(prefix); pw.print("Service Label: "); pw.println(getServiceLabelLocked());
pw.print(prefix); pw.print("Target SDK: "); pw.println(getTargedSdkLocked());
}
pw.print(prefix); pw.print("Component from settings: ");
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index c1b620c657b3..f85749af54fd 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -48,6 +48,7 @@ import android.content.Intent;
import android.content.IntentSender;
import android.graphics.Bitmap;
import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
import android.metrics.LogMaker;
import android.os.Binder;
import android.os.Build;
@@ -311,8 +312,8 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
Slog.d(TAG, "Setting urlBar as id=" + urlBarId + " and domain "
+ mUrlBar.getWebDomain());
}
- final ViewState viewState = new ViewState(Session.this, urlBarId,
- Session.this, ViewState.STATE_URL_BAR);
+ final ViewState viewState = new ViewState(urlBarId, Session.this,
+ ViewState.STATE_URL_BAR);
mViewStates.put(urlBarId, viewState);
}
}
@@ -1749,7 +1750,18 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
final IAutoFillManagerClient client = getClient();
mPendingSaveUi = new PendingUi(mActivityToken, id, client);
- getUiForShowing().showSaveUi(mService.getServiceLabel(), mService.getServiceIcon(),
+
+ final CharSequence serviceLabel;
+ final Drawable serviceIcon;
+ synchronized (mLock) {
+ serviceLabel = mService.getServiceLabelLocked();
+ serviceIcon = mService.getServiceIconLocked();
+ }
+ if (serviceLabel == null || serviceIcon == null) {
+ wtf(null, "showSaveLocked(): no service label or icon");
+ return true;
+ }
+ getUiForShowing().showSaveUi(serviceLabel, serviceIcon,
mService.getServicePackageName(), saveInfo, this,
mComponentName, this, mPendingSaveUi, isUpdate, mCompatMode);
if (client != null) {
@@ -1801,8 +1813,6 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
return sanitizers;
}
- // TODO: this method is called a few times in the save process, we should cache its results into
- // ViewState.
@Nullable
private AutofillValue getSanitizedValue(
@Nullable ArrayMap<AutofillId, InternalSanitizer> sanitizers,
@@ -1810,13 +1820,22 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
@Nullable AutofillValue value) {
if (sanitizers == null || value == null) return value;
- final InternalSanitizer sanitizer = sanitizers.get(id);
- if (sanitizer == null) {
- return value;
- }
+ final ViewState state = mViewStates.get(id);
+ AutofillValue sanitized = state == null ? null : state.getSanitizedValue();
+ if (sanitized == null) {
+ final InternalSanitizer sanitizer = sanitizers.get(id);
+ if (sanitizer == null) {
+ return value;
+ }
- final AutofillValue sanitized = sanitizer.sanitize(value);
- if (sDebug) Slog.d(TAG, "Value for " + id + "(" + value + ") sanitized to " + sanitized);
+ sanitized = sanitizer.sanitize(value);
+ if (sDebug) {
+ Slog.d(TAG, "Value for " + id + "(" + value + ") sanitized to " + sanitized);
+ }
+ if (state != null) {
+ state.setSanitizedValue(sanitized);
+ }
+ }
return sanitized;
}
@@ -2137,7 +2156,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
|| action == ACTION_VIEW_ENTERED) {
if (sVerbose) Slog.v(TAG, "Creating viewState for " + id);
boolean isIgnored = isIgnoredLocked(id);
- viewState = new ViewState(this, id, this,
+ viewState = new ViewState(id, this,
isIgnored ? ViewState.STATE_IGNORED : ViewState.STATE_INITIAL);
mViewStates.put(id, viewState);
@@ -2318,9 +2337,19 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
filterText = value.getTextValue().toString();
}
+ final CharSequence serviceLabel;
+ final Drawable serviceIcon;
+ synchronized (mLock) {
+ serviceLabel = mService.getServiceLabelLocked();
+ serviceIcon = mService.getServiceIconLocked();
+ }
+ if (serviceLabel == null || serviceIcon == null) {
+ wtf(null, "onFillReady(): no service label or icon");
+ return;
+ }
getUiForShowing().showFillUi(filledId, response, filterText,
mService.getServicePackageName(), mComponentName,
- mService.getServiceLabel(), mService.getServiceIcon(), this, id, mCompatMode);
+ serviceLabel, serviceIcon, this, id, mCompatMode);
synchronized (mLock) {
if (mUiShownTime == 0) {
@@ -2607,7 +2636,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
if (viewState != null) {
viewState.setState(state);
} else {
- viewState = new ViewState(this, id, this, state);
+ viewState = new ViewState(id, this, state);
if (sVerbose) {
Slog.v(TAG, "Adding autofillable view with id " + id + " and state " + state);
}
@@ -2655,12 +2684,6 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
}
}
- CharSequence getServiceName() {
- synchronized (mLock) {
- return mService.getServiceName();
- }
- }
-
// TODO: this should never be null, but we got at least one occurrence, probably due to a race.
@GuardedBy("mLock")
@Nullable
diff --git a/services/autofill/java/com/android/server/autofill/ViewState.java b/services/autofill/java/com/android/server/autofill/ViewState.java
index a8dae03e4c12..2cc6d20ef6db 100644
--- a/services/autofill/java/com/android/server/autofill/ViewState.java
+++ b/services/autofill/java/com/android/server/autofill/ViewState.java
@@ -77,7 +77,6 @@ final class ViewState {
public final AutofillId id;
private final Listener mListener;
- private final Session mSession;
private FillResponse mResponse;
private AutofillValue mCurrentValue;
@@ -87,8 +86,7 @@ final class ViewState {
private int mState;
private String mDatasetId;
- ViewState(Session session, AutofillId id, Listener listener, int state) {
- mSession = session;
+ ViewState(AutofillId id, Listener listener, int state) {
this.id = id;
mListener = listener;
mState = state;
@@ -141,10 +139,6 @@ final class ViewState {
mResponse = response;
}
- CharSequence getServiceName() {
- return mSession.getServiceName();
- }
-
int getState() {
return mState;
}
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 34e56a757895..79a81f2c8fd2 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -36,6 +36,8 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
import static android.net.NetworkCapabilities.TRANSPORT_VPN;
+import static android.net.NetworkPolicyManager.RULE_NONE;
+import static android.net.NetworkPolicyManager.uidRulesToString;
import static android.os.Process.INVALID_UID;
import static android.system.OsConstants.IPPROTO_TCP;
import static android.system.OsConstants.IPPROTO_UDP;
@@ -193,6 +195,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
+import java.util.ConcurrentModificationException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@@ -261,6 +264,14 @@ public class ConnectivityService extends IConnectivityManager.Stub
@GuardedBy("mVpns")
private LockdownVpnTracker mLockdownTracker;
+ /**
+ * Stale copy of uid rules provided by NPMS. As long as they are accessed only in internal
+ * handler thread, they don't need a lock.
+ */
+ private SparseIntArray mUidRules = new SparseIntArray();
+ /** Flag indicating if background data is restricted. */
+ private boolean mRestrictBackground;
+
final private Context mContext;
// 0 is full bad, 100 is full good
private int mDefaultInetConditionPublished = 0;
@@ -423,6 +434,16 @@ public class ConnectivityService extends IConnectivityManager.Stub
// Handle private DNS validation status updates.
private static final int EVENT_PRIVATE_DNS_VALIDATION_UPDATE = 38;
+ /**
+ * Used to handle onUidRulesChanged event from NetworkPolicyManagerService.
+ */
+ private static final int EVENT_UID_RULES_CHANGED = 39;
+
+ /**
+ * Used to handle onRestrictBackgroundChanged event from NetworkPolicyManagerService.
+ */
+ private static final int EVENT_DATA_SAVER_CHANGED = 40;
+
private static final int EVENT_UPDATE_TCP_BUFFER_FOR_5G = 160;
private static String eventName(int what) {
@@ -788,6 +809,9 @@ public class ConnectivityService extends IConnectivityManager.Stub
mTelephonyManager = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
mSubscriptionManager = SubscriptionManager.from(mContext);
+ // To ensure uid rules are synchronized with Network Policy, register for
+ // NetworkPolicyManagerService events must happen prior to NetworkPolicyManagerService
+ // reading existing policy from disk.
try {
mPolicyManager.registerListener(mPolicyListener);
} catch (RemoteException e) {
@@ -918,7 +942,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
registerPrivateDnsSettingsCallbacks();
}
- private Tethering makeTethering() {
+ @VisibleForTesting
+ protected Tethering makeTethering() {
// TODO: Move other elements into @Overridden getters.
final TetheringDependencies deps = new TetheringDependencies() {
@Override
@@ -1124,11 +1149,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
if (ignoreBlocked) {
return false;
}
- // Networks are never blocked for system services
- // TODO: consider moving this check to NetworkPolicyManagerInternal.isUidNetworkingBlocked.
- if (isSystem(uid)) {
- return false;
- }
synchronized (mVpns) {
final Vpn vpn = mVpns.get(UserHandle.getUserId(uid));
if (vpn != null && vpn.isBlockingUid(uid)) {
@@ -1158,6 +1178,17 @@ public class ConnectivityService extends IConnectivityManager.Stub
mNetworkInfoBlockingLogs.log(action + " " + uid);
}
+ private void maybeLogBlockedStatusChanged(NetworkRequestInfo nri, Network net,
+ boolean blocked) {
+ if (nri == null || net == null || !LOGD_BLOCKED_NETWORKINFO) {
+ return;
+ }
+ String action = blocked ? "BLOCKED" : "UNBLOCKED";
+ log(String.format("Blocked status changed to %s for %d(%d) on netId %d", blocked,
+ nri.mUid, nri.request.requestId, net.netId));
+ mNetworkInfoBlockingLogs.log(action + " " + nri.mUid);
+ }
+
/**
* Apply any relevant filters to {@link NetworkState} for the given UID. For
* example, this may mark the network as {@link DetailedState#BLOCKED} based
@@ -1659,10 +1690,17 @@ public class ConnectivityService extends IConnectivityManager.Stub
private final INetworkPolicyListener mPolicyListener = new NetworkPolicyManager.Listener() {
@Override
public void onUidRulesChanged(int uid, int uidRules) {
- // TODO: notify UID when it has requested targeted updates
+ mHandler.sendMessage(mHandler.obtainMessage(EVENT_UID_RULES_CHANGED, uid, uidRules));
}
@Override
public void onRestrictBackgroundChanged(boolean restrictBackground) {
+ // caller is NPMS, since we only register with them
+ if (LOGD_BLOCKED_NETWORKINFO) {
+ log("onRestrictBackgroundChanged(restrictBackground=" + restrictBackground + ")");
+ }
+ mHandler.sendMessage(mHandler.obtainMessage(
+ EVENT_DATA_SAVER_CHANGED, restrictBackground ? 1 : 0, 0));
+
// TODO: relocate this specific callback in Tethering.
if (restrictBackground) {
log("onRestrictBackgroundChanged(true): disabling tethering");
@@ -1671,6 +1709,50 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
};
+ void handleUidRulesChanged(int uid, int newRules) {
+ // skip update when we've already applied rules
+ final int oldRules = mUidRules.get(uid, RULE_NONE);
+ if (oldRules == newRules) return;
+
+ maybeNotifyNetworkBlockedForNewUidRules(uid, newRules);
+
+ if (newRules == RULE_NONE) {
+ mUidRules.delete(uid);
+ } else {
+ mUidRules.put(uid, newRules);
+ }
+ }
+
+ void handleRestrictBackgroundChanged(boolean restrictBackground) {
+ if (mRestrictBackground == restrictBackground) return;
+
+ for (final NetworkAgentInfo nai : mNetworkAgentInfos.values()) {
+ final boolean curMetered = nai.networkCapabilities.isMetered();
+ maybeNotifyNetworkBlocked(nai, curMetered, curMetered, mRestrictBackground,
+ restrictBackground);
+ }
+
+ mRestrictBackground = restrictBackground;
+ }
+
+ private boolean isUidNetworkingWithVpnBlocked(int uid, int uidRules, boolean isNetworkMetered,
+ boolean isBackgroundRestricted) {
+ synchronized (mVpns) {
+ final Vpn vpn = mVpns.get(UserHandle.getUserId(uid));
+ // Because the return value of this function depends on the list of UIDs the
+ // always-on VPN blocks when in lockdown mode, when the always-on VPN changes that
+ // list all state depending on the return value of this function has to be recomputed.
+ // TODO: add a trigger when the always-on VPN sets its blocked UIDs to reevaluate and
+ // send the necessary onBlockedStatusChanged callbacks.
+ if (vpn != null && vpn.isBlockingUid(uid)) {
+ return true;
+ }
+ }
+
+ return mPolicyManagerInternal.isUidNetworkingBlocked(uid, uidRules,
+ isNetworkMetered, isBackgroundRestricted);
+ }
+
/**
* Require that the caller is either in the same user or has appropriate permission to interact
* across users.
@@ -1687,6 +1769,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,
@@ -1731,6 +1823,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);
@@ -1806,7 +1905,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);
@@ -1854,8 +1954,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.
@@ -2113,6 +2211,28 @@ public class ConnectivityService extends IConnectivityManager.Stub
pw.decreaseIndent();
pw.println();
+ pw.print("Restrict background: ");
+ pw.println(mRestrictBackground);
+ pw.println();
+
+ pw.println("Status for known UIDs:");
+ pw.increaseIndent();
+ final int size = mUidRules.size();
+ for (int i = 0; i < size; i++) {
+ // Don't crash if the array is modified while dumping in bugreports.
+ try {
+ final int uid = mUidRules.keyAt(i);
+ final int uidRules = mUidRules.get(uid, RULE_NONE);
+ pw.println("UID=" + uid + " rules=" + uidRulesToString(uidRules));
+ } catch (ArrayIndexOutOfBoundsException e) {
+ pw.println(" ArrayIndexOutOfBoundsException");
+ } catch (ConcurrentModificationException e) {
+ pw.println(" ConcurrentModificationException");
+ }
+ }
+ pw.println();
+ pw.decreaseIndent();
+
pw.println("Network Requests:");
pw.increaseIndent();
dumpNetworkRequests(pw);
@@ -3112,7 +3232,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
break;
}
case EVENT_APPLY_GLOBAL_HTTP_PROXY: {
- handleDeprecatedGlobalHttpProxy();
+ mProxyTracker.loadDeprecatedGlobalHttpProxy();
break;
}
case EVENT_PROXY_HAS_CHANGED: {
@@ -3203,6 +3323,12 @@ public class ConnectivityService extends IConnectivityManager.Stub
handlePrivateDnsValidationUpdate(
(PrivateDnsValidationUpdate) msg.obj);
break;
+ case EVENT_UID_RULES_CHANGED:
+ handleUidRulesChanged(msg.arg1, msg.arg2);
+ break;
+ case EVENT_DATA_SAVER_CHANGED:
+ handleRestrictBackgroundChanged(toBool(msg.arg1));
+ break;
case EVENT_UPDATE_TCP_BUFFER_FOR_5G:
handleUpdateTCPBuffersfor5G();
break;
@@ -3506,30 +3632,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();
}
}
@@ -3817,6 +3920,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
private void setLockdownTracker(LockdownVpnTracker tracker) {
// Shutdown any existing tracker
final LockdownVpnTracker existing = mLockdownTracker;
+ // TODO: Add a trigger when the always-on VPN enable/disable to reevaluate and send the
+ // necessary onBlockedStatusChanged callbacks.
mLockdownTracker = null;
if (existing != null) {
existing.shutdown();
@@ -4035,7 +4140,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();
@@ -4816,15 +4921,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;
}
/**
@@ -4897,9 +5001,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) {
@@ -4928,12 +5032,20 @@ public class ConnectivityService extends IConnectivityManager.Stub
notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_CAP_CHANGED);
}
- // Report changes that are interesting for network statistics tracking.
if (prevNc != null) {
- final boolean meteredChanged = prevNc.hasCapability(NET_CAPABILITY_NOT_METERED) !=
- newNc.hasCapability(NET_CAPABILITY_NOT_METERED);
+ final boolean oldMetered = prevNc.isMetered();
+ final boolean newMetered = newNc.isMetered();
+ final boolean meteredChanged = oldMetered != newMetered;
+
+ if (meteredChanged) {
+ maybeNotifyNetworkBlocked(nai, oldMetered, newMetered, mRestrictBackground,
+ mRestrictBackground);
+ }
+
final boolean roamingChanged = prevNc.hasCapability(NET_CAPABILITY_NOT_ROAMING) !=
newNc.hasCapability(NET_CAPABILITY_NOT_ROAMING);
+
+ // Report changes that are interesting for network statistics tracking.
if (meteredChanged || roamingChanged) {
notifyIfacesChangedForNetworkStats();
}
@@ -5063,6 +5175,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
case ConnectivityManager.CALLBACK_AVAILABLE: {
putParcelable(bundle, new NetworkCapabilities(networkAgent.networkCapabilities));
putParcelable(bundle, new LinkProperties(networkAgent.linkProperties));
+ // For this notification, arg1 contains the blocked status.
+ msg.arg1 = arg1;
break;
}
case ConnectivityManager.CALLBACK_LOSING: {
@@ -5080,6 +5194,10 @@ public class ConnectivityService extends IConnectivityManager.Stub
putParcelable(bundle, new LinkProperties(networkAgent.linkProperties));
break;
}
+ case ConnectivityManager.CALLBACK_BLK_CHANGED: {
+ msg.arg1 = arg1;
+ break;
+ }
}
msg.what = notificationType;
msg.setData(bundle);
@@ -5578,15 +5696,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.
}
@@ -5608,15 +5718,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);
@@ -5665,7 +5767,76 @@ public class ConnectivityService extends IConnectivityManager.Stub
return;
}
- callCallbackForRequest(nri, nai, ConnectivityManager.CALLBACK_AVAILABLE, 0);
+ final boolean metered = nai.networkCapabilities.isMetered();
+ final boolean blocked = isUidNetworkingWithVpnBlocked(nri.mUid, mUidRules.get(nri.mUid),
+ metered, mRestrictBackground);
+ callCallbackForRequest(nri, nai, ConnectivityManager.CALLBACK_AVAILABLE, blocked ? 1 : 0);
+ }
+
+ /**
+ * Notify of the blocked state apps with a registered callback matching a given NAI.
+ *
+ * Unlike other callbacks, blocked status is different between each individual uid. So for
+ * any given nai, all requests need to be considered according to the uid who filed it.
+ *
+ * @param nai The target NetworkAgentInfo.
+ * @param oldMetered True if the previous network capabilities is metered.
+ * @param newRestrictBackground True if data saver is enabled.
+ */
+ private void maybeNotifyNetworkBlocked(NetworkAgentInfo nai, boolean oldMetered,
+ boolean newMetered, boolean oldRestrictBackground, boolean newRestrictBackground) {
+
+ for (int i = 0; i < nai.numNetworkRequests(); i++) {
+ NetworkRequest nr = nai.requestAt(i);
+ NetworkRequestInfo nri = mNetworkRequests.get(nr);
+ final int uidRules = mUidRules.get(nri.mUid);
+ final boolean oldBlocked, newBlocked;
+ // mVpns lock needs to be hold here to ensure that the active VPN cannot be changed
+ // between these two calls.
+ synchronized (mVpns) {
+ oldBlocked = isUidNetworkingWithVpnBlocked(nri.mUid, uidRules, oldMetered,
+ oldRestrictBackground);
+ newBlocked = isUidNetworkingWithVpnBlocked(nri.mUid, uidRules, newMetered,
+ newRestrictBackground);
+ }
+ if (oldBlocked != newBlocked) {
+ callCallbackForRequest(nri, nai, ConnectivityManager.CALLBACK_BLK_CHANGED,
+ encodeBool(newBlocked));
+ }
+ }
+ }
+
+ /**
+ * Notify apps with a given UID of the new blocked state according to new uid rules.
+ * @param uid The uid for which the rules changed.
+ * @param newRules The new rules to apply.
+ */
+ private void maybeNotifyNetworkBlockedForNewUidRules(int uid, int newRules) {
+ for (final NetworkAgentInfo nai : mNetworkAgentInfos.values()) {
+ final boolean metered = nai.networkCapabilities.isMetered();
+ final boolean oldBlocked, newBlocked;
+ // TODO: Consider that doze mode or turn on/off battery saver would deliver lots of uid
+ // rules changed event. And this function actually loop through all connected nai and
+ // its requests. It seems that mVpns lock will be grabbed frequently in this case.
+ // Reduce the number of locking or optimize the use of lock are likely needed in future.
+ synchronized (mVpns) {
+ oldBlocked = isUidNetworkingWithVpnBlocked(
+ uid, mUidRules.get(uid), metered, mRestrictBackground);
+ newBlocked = isUidNetworkingWithVpnBlocked(
+ uid, newRules, metered, mRestrictBackground);
+ }
+ if (oldBlocked == newBlocked) {
+ return;
+ }
+ final int arg = encodeBool(newBlocked);
+ for (int i = 0; i < nai.numNetworkRequests(); i++) {
+ NetworkRequest nr = nai.requestAt(i);
+ NetworkRequestInfo nri = mNetworkRequests.get(nr);
+ if (nri != null && nri.mUid == uid) {
+ callCallbackForRequest(nri, nai, ConnectivityManager.CALLBACK_BLK_CHANGED, arg);
+ }
+ }
+ }
}
private void sendLegacyNetworkBroadcast(NetworkAgentInfo nai, DetailedState state, int type) {
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/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index b3d88f44275f..3d285b6f28d6 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -76,6 +76,7 @@ import android.util.ArraySet;
import android.util.EventLog;
import android.util.Log;
import android.util.Slog;
+
import com.android.internal.content.PackageMonitor;
import com.android.internal.location.ProviderProperties;
import com.android.internal.location.ProviderRequest;
@@ -99,6 +100,7 @@ import com.android.server.location.LocationRequestStatistics.PackageProviderKey;
import com.android.server.location.LocationRequestStatistics.PackageStatistics;
import com.android.server.location.MockProvider;
import com.android.server.location.PassiveProvider;
+
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -1774,9 +1776,7 @@ public class LocationManagerService extends ILocationManager.Stub {
if (enabled) {
p.enable();
- if (listeners > 0) {
- applyRequirementsLocked(provider);
- }
+ applyRequirementsLocked(provider);
} else {
p.disable();
}
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/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index fb8894b48411..65f3c035b031 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;
@@ -215,6 +216,9 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
private int mPreferredDataSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+ @TelephonyManager.RadioPowerState
+ private int mRadioPowerState = TelephonyManager.RADIO_POWER_UNAVAILABLE;
+
private final LocalLog mLocalLog = new LocalLog(100);
private PreciseDataConnectionState mPreciseDataConnectionState =
@@ -761,6 +765,13 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
remove(r.binder);
}
}
+ if ((events & PhoneStateListener.LISTEN_RADIO_POWER_STATE_CHANGED) != 0) {
+ try {
+ r.callback.onRadioPowerStateChanged(mRadioPowerState);
+ } catch (RemoteException ex) {
+ remove(r.binder);
+ }
+ }
}
}
} else {
@@ -1608,6 +1619,32 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
}
}
+ public void notifyRadioPowerStateChanged(@TelephonyManager.RadioPowerState int state) {
+ if (!checkNotifyPermission("notifyRadioPowerStateChanged()")) {
+ return;
+ }
+
+ if (VDBG) {
+ log("notifyRadioPowerStateChanged: state= " + state);
+ }
+
+ synchronized (mRecords) {
+ mRadioPowerState = state;
+
+ for (Record r : mRecords) {
+ if (r.matchPhoneStateListenerEvent(
+ PhoneStateListener.LISTEN_RADIO_POWER_STATE_CHANGED)) {
+ try {
+ r.callback.onRadioPowerStateChanged(state);
+ } catch (RemoteException ex) {
+ mRemoveList.add(r.binder);
+ }
+ }
+ }
+ handleRemoveListLocked();
+ }
+ }
+
@Override
public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " ");
@@ -1645,6 +1682,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
pw.println("mVoLteServiceState=" + mVoLteServiceState);
pw.println("mPhoneCapability=" + mPhoneCapability);
pw.println("mPreferredDataSubId=" + mPreferredDataSubId);
+ pw.println("mRadioPowerState=" + mRadioPowerState);
pw.decreaseIndent();
@@ -1719,8 +1757,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/Watchdog.java b/services/core/java/com/android/server/Watchdog.java
index 353decc165ac..c51e9e46efa2 100644
--- a/services/core/java/com/android/server/Watchdog.java
+++ b/services/core/java/com/android/server/Watchdog.java
@@ -599,7 +599,7 @@ public class Watchdog extends Thread {
Thread dropboxThread = new Thread("watchdogWriteToDropbox") {
public void run() {
mActivity.addErrorToDropBox(
- "watchdog", null, "system_server", null, null,
+ "watchdog", null, "system_server", null, null, null,
subject, null, finalStack, null);
}
};
diff --git a/services/core/java/com/android/server/WiredAccessoryManager.java b/services/core/java/com/android/server/WiredAccessoryManager.java
index a4ceb0114515..a8530b87dd8e 100644
--- a/services/core/java/com/android/server/WiredAccessoryManager.java
+++ b/services/core/java/com/android/server/WiredAccessoryManager.java
@@ -354,7 +354,8 @@ final class WiredAccessoryManager implements WiredAccessoryCallbacks {
Slog.w(TAG, uei.getSwitchStatePath() +
" not found while attempting to determine initial switch state");
} catch (Exception e) {
- Slog.e(TAG, "" , e);
+ Slog.e(TAG, "Error while attempting to determine initial switch state for "
+ + uei.getDevName() , e);
}
}
}
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index cead8aa3d0c2..5d7a705e4342 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;
@@ -556,7 +555,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
@@ -584,7 +583,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.
@@ -593,7 +592,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) {
@@ -1446,8 +1445,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);
}
@@ -1627,8 +1626,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,
@@ -1684,7 +1684,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);
}
@@ -1798,7 +1798,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);
@@ -3328,9 +3328,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())) {
@@ -3689,7 +3689,7 @@ public final class ActiveServices {
nextTime = sr.executingStart;
}
}
- if (timeout != null && mAm.mLruProcesses.contains(proc)) {
+ if (timeout != null && mAm.mProcessList.mLruProcesses.contains(proc)) {
Slog.w(TAG, "Timeout executing service: " + timeout);
StringWriter sw = new StringWriter();
PrintWriter pw = new FastPrintWriter(sw, false, 1024);
@@ -3710,7 +3710,7 @@ public final class ActiveServices {
}
if (anrMessage != null) {
- mAm.mAppErrors.appNotResponding(proc, null, null, false, anrMessage);
+ proc.appNotResponding(null, null, null, null, false, anrMessage);
}
}
@@ -3735,7 +3735,7 @@ public final class ActiveServices {
}
if (app != null) {
- mAm.mAppErrors.appNotResponding(app, null, null, false,
+ app.appNotResponding(null, null, null, null, false,
"Context.startForegroundService() did not then call Service.startForeground(): "
+ r);
}
diff --git a/services/core/java/com/android/server/am/ActivityDisplay.java b/services/core/java/com/android/server/am/ActivityDisplay.java
index a648b09abda5..9a47553bf446 100644
--- a/services/core/java/com/android/server/am/ActivityDisplay.java
+++ b/services/core/java/com/android/server/am/ActivityDisplay.java
@@ -37,16 +37,16 @@ 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.ActivityStack.ActivityState.RESUMED;
import static com.android.server.am.ActivityStackSupervisor.FindTaskResult;
import static com.android.server.am.ActivityStackSupervisor.TAG_STATES;
import static com.android.server.am.ActivityStackSupervisor.TAG_TASKS;
+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 android.annotation.Nullable;
import android.app.ActivityOptions;
@@ -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;
@@ -998,7 +998,10 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack>
* @see Display#FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS
*/
boolean supportsSystemDecorations() {
- return mDisplay.supportsSystemDecorations();
+ return mDisplay.supportsSystemDecorations()
+ // TODO (b/111363427): Remove this and set the new FLAG_SHOULD_SHOW_LAUNCHER flag
+ // (b/114338689) whenever vr 2d display id is set.
+ || mDisplayId == mSupervisor.mService.mVr2dDisplayId;
}
private boolean shouldDestroyContentOnRemove() {
@@ -1087,7 +1090,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 6266e11ec55c..00824c382eb7 100644
--- a/services/core/java/com/android/server/am/ActivityManagerConstants.java
+++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java
@@ -223,7 +223,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 6a506d5a4d13..8b5ab202c8b6 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -18,19 +18,16 @@ package com.android.server.am;
import static android.Manifest.permission.CHANGE_CONFIGURATION;
import static android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST;
+import static android.Manifest.permission.FILTER_EVENTS;
import static android.Manifest.permission.INTERACT_ACROSS_USERS;
import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
-import static android.Manifest.permission.MANAGE_ACTIVITY_STACKS;
import static android.Manifest.permission.REMOVE_TASKS;
import static android.app.ActivityManager.PROCESS_STATE_CACHED_ACTIVITY;
import static android.app.ActivityManager.PROCESS_STATE_LAST_ACTIVITY;
import static android.app.ActivityManagerInternal.ALLOW_FULL_ONLY;
import static android.app.ActivityManagerInternal.ALLOW_NON_FULL;
-import static android.app.ActivityThread.PROC_START_SEQ_IDENT;
import static android.app.AppOpsManager.OP_NONE;
-import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
-import static android.content.Intent.FLAG_ACTIVITY_TASK_ON_HOME;
import static android.content.pm.ApplicationInfo.HIDDEN_API_ENFORCEMENT_DEFAULT;
import static android.content.pm.PackageManager.GET_PROVIDERS;
import static android.content.pm.PackageManager.MATCH_ANY_USER;
@@ -49,8 +46,6 @@ import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_NORMAL;
import static android.os.IServiceManager.DUMP_FLAG_PROTO;
import static android.os.Process.BLUETOOTH_UID;
import static android.os.Process.FIRST_APPLICATION_UID;
-import static android.os.Process.FIRST_ISOLATED_UID;
-import static android.os.Process.LAST_ISOLATED_UID;
import static android.os.Process.NFC_UID;
import static android.os.Process.PHONE_UID;
import static android.os.Process.PROC_CHAR;
@@ -69,10 +64,10 @@ import static android.os.Process.THREAD_GROUP_BG_NONINTERACTIVE;
import static android.os.Process.THREAD_GROUP_DEFAULT;
import static android.os.Process.THREAD_GROUP_RESTRICTED;
import static android.os.Process.THREAD_GROUP_TOP_APP;
-import static android.os.Process.THREAD_PRIORITY_BACKGROUND;
import static android.os.Process.THREAD_PRIORITY_FOREGROUND;
-import static android.os.Process.getFreeMemory;
+import static android.os.Process.getPidsForCommands;
import static android.os.Process.getTotalMemory;
+import static android.os.Process.getUidForPid;
import static android.os.Process.isThreadInProcess;
import static android.os.Process.killProcess;
import static android.os.Process.killProcessQuiet;
@@ -85,14 +80,12 @@ import static android.os.Process.setProcessGroup;
import static android.os.Process.setCgroupProcsProcessGroup;
import static android.os.Process.setThreadPriority;
import static android.os.Process.setThreadScheduler;
-import static android.os.Process.startWebView;
import static android.os.Process.zygoteProcess;
import static android.provider.Settings.Global.ALWAYS_FINISH_ACTIVITIES;
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;
@@ -101,9 +94,6 @@ 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.ActivityManagerDebugConfig.DEBUG_LRU;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_MU;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_NETWORK;
@@ -116,15 +106,12 @@ 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.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.ActivityManagerDebugConfig.POSTFIX_LRU;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_MU;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_NETWORK;
@@ -135,13 +122,32 @@ 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.ActivityManagerDebugConfig.POSTFIX_UID_OBSERVERS;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
-import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS;
+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.ActivityTaskManagerDebugConfig.DEBUG_SWITCH;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_CONFIGURATION;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_LOCKTASK;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.POSTFIX_SWITCH;
+import static com.android.server.am.ActivityTaskManagerService.DUMP_ACTIVITIES_CMD;
+import static com.android.server.am.ActivityTaskManagerService.DUMP_ACTIVITIES_SHORT_CMD;
+import static com.android.server.am.ActivityTaskManagerService.DUMP_CONTAINERS_CMD;
+import static com.android.server.am.ActivityTaskManagerService.DUMP_LASTANR_CMD;
+import static com.android.server.am.ActivityTaskManagerService.DUMP_LASTANR_TRACES_CMD;
+import static com.android.server.am.ActivityTaskManagerService.DUMP_RECENTS_CMD;
+import static com.android.server.am.ActivityTaskManagerService.DUMP_RECENTS_SHORT_CMD;
+import static com.android.server.am.ActivityTaskManagerService.DUMP_STARTER_CMD;
+import static com.android.server.am.ActivityTaskManagerService.KEY_DISPATCHING_TIMEOUT_MS;
+import static com.android.server.am.ActivityTaskManagerService.RELAUNCH_REASON_NONE;
+import static com.android.server.am.ActivityTaskManagerService.relaunchReasonToString;
+import static com.android.server.am.MemoryStatUtil.MEMORY_STAT_INTERESTING_NATIVE_PROCESSES;
import static com.android.server.am.MemoryStatUtil.hasMemcg;
+import static com.android.server.am.MemoryStatUtil.readCmdlineFromProcfs;
import static com.android.server.am.MemoryStatUtil.readMemoryStatFromFilesystem;
+import static com.android.server.am.MemoryStatUtil.readMemoryStatFromProcfs;
import android.Manifest;
import android.Manifest.permission;
@@ -154,7 +160,6 @@ import android.app.ActivityManager.RunningTaskInfo;
import android.app.ActivityManager.StackInfo;
import android.app.ActivityManagerInternal;
import android.app.ActivityManagerProto;
-import android.app.ActivityOptions;
import android.app.ActivityThread;
import android.app.AppGlobals;
import android.app.AppOpsManager;
@@ -183,6 +188,7 @@ import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.ProcessMemoryState;
import android.app.ProfilerInfo;
+import android.app.WaitResult;
import android.app.WindowConfiguration.ActivityType;
import android.app.WindowConfiguration.WindowingMode;
import android.app.backup.IBackupManager;
@@ -203,7 +209,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;
@@ -256,7 +261,6 @@ import android.os.PowerManager;
import android.os.PowerManager.ServiceType;
import android.os.PowerManagerInternal;
import android.os.Process;
-import android.os.Process.ProcessStartResult;
import android.os.RemoteCallback;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
@@ -271,9 +275,7 @@ 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;
import android.text.TextUtils;
import android.text.format.DateUtils;
@@ -283,7 +285,6 @@ import android.util.ArraySet;
import android.util.DebugUtils;
import android.util.EventLog;
import android.util.Log;
-import android.util.LongSparseArray;
import android.util.Pair;
import android.util.PrintWriterPrinter;
import android.util.Slog;
@@ -322,7 +323,6 @@ import com.android.internal.os.ByteTransferPipe;
import com.android.internal.os.IResultReceiver;
import com.android.internal.os.ProcessCpuTracker;
import com.android.internal.os.TransferPipe;
-import com.android.internal.os.Zygote;
import com.android.internal.telephony.TelephonyIntents;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.DumpUtils;
@@ -348,13 +348,11 @@ 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;
import com.android.server.pm.Installer;
import com.android.server.pm.Installer.InstallerException;
-import com.android.server.pm.dex.DexManager;
import com.android.server.uri.GrantUri;
import com.android.server.uri.UriGrantsManagerInternal;
import com.android.server.utils.PriorityDump;
@@ -366,18 +364,15 @@ import dalvik.system.VMRuntime;
import libcore.util.EmptyArray;
-import java.io.BufferedReader;
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
-import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
-import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
@@ -406,24 +401,24 @@ public class ActivityManagerService extends IActivityManager.Stub
*/
public static final int TOP_APP_PRIORITY_BOOST = -10;
- private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityManagerService" : TAG_AM;
+ static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityManagerService" : TAG_AM;
private static final String TAG_BACKUP = TAG + POSTFIX_BACKUP;
private static final String TAG_BROADCAST = TAG + POSTFIX_BROADCAST;
private static final String TAG_CLEANUP = TAG + POSTFIX_CLEANUP;
private static final String TAG_CONFIGURATION = TAG + POSTFIX_CONFIGURATION;
private static final String TAG_LOCKTASK = TAG + POSTFIX_LOCKTASK;
- private static final String TAG_LRU = TAG + POSTFIX_LRU;
+ static final String TAG_LRU = TAG + POSTFIX_LRU;
private static final String TAG_MU = TAG + POSTFIX_MU;
private static final String TAG_NETWORK = TAG + POSTFIX_NETWORK;
private static final String TAG_OOM_ADJ = TAG + POSTFIX_OOM_ADJ;
private static final String TAG_POWER = TAG + POSTFIX_POWER;
private static final String TAG_PROCESS_OBSERVERS = TAG + POSTFIX_PROCESS_OBSERVERS;
- private static final String TAG_PROCESSES = TAG + POSTFIX_PROCESSES;
+ static final String TAG_PROCESSES = TAG + POSTFIX_PROCESSES;
private static final String TAG_PROVIDER = TAG + POSTFIX_PROVIDER;
- private static final String TAG_PSS = TAG + POSTFIX_PSS;
+ static final String TAG_PSS = TAG + POSTFIX_PSS;
private static final String TAG_SERVICE = TAG + POSTFIX_SERVICE;
private static final String TAG_SWITCH = TAG + POSTFIX_SWITCH;
- private static final String TAG_UID_OBSERVERS = TAG + POSTFIX_UID_OBSERVERS;
+ static final String TAG_UID_OBSERVERS = TAG + POSTFIX_UID_OBSERVERS;
// Mock "pretend we're idle now" broadcast action to the job scheduler; declared
// here so that while the job scheduler can depend on AMS, the other way around
@@ -441,11 +436,11 @@ 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";
- private static final String ANR_TRACE_DIR = "/data/anr";
+ public static final String ANR_TRACE_DIR = "/data/anr";
// Maximum number of receivers an app can register.
private static final int MAX_RECEIVERS_ALLOWED_PER_APP = 1000;
@@ -457,6 +452,12 @@ public class ActivityManagerService extends IActivityManager.Stub
// before we decide it must be hung.
static final int CONTENT_PROVIDER_PUBLISH_TIMEOUT = 10*1000;
+ /**
+ * How long we wait for an provider to be published. Should be longer than
+ * {@link #CONTENT_PROVIDER_PUBLISH_TIMEOUT}.
+ */
+ static final int CONTENT_PROVIDER_WAIT_TIMEOUT = 20 * 1000;
+
// How long we wait for a launched process to attach to the activity manager
// before we decide it's never going to come up for real, when the process was
// started with a wrapper for instrumentation (such as Valgrind) because it
@@ -471,7 +472,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,16 +486,13 @@ public class ActivityManagerService extends IActivityManager.Stub
private static final int SLOW_UID_OBSERVER_THRESHOLD_MS = 20;
// Necessary ApplicationInfo flags to mark an app as persistent
- private static final int PERSISTENT_MASK =
+ static final int PERSISTENT_MASK =
ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT;
// Intent sent when remote bugreport collection has been completed
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;
@@ -503,6 +501,9 @@ public class ActivityManagerService extends IActivityManager.Stub
*/
private static final long NETWORK_ACCESS_TIMEOUT_DEFAULT_MS = 200; // 0.2 sec
+ // The minimum memory growth threshold (in KB) for low RAM devices.
+ private static final int MINIMUM_MEMORY_GROWTH_THRESHOLD = 10 * 1000; // 10 MB
+
/**
* State indicating that there is no need for any blocking for network.
*/
@@ -541,9 +542,6 @@ public class ActivityManagerService extends IActivityManager.Stub
private Installer mInstaller;
- /** Run all ActivityStacks through this */
- ActivityStackSupervisor mStackSupervisor;
-
final InstrumentationReporter mInstrumentationReporter = new InstrumentationReporter();
final ArrayList<ActiveInstrumentation> mActiveInstrumentation = new ArrayList<>();
@@ -583,12 +581,6 @@ public class ActivityManagerService extends IActivityManager.Stub
final AppErrors mAppErrors;
/**
- * Dump of the activity state at the time of the last ANR. Cleared after
- * {@link WindowManagerService#LAST_ANR_LIFETIME_DURATION_MSECS}
- */
- String mLastANRState;
-
- /**
* Indicates the maximum time spent waiting for the network rules to get updated.
*/
@VisibleForTesting
@@ -641,46 +633,12 @@ public class ActivityManagerService extends IActivityManager.Stub
final ProcessList mProcessList = new ProcessList();
/**
- * All of the applications we currently have running organized by name.
- * The keys are strings of the application package name (as
- * returned by the package manager), and the keys are ApplicationRecord
- * objects.
- */
- final MyProcessMap mProcessNames = new MyProcessMap();
- final class MyProcessMap extends ProcessMap<ProcessRecord> {
- @Override
- public ProcessRecord put(String name, int uid, ProcessRecord value) {
- final ProcessRecord r = super.put(name, uid, value);
- mAtmInternal.onProcessAdded(r.getWindowProcessController());
- return r;
- }
-
- @Override
- public ProcessRecord remove(String name, int uid) {
- final ProcessRecord r = super.remove(name, uid);
- mAtmInternal.onProcessRemoved(name, uid);
- return r;
- }
- }
-
- /**
* Tracking long-term execution of processes to look for abuse and other
* bad app behavior.
*/
final ProcessStatsService mProcessStats;
/**
- * The currently running isolated processes.
- */
- final SparseArray<ProcessRecord> mIsolatedProcesses = new SparseArray<>();
-
- /**
- * Counter for assigning isolated process uids, to avoid frequently reusing the
- * same ones.
- */
- int mNextIsolatedProcessUid = 0;
-
- /**
* Non-persistent appId whitelist for background restrictions
*/
int[] mBackgroundAppIdWhitelist = new int[] {
@@ -781,28 +739,6 @@ public class ActivityManagerService extends IActivityManager.Stub
final ArrayList<ProcessRecord> mPersistentStartingProcesses = new ArrayList<ProcessRecord>();
/**
- * Processes that are being forcibly torn down.
- */
- final ArrayList<ProcessRecord> mRemovedProcesses = new ArrayList<ProcessRecord>();
-
- /**
- * List of running applications, sorted by recent usage.
- * The first entry in the list is the least recently used.
- */
- final ArrayList<ProcessRecord> mLruProcesses = new ArrayList<ProcessRecord>();
-
- /**
- * Where in mLruProcesses that the processes hosting activities start.
- */
- int mLruProcessActivityStart = 0;
-
- /**
- * Where in mLruProcesses that the processes hosting services start.
- * This is after (lower index) than mLruProcessesActivityStart.
- */
- int mLruProcessServiceStart = 0;
-
- /**
* List of processes that should gc as soon as things are idle.
*/
final ArrayList<ProcessRecord> mProcessesToGc = new ArrayList<ProcessRecord>();
@@ -1069,11 +1005,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.
*/
@@ -1093,7 +1024,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;
@@ -1124,11 +1054,6 @@ public class ActivityManagerService extends IActivityManager.Stub
int mAdjSeq = 0;
/**
- * Current sequence id for process LRU updating.
- */
- int mLruSeq = 0;
-
- /**
* Keep track of the non-cached/empty process we last found, to help
* determine how to distribute cached/empty processes next time.
*/
@@ -1240,31 +1165,6 @@ public class ActivityManagerService extends IActivityManager.Stub
private final ArraySet<BroadcastQueue> mTmpBroadcastQueue = new ArraySet();
- /**
- * A global counter for generating sequence numbers.
- * This value will be used when incrementing sequence numbers in individual uidRecords.
- *
- * Having a global counter ensures that seq numbers are monotonically increasing for a
- * particular uid even when the uidRecord is re-created.
- */
- @GuardedBy("this")
- @VisibleForTesting
- long mProcStateSeqCounter = 0;
-
- /**
- * A global counter for generating sequence numbers to uniquely identify pending process starts.
- */
- @GuardedBy("this")
- private long mProcStartSeqCounter = 0;
-
- /**
- * Contains {@link ProcessRecord} objects for pending process starts.
- *
- * Mapping: {@link #mProcStartSeqCounter} -> {@link ProcessRecord}
- */
- @GuardedBy("this")
- private final LongSparseArray<ProcessRecord> mPendingStarts = new LongSparseArray<>();
-
private final Injector mInjector;
static final class ProcessChangeItem {
@@ -1421,7 +1321,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;
@@ -1436,7 +1335,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;
@@ -1451,15 +1349,11 @@ public class ActivityManagerService extends IActivityManager.Stub
static final int DISPATCH_OOM_ADJ_OBSERVER_MSG = 70;
static final int NETWORK_OPTS_CHECK_MSG = 88;
- 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";
static ServiceThread sKillThread = null;
- static KillHandler sKillHandler = null;
static final ActivityTrigger mActivityTrigger = new ActivityTrigger();
long mLastMemUsageReportTime = 0;
@@ -1508,31 +1402,7 @@ public class ActivityManagerService extends IActivityManager.Stub
* also corresponds to the merged configuration of the default display.
*/
Configuration getGlobalConfiguration() {
- return mStackSupervisor.getConfiguration();
- }
-
- final class KillHandler extends Handler {
- static final int KILL_PROCESS_GROUP_MSG = 4000;
-
- public KillHandler(Looper looper) {
- super(looper, null, true);
- }
-
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case KILL_PROCESS_GROUP_MSG:
- {
- Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "killProcessGroup");
- Process.killProcessGroup(msg.arg1 /* uid */, msg.arg2 /* pid */);
- Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
- }
- break;
-
- default:
- super.handleMessage(msg);
- }
- }
+ return mActivityTaskManager.getGlobalConfiguration();
}
final class UiHandler extends Handler {
@@ -1631,11 +1501,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();
@@ -1653,8 +1518,8 @@ public class ActivityManagerService extends IActivityManager.Stub
} break;
case UPDATE_TIME_ZONE: {
synchronized (ActivityManagerService.this) {
- for (int i = mLruProcesses.size() - 1 ; i >= 0 ; i--) {
- ProcessRecord r = mLruProcesses.get(i);
+ for (int i = mProcessList.mLruProcesses.size() - 1; i >= 0; i--) {
+ ProcessRecord r = mProcessList.mLruProcesses.get(i);
if (r.thread != null) {
try {
r.thread.updateTimeZone();
@@ -1667,16 +1532,7 @@ public class ActivityManagerService extends IActivityManager.Stub
} break;
case CLEAR_DNS_CACHE_MSG: {
synchronized (ActivityManagerService.this) {
- for (int i = mLruProcesses.size() - 1 ; i >= 0 ; i--) {
- ProcessRecord r = mLruProcesses.get(i);
- if (r.thread != null) {
- try {
- r.thread.clearDnsCache();
- } catch (RemoteException ex) {
- Slog.w(TAG, "Failed to clear dns cache for: " + r.info.processName);
- }
- }
- }
+ mProcessList.clearAllDnsCacheLocked();
}
} break;
case UPDATE_HTTP_PROXY_MSG: {
@@ -1692,19 +1548,7 @@ public class ActivityManagerService extends IActivityManager.Stub
pacFileUrl = proxy.getPacFileUrl();
}
synchronized (ActivityManagerService.this) {
- for (int i = mLruProcesses.size() - 1 ; i >= 0 ; i--) {
- ProcessRecord r = mLruProcesses.get(i);
- // Don't dispatch to isolated processes as they can't access
- // ConnectivityManager and don't have network privileges anyway.
- if (r.thread != null && !r.isolated) {
- try {
- r.thread.setHttpProxy(host, port, exclList, pacFileUrl);
- } catch (RemoteException ex) {
- Slog.w(TAG, "Failed to update http proxy for: " +
- r.info.processName);
- }
- }
- }
+ mProcessList.setAllHttpProxyLocked(host, port, exclList, pacFileUrl);
}
} break;
case PROC_START_TIMEOUT_MSG: {
@@ -1752,29 +1596,7 @@ public class ActivityManagerService extends IActivityManager.Stub
// The user's time format preference might have changed.
// For convenience we re-use the Intent extra values.
synchronized (ActivityManagerService.this) {
- for (int i = mLruProcesses.size() - 1; i >= 0; i--) {
- ProcessRecord r = mLruProcesses.get(i);
- if (r.thread != null) {
- try {
- r.thread.updateTimePrefs(msg.arg1);
- } catch (RemoteException ex) {
- Slog.w(TAG, "Failed to update preferences for: "
- + r.info.processName);
- }
- }
- }
- }
- 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);
+ mProcessList.updateAllTimePrefsLocked(msg.arg1);
}
break;
}
@@ -1898,17 +1720,7 @@ public class ActivityManagerService extends IActivityManager.Stub
} break;
case HANDLE_TRUST_STORAGE_UPDATE_MSG: {
synchronized (ActivityManagerService.this) {
- for (int i = mLruProcesses.size() - 1 ; i >= 0 ; i--) {
- ProcessRecord r = mLruProcesses.get(i);
- if (r.thread != null) {
- try {
- r.thread.handleTrustStorageUpdate();
- } catch (RemoteException ex) {
- Slog.w(TAG, "Failed to handle trust storage update for: " +
- r.info.processName);
- }
- }
- }
+ mProcessList.handleAllTrustStorageUpdateLocked();
}
} break;
case NETWORK_OPTS_CHECK_MSG: {
@@ -2067,7 +1879,9 @@ public class ActivityManagerService extends IActivityManager.Stub
mSystemThread.installSystemApplicationInfo(info, getClass().getClassLoader());
synchronized (this) {
- ProcessRecord app = newProcessRecordLocked(info, info.processName, false, 0);
+ ProcessRecord app = mProcessList.newProcessRecordLocked(info, info.processName,
+ false,
+ 0);
app.setPersistent(true);
app.pid = MY_PID;
app.getWindowProcessController().setPid(MY_PID);
@@ -2076,7 +1890,7 @@ public class ActivityManagerService extends IActivityManager.Stub
synchronized (mPidsSelfLocked) {
mPidsSelfLocked.put(app.pid, app);
}
- updateLruProcessLocked(app, false, null);
+ mProcessList.updateLruProcessLocked(app, false, null);
updateOomAdjLocked();
}
} catch (PackageManager.NameNotFoundException e) {
@@ -2102,12 +1916,12 @@ public class ActivityManagerService extends IActivityManager.Stub
synchronized (this) {
mWindowManager = wm;
mActivityTaskManager.setWindowManager(wm);
- mStackSupervisor.setWindowManager(wm);
}
}
public void setUsageStatsManager(UsageStatsManagerInternal usageStatsManager) {
mUsageStatsService = usageStatsManager;
+ mActivityTaskManager.setUsageStatsManager(usageStatsManager);
}
public void startObservingNativeCrashes() {
@@ -2347,7 +2161,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;
@@ -2395,13 +2208,7 @@ public class ActivityManagerService extends IActivityManager.Stub
mConstants = new ActivityManagerConstants(this, mHandler);
- /* static; one-time init here */
- if (sKillHandler == null) {
- sKillThread = new ServiceThread(TAG + ":kill",
- THREAD_PRIORITY_BACKGROUND, true /* allowIo */);
- sKillThread.start();
- sKillHandler = new KillHandler(sKillThread.getLooper());
- }
+ mProcessList.init(this);
mFgBroadcastQueue = new BroadcastQueue(this, mHandler,
"foreground", BROADCAST_FG_TIMEOUT, false);
@@ -2437,9 +2244,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;
}
@@ -2448,9 +2252,9 @@ 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;
mProcessCpuThread = new Thread("CpuTracker") {
@Override
@@ -2554,12 +2358,13 @@ public class ActivityManagerService extends IActivityManager.Stub
if (code == SYSPROPS_TRANSACTION) {
// We need to tell all apps about the system property change.
ArrayList<IBinder> procs = new ArrayList<IBinder>();
- synchronized(this) {
- final int NP = mProcessNames.getMap().size();
- for (int ip=0; ip<NP; ip++) {
- SparseArray<ProcessRecord> apps = mProcessNames.getMap().valueAt(ip);
+ synchronized (this) {
+ final int NP = mProcessList.mProcessNames.getMap().size();
+ for (int ip = 0; ip < NP; ip++) {
+ SparseArray<ProcessRecord> apps =
+ mProcessList.mProcessNames.getMap().valueAt(ip);
final int NA = apps.size();
- for (int ia=0; ia<NA; ia++) {
+ for (int ia = 0; ia < NA; ia++) {
ProcessRecord app = apps.valueAt(ia);
if (app.thread != null) {
procs.add(app.thread.asBinder());
@@ -2780,10 +2585,6 @@ public class ActivityManagerService extends IActivityManager.Stub
return mAppBindArgs;
}
- public final void networkOptsCheck(int flag, String packageName) {
- mHandler.sendMessage(mHandler.obtainMessage(NETWORK_OPTS_CHECK_MSG, flag, 0, packageName));
- }
-
private static void addServiceToMap(ArrayMap<String, IBinder> map, String name) {
final IBinder service = ServiceManager.getService(name);
if (service != null) {
@@ -2813,329 +2614,21 @@ public class ActivityManagerService extends IActivityManager.Stub
mActivityTaskManager.unregisterTaskStackListener(listener);
}
- private int updateLruProcessInternalLocked(ProcessRecord app, long now, int index,
- String what, Object obj, ProcessRecord srcApp) {
- app.lastActivityTime = now;
-
- if (app.hasActivitiesOrRecentTasks()) {
- // Don't want to touch dependent processes that are hosting activities.
- return index;
- }
-
- int lrui = mLruProcesses.lastIndexOf(app);
- if (lrui < 0) {
- Slog.wtf(TAG, "Adding dependent process " + app + " not on LRU list: "
- + what + " " + obj + " from " + srcApp);
- return index;
- }
-
- if (lrui >= index) {
- // Don't want to cause this to move dependent processes *back* in the
- // list as if they were less frequently used.
- return index;
- }
-
- if (lrui >= mLruProcessActivityStart) {
- // Don't want to touch dependent processes that are hosting activities.
- return index;
- }
-
- mLruProcesses.remove(lrui);
- if (index > 0) {
- index--;
- }
- if (DEBUG_LRU) Slog.d(TAG_LRU, "Moving dep from " + lrui + " to " + index
- + " in LRU list: " + app);
- mLruProcesses.add(index, app);
- return index;
- }
-
- static void killProcessGroup(int uid, int pid) {
- if (sKillHandler != null) {
- sKillHandler.sendMessage(
- sKillHandler.obtainMessage(KillHandler.KILL_PROCESS_GROUP_MSG, uid, pid));
- } else {
- Slog.w(TAG, "Asked to kill process group before system bringup!");
- Process.killProcessGroup(uid, pid);
- }
+ final void updateLruProcessLocked(ProcessRecord app, boolean activityChange,
+ ProcessRecord client) {
+ mProcessList.updateLruProcessLocked(app, activityChange, client);
}
final void removeLruProcessLocked(ProcessRecord app) {
- int lrui = mLruProcesses.lastIndexOf(app);
- if (lrui >= 0) {
- if (!app.killed) {
- if (app.isPersistent()) {
- Slog.w(TAG, "Removing persistent process that hasn't been killed: " + app);
- } else {
- Slog.wtfStack(TAG, "Removing process that hasn't been killed: " + app);
- if (app.pid > 0) {
- killProcessQuiet(app.pid);
- killProcessGroup(app.uid, app.pid);
- } else {
- app.pendingStart = false;
- }
- }
- }
- if (lrui <= mLruProcessActivityStart) {
- mLruProcessActivityStart--;
- }
- if (lrui <= mLruProcessServiceStart) {
- mLruProcessServiceStart--;
- }
- mLruProcesses.remove(lrui);
- }
+ mProcessList.removeLruProcessLocked(app);
}
- final void updateLruProcessLocked(ProcessRecord app, boolean activityChange,
- ProcessRecord client) {
- final boolean hasActivity = app.hasActivitiesOrRecentTasks() || app.hasClientActivities
- || app.treatLikeActivity;
- final boolean hasService = false; // not impl yet. app.services.size() > 0;
- if (!activityChange && hasActivity) {
- // The process has activities, so we are only allowing activity-based adjustments
- // to move it. It should be kept in the front of the list with other
- // processes that have activities, and we don't want those to change their
- // order except due to activity operations.
- return;
- }
-
- mLruSeq++;
- final long now = SystemClock.uptimeMillis();
- app.lastActivityTime = now;
-
- // First a quick reject: if the app is already at the position we will
- // put it, then there is nothing to do.
- if (hasActivity) {
- final int N = mLruProcesses.size();
- if (N > 0 && mLruProcesses.get(N-1) == app) {
- if (DEBUG_LRU) Slog.d(TAG_LRU, "Not moving, already top activity: " + app);
- return;
- }
- } else {
- if (mLruProcessServiceStart > 0
- && mLruProcesses.get(mLruProcessServiceStart-1) == app) {
- if (DEBUG_LRU) Slog.d(TAG_LRU, "Not moving, already top other: " + app);
- return;
- }
- }
-
- int lrui = mLruProcesses.lastIndexOf(app);
-
- if (app.isPersistent() && lrui >= 0) {
- // We don't care about the position of persistent processes, as long as
- // they are in the list.
- if (DEBUG_LRU) Slog.d(TAG_LRU, "Not moving, persistent: " + app);
- return;
- }
-
- /* In progress: compute new position first, so we can avoid doing work
- if the process is not actually going to move. Not yet working.
- int addIndex;
- int nextIndex;
- boolean inActivity = false, inService = false;
- if (hasActivity) {
- // Process has activities, put it at the very tipsy-top.
- addIndex = mLruProcesses.size();
- nextIndex = mLruProcessServiceStart;
- inActivity = true;
- } else if (hasService) {
- // Process has services, put it at the top of the service list.
- addIndex = mLruProcessActivityStart;
- nextIndex = mLruProcessServiceStart;
- inActivity = true;
- inService = true;
- } else {
- // Process not otherwise of interest, it goes to the top of the non-service area.
- addIndex = mLruProcessServiceStart;
- if (client != null) {
- int clientIndex = mLruProcesses.lastIndexOf(client);
- if (clientIndex < 0) Slog.d(TAG, "Unknown client " + client + " when updating "
- + app);
- if (clientIndex >= 0 && addIndex > clientIndex) {
- addIndex = clientIndex;
- }
- }
- nextIndex = addIndex > 0 ? addIndex-1 : addIndex;
- }
-
- Slog.d(TAG, "Update LRU at " + lrui + " to " + addIndex + " (act="
- + mLruProcessActivityStart + "): " + app);
- */
-
- if (lrui >= 0) {
- if (lrui < mLruProcessActivityStart) {
- mLruProcessActivityStart--;
- }
- if (lrui < mLruProcessServiceStart) {
- mLruProcessServiceStart--;
- }
- /*
- if (addIndex > lrui) {
- addIndex--;
- }
- if (nextIndex > lrui) {
- nextIndex--;
- }
- */
- mLruProcesses.remove(lrui);
- }
-
- /*
- mLruProcesses.add(addIndex, app);
- if (inActivity) {
- mLruProcessActivityStart++;
- }
- if (inService) {
- mLruProcessActivityStart++;
- }
- */
-
- int nextIndex;
- if (hasActivity) {
- final int N = mLruProcesses.size();
- if ((!app.hasActivities() || app.hasRecentTasks())
- && mLruProcessActivityStart < (N - 1)) {
- // Process doesn't have activities, but has clients with
- // activities... move it up, but one below the top (the top
- // should always have a real activity).
- if (DEBUG_LRU) Slog.d(TAG_LRU,
- "Adding to second-top of LRU activity list: " + app);
- mLruProcesses.add(N - 1, app);
- // To keep it from spamming the LRU list (by making a bunch of clients),
- // we will push down any other entries owned by the app.
- final int uid = app.info.uid;
- for (int i = N - 2; i > mLruProcessActivityStart; i--) {
- ProcessRecord subProc = mLruProcesses.get(i);
- if (subProc.info.uid == uid) {
- // We want to push this one down the list. If the process after
- // it is for the same uid, however, don't do so, because we don't
- // want them internally to be re-ordered.
- if (mLruProcesses.get(i - 1).info.uid != uid) {
- if (DEBUG_LRU) Slog.d(TAG_LRU,
- "Pushing uid " + uid + " swapping at " + i + ": "
- + mLruProcesses.get(i) + " : " + mLruProcesses.get(i - 1));
- ProcessRecord tmp = mLruProcesses.get(i);
- mLruProcesses.set(i, mLruProcesses.get(i - 1));
- mLruProcesses.set(i - 1, tmp);
- i--;
- }
- } else {
- // A gap, we can stop here.
- break;
- }
- }
- } else {
- // Process has activities, put it at the very tipsy-top.
- if (DEBUG_LRU) Slog.d(TAG_LRU, "Adding to top of LRU activity list: " + app);
- mLruProcesses.add(app);
- }
- nextIndex = mLruProcessServiceStart;
- } else if (hasService) {
- // Process has services, put it at the top of the service list.
- if (DEBUG_LRU) Slog.d(TAG_LRU, "Adding to top of LRU service list: " + app);
- mLruProcesses.add(mLruProcessActivityStart, app);
- nextIndex = mLruProcessServiceStart;
- mLruProcessActivityStart++;
- } else {
- // Process not otherwise of interest, it goes to the top of the non-service area.
- int index = mLruProcessServiceStart;
- if (client != null) {
- // If there is a client, don't allow the process to be moved up higher
- // in the list than that client.
- int clientIndex = mLruProcesses.lastIndexOf(client);
- if (DEBUG_LRU && clientIndex < 0) Slog.d(TAG_LRU, "Unknown client " + client
- + " when updating " + app);
- if (clientIndex <= lrui) {
- // Don't allow the client index restriction to push it down farther in the
- // list than it already is.
- clientIndex = lrui;
- }
- if (clientIndex >= 0 && index > clientIndex) {
- index = clientIndex;
- }
- }
- if (DEBUG_LRU) Slog.d(TAG_LRU, "Adding at " + index + " of LRU list: " + app);
- mLruProcesses.add(index, app);
- nextIndex = index-1;
- mLruProcessActivityStart++;
- mLruProcessServiceStart++;
- }
-
- // If the app is currently using a content provider or service,
- // bump those processes as well.
- for (int j=app.connections.size()-1; j>=0; j--) {
- ConnectionRecord cr = app.connections.valueAt(j);
- if (cr.binding != null && !cr.serviceDead && cr.binding.service != null
- && cr.binding.service.app != null
- && cr.binding.service.app.lruSeq != mLruSeq
- && !cr.binding.service.app.isPersistent()) {
- nextIndex = updateLruProcessInternalLocked(cr.binding.service.app, now, nextIndex,
- "service connection", cr, app);
- }
- }
- for (int j=app.conProviders.size()-1; j>=0; j--) {
- ContentProviderRecord cpr = app.conProviders.get(j).provider;
- if (cpr.proc != null && cpr.proc.lruSeq != mLruSeq && !cpr.proc.isPersistent()) {
- nextIndex = updateLruProcessInternalLocked(cpr.proc, now, nextIndex,
- "provider reference", cpr, app);
- }
- }
+ final ProcessRecord getProcessRecordLocked(String processName, int uid, boolean keepIfLarge) {
+ return mProcessList.getProcessRecordLocked(processName, uid, keepIfLarge);
}
- final ProcessRecord getProcessRecordLocked(String processName, int uid, boolean keepIfLarge) {
- if (uid == SYSTEM_UID) {
- // The system gets to run in any process. If there are multiple
- // processes with the same uid, just pick the first (this
- // should never happen).
- SparseArray<ProcessRecord> procs = mProcessNames.getMap().get(processName);
- if (procs == null) return null;
- final int procCount = procs.size();
- for (int i = 0; i < procCount; i++) {
- final int procUid = procs.keyAt(i);
- if (UserHandle.isApp(procUid) || !UserHandle.isSameUser(procUid, uid)) {
- // Don't use an app process or different user process for system component.
- continue;
- }
- return procs.valueAt(i);
- }
- }
- ProcessRecord proc = mProcessNames.get(processName, uid);
- if (false && proc != null && !keepIfLarge
- && proc.setProcState >= ActivityManager.PROCESS_STATE_CACHED_EMPTY
- && proc.lastCachedPss >= 4000) {
- // Turn this condition on to cause killing to happen regularly, for testing.
- if (proc.baseProcessTracker != null) {
- proc.baseProcessTracker.reportCachedKill(proc.pkgList.mPkgList, proc.lastCachedPss);
- for (int ipkg = proc.pkgList.size() - 1; ipkg >= 0; ipkg--) {
- ProcessStats.ProcessStateHolder holder = proc.pkgList.valueAt(ipkg);
- StatsLog.write(StatsLog.CACHED_KILL_REPORTED,
- proc.info.uid,
- holder.state.getName(),
- holder.state.getPackage(),
- proc.lastCachedPss, holder.appVersion);
- }
- }
- proc.kill(Long.toString(proc.lastCachedPss) + "k from cached", true);
- } else if (proc != null && !keepIfLarge
- && mLastMemoryLevel > ProcessStats.ADJ_MEM_FACTOR_NORMAL
- && proc.setProcState >= ActivityManager.PROCESS_STATE_CACHED_EMPTY) {
- if (DEBUG_PSS) Slog.d(TAG_PSS, "May not keep " + proc + ": pss=" + proc.lastCachedPss);
- if (proc.lastCachedPss >= mProcessList.getCachedRestoreThresholdKb()) {
- if (proc.baseProcessTracker != null) {
- proc.baseProcessTracker.reportCachedKill(proc.pkgList.mPkgList, proc.lastCachedPss);
- for (int ipkg = proc.pkgList.size() - 1; ipkg >= 0; ipkg--) {
- ProcessStats.ProcessStateHolder holder = proc.pkgList.valueAt(ipkg);
- StatsLog.write(StatsLog.CACHED_KILL_REPORTED,
- proc.info.uid,
- holder.state.getName(),
- holder.state.getPackage(),
- proc.lastCachedPss, holder.appVersion);
- }
- }
- proc.kill(Long.toString(proc.lastCachedPss) + "k from cached", true);
- }
- }
- return proc;
+ final ProcessMap<ProcessRecord> getProcessNames() {
+ return mProcessList.mProcessNames;
}
void notifyPackageUse(String packageName, int reason) {
@@ -3162,7 +2655,7 @@ public class ActivityManagerService extends IActivityManager.Stub
info.packageName = "android";
info.seInfoUser = SELinuxUtil.COMPLETE_STR;
info.targetSdkVersion = Build.VERSION.SDK_INT;
- ProcessRecord proc = startProcessLocked(processName, info /* info */,
+ ProcessRecord proc = mProcessList.startProcessLocked(processName, info /* info */,
false /* knownToBeDead */, 0 /* intentFlags */, "" /* hostingType */,
null /* hostingName */, true /* allowWhileBooting */, true /* isolated */,
uid, true /* keepIfLarge */, abiOverride, entryPoint, entryPointArgs,
@@ -3176,557 +2669,17 @@ public class ActivityManagerService extends IActivityManager.Stub
ApplicationInfo info, boolean knownToBeDead, int intentFlags,
String hostingType, ComponentName hostingName, boolean allowWhileBooting,
boolean isolated, boolean keepIfLarge) {
- return startProcessLocked(processName, info, knownToBeDead, intentFlags, hostingType,
+ return mProcessList.startProcessLocked(processName, info, knownToBeDead, intentFlags,
+ hostingType,
hostingName, allowWhileBooting, isolated, 0 /* isolatedUid */, keepIfLarge,
null /* ABI override */, null /* entryPoint */, null /* entryPointArgs */,
null /* crashHandler */);
}
- @GuardedBy("this")
- final ProcessRecord startProcessLocked(String processName, ApplicationInfo info,
- boolean knownToBeDead, int intentFlags, String hostingType, ComponentName hostingName,
- boolean allowWhileBooting, boolean isolated, int isolatedUid, boolean keepIfLarge,
- String abiOverride, String entryPoint, String[] entryPointArgs, Runnable crashHandler) {
- long startTime = SystemClock.elapsedRealtime();
- ProcessRecord app;
- if (!isolated) {
- app = getProcessRecordLocked(processName, info.uid, keepIfLarge);
- checkTime(startTime, "startProcess: after getProcessRecord");
-
- if ((intentFlags & Intent.FLAG_FROM_BACKGROUND) != 0) {
- // If we are in the background, then check to see if this process
- // is bad. If so, we will just silently fail.
- if (mAppErrors.isBadProcessLocked(info)) {
- if (DEBUG_PROCESSES) Slog.v(TAG, "Bad process: " + info.uid
- + "/" + info.processName);
- return null;
- }
- } else {
- // When the user is explicitly starting a process, then clear its
- // crash count so that we won't make it bad until they see at
- // least one crash dialog again, and make the process good again
- // if it had been bad.
- if (DEBUG_PROCESSES) Slog.v(TAG, "Clearing bad process: " + info.uid
- + "/" + info.processName);
- mAppErrors.resetProcessCrashTimeLocked(info);
- if (mAppErrors.isBadProcessLocked(info)) {
- EventLog.writeEvent(EventLogTags.AM_PROC_GOOD,
- UserHandle.getUserId(info.uid), info.uid,
- info.processName);
- mAppErrors.clearBadProcessLocked(info);
- if (app != null) {
- app.bad = false;
- }
- }
- }
- } else {
- // If this is an isolated process, it can't re-use an existing process.
- app = null;
- }
-
- // We don't have to do anything more if:
- // (1) There is an existing application record; and
- // (2) The caller doesn't think it is dead, OR there is no thread
- // object attached to it so we know it couldn't have crashed; and
- // (3) There is a pid assigned to it, so it is either starting or
- // already running.
- if (DEBUG_PROCESSES) Slog.v(TAG_PROCESSES, "startProcess: name=" + processName
- + " app=" + app + " knownToBeDead=" + knownToBeDead
- + " thread=" + (app != null ? app.thread : null)
- + " pid=" + (app != null ? app.pid : -1));
- if (app != null && app.pid > 0) {
- if ((!knownToBeDead && !app.killed) || app.thread == null) {
- // We already have the app running, or are waiting for it to
- // come up (we have a pid but not yet its thread), so keep it.
- if (DEBUG_PROCESSES) Slog.v(TAG_PROCESSES, "App already running: " + app);
- // If this is a new package in the process, add the package to the list
- app.addPackage(info.packageName, info.versionCode, mProcessStats);
- checkTime(startTime, "startProcess: done, added package to proc");
- return app;
- }
-
- // An application record is attached to a previous process,
- // clean it up now.
- if (DEBUG_PROCESSES || DEBUG_CLEANUP) Slog.v(TAG_PROCESSES, "App died: " + app);
- checkTime(startTime, "startProcess: bad proc running, killing");
- killProcessGroup(app.uid, app.pid);
- handleAppDiedLocked(app, true, true);
- checkTime(startTime, "startProcess: done killing old proc");
- }
-
- String hostingNameStr = hostingName != null
- ? hostingName.flattenToShortString() : null;
-
- if (app == null) {
- checkTime(startTime, "startProcess: creating new process record");
- app = newProcessRecordLocked(info, processName, isolated, isolatedUid);
- if (app == null) {
- Slog.w(TAG, "Failed making new process record for "
- + processName + "/" + info.uid + " isolated=" + isolated);
- return null;
- }
- app.crashHandler = crashHandler;
- app.isolatedEntryPoint = entryPoint;
- app.isolatedEntryPointArgs = entryPointArgs;
- checkTime(startTime, "startProcess: done creating new process record");
- } else {
- // If this is a new package in the process, add the package to the list
- app.addPackage(info.packageName, info.versionCode, mProcessStats);
- checkTime(startTime, "startProcess: added package to existing proc");
- }
-
- // If the system is not ready yet, then hold off on starting this
- // process until it is.
- if (!mProcessesReady
- && !isAllowedWhileBooting(info)
- && !allowWhileBooting) {
- if (!mProcessesOnHold.contains(app)) {
- mProcessesOnHold.add(app);
- }
- if (DEBUG_PROCESSES) Slog.v(TAG_PROCESSES,
- "System not ready, putting on hold: " + app);
- checkTime(startTime, "startProcess: returning with proc on hold");
- return app;
- }
-
- checkTime(startTime, "startProcess: stepping in to startProcess");
- final boolean success = startProcessLocked(app, hostingType, hostingNameStr, abiOverride);
- checkTime(startTime, "startProcess: done starting proc!");
- return success ? app : null;
- }
-
boolean isAllowedWhileBooting(ApplicationInfo ai) {
return (ai.flags&ApplicationInfo.FLAG_PERSISTENT) != 0;
}
- @GuardedBy("this")
- private final void startProcessLocked(ProcessRecord app,
- String hostingType, String hostingNameStr) {
- startProcessLocked(app, hostingType, hostingNameStr, null /* abiOverride */);
- }
-
- @GuardedBy("this")
- private final boolean startProcessLocked(ProcessRecord app,
- String hostingType, String hostingNameStr, String abiOverride) {
- return startProcessLocked(app, hostingType, hostingNameStr,
- false /* disableHiddenApiChecks */, abiOverride);
- }
-
- /**
- * @return {@code true} if process start is successful, false otherwise.
- */
- @GuardedBy("this")
- private final boolean startProcessLocked(ProcessRecord app, String hostingType,
- String hostingNameStr, boolean disableHiddenApiChecks, String abiOverride) {
- if (app.pendingStart) {
- return true;
- }
- long startTime = SystemClock.elapsedRealtime();
- if (app.pid > 0 && app.pid != MY_PID) {
- checkTime(startTime, "startProcess: removing from pids map");
- synchronized (mPidsSelfLocked) {
- mPidsSelfLocked.remove(app.pid);
- mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
- }
- checkTime(startTime, "startProcess: done removing from pids map");
- app.setPid(0);
- }
-
- if (DEBUG_PROCESSES && mProcessesOnHold.contains(app)) Slog.v(TAG_PROCESSES,
- "startProcessLocked removing on hold: " + app);
- mProcessesOnHold.remove(app);
-
- checkTime(startTime, "startProcess: starting to update cpu stats");
- updateCpuStats();
- checkTime(startTime, "startProcess: done updating cpu stats");
-
- try {
- try {
- final int userId = UserHandle.getUserId(app.uid);
- AppGlobals.getPackageManager().checkPackageStartable(app.info.packageName, userId);
- } catch (RemoteException e) {
- throw e.rethrowAsRuntimeException();
- }
-
- int uid = app.uid;
- int[] gids = null;
- int mountExternal = Zygote.MOUNT_EXTERNAL_NONE;
- if (!app.isolated) {
- int[] permGids = null;
- try {
- checkTime(startTime, "startProcess: getting gids from package manager");
- final IPackageManager pm = AppGlobals.getPackageManager();
- permGids = pm.getPackageGids(app.info.packageName,
- MATCH_DEBUG_TRIAGED_MISSING, app.userId);
- StorageManagerInternal storageManagerInternal = LocalServices.getService(
- StorageManagerInternal.class);
- mountExternal = storageManagerInternal.getExternalStorageMountMode(uid,
- app.info.packageName);
- } catch (RemoteException e) {
- throw e.rethrowAsRuntimeException();
- }
-
- /*
- * Add shared application and profile GIDs so applications can share some
- * resources like shared libraries and access user-wide resources
- */
- if (ArrayUtils.isEmpty(permGids)) {
- gids = new int[3];
- } else {
- gids = new int[permGids.length + 3];
- System.arraycopy(permGids, 0, gids, 3, permGids.length);
- }
- gids[0] = UserHandle.getSharedAppGid(UserHandle.getAppId(uid));
- gids[1] = UserHandle.getCacheAppGid(UserHandle.getAppId(uid));
- gids[2] = UserHandle.getUserGid(UserHandle.getUserId(uid));
-
- // Replace any invalid GIDs
- if (gids[0] == UserHandle.ERR_GID) gids[0] = gids[2];
- if (gids[1] == UserHandle.ERR_GID) gids[1] = gids[2];
- }
- checkTime(startTime, "startProcess: building args");
- if (mAtmInternal.isFactoryTestProcess(app.getWindowProcessController())) {
- uid = 0;
- }
- int runtimeFlags = 0;
- if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
- runtimeFlags |= Zygote.DEBUG_ENABLE_JDWP;
- runtimeFlags |= Zygote.DEBUG_JAVA_DEBUGGABLE;
- // Also turn on CheckJNI for debuggable apps. It's quite
- // awkward to turn on otherwise.
- runtimeFlags |= Zygote.DEBUG_ENABLE_CHECKJNI;
- }
- // Run the app in safe mode if its manifest requests so or the
- // system is booted in safe mode.
- if ((app.info.flags & ApplicationInfo.FLAG_VM_SAFE_MODE) != 0 ||
- mSafeMode == true) {
- runtimeFlags |= Zygote.DEBUG_ENABLE_SAFEMODE;
- }
- if ("1".equals(SystemProperties.get("debug.checkjni"))) {
- runtimeFlags |= Zygote.DEBUG_ENABLE_CHECKJNI;
- }
- String genDebugInfoProperty = SystemProperties.get("debug.generate-debug-info");
- if ("1".equals(genDebugInfoProperty) || "true".equals(genDebugInfoProperty)) {
- runtimeFlags |= Zygote.DEBUG_GENERATE_DEBUG_INFO;
- }
- String genMiniDebugInfoProperty = SystemProperties.get("dalvik.vm.minidebuginfo");
- if ("1".equals(genMiniDebugInfoProperty) || "true".equals(genMiniDebugInfoProperty)) {
- runtimeFlags |= Zygote.DEBUG_GENERATE_MINI_DEBUG_INFO;
- }
- if ("1".equals(SystemProperties.get("debug.jni.logging"))) {
- runtimeFlags |= Zygote.DEBUG_ENABLE_JNI_LOGGING;
- }
- if ("1".equals(SystemProperties.get("debug.assert"))) {
- runtimeFlags |= Zygote.DEBUG_ENABLE_ASSERT;
- }
- if (mNativeDebuggingApp != null && mNativeDebuggingApp.equals(app.processName)) {
- // Enable all debug flags required by the native debugger.
- runtimeFlags |= Zygote.DEBUG_ALWAYS_JIT; // Don't interpret anything
- runtimeFlags |= Zygote.DEBUG_GENERATE_DEBUG_INFO; // Generate debug info
- runtimeFlags |= Zygote.DEBUG_NATIVE_DEBUGGABLE; // Disbale optimizations
- mNativeDebuggingApp = null;
- }
-
- if (app.info.isPrivilegedApp() &&
- DexManager.isPackageSelectedToRunOob(app.pkgList.mPkgList.keySet())) {
- runtimeFlags |= Zygote.ONLY_USE_SYSTEM_OAT_FILES;
- }
-
- if (!disableHiddenApiChecks && !mHiddenApiBlacklist.isDisabled()) {
- app.info.maybeUpdateHiddenApiEnforcementPolicy(
- mHiddenApiBlacklist.getPolicyForPrePApps(),
- mHiddenApiBlacklist.getPolicyForPApps());
- @HiddenApiEnforcementPolicy int policy =
- app.info.getHiddenApiEnforcementPolicy();
- int policyBits = (policy << Zygote.API_ENFORCEMENT_POLICY_SHIFT);
- if ((policyBits & Zygote.API_ENFORCEMENT_POLICY_MASK) != policyBits) {
- throw new IllegalStateException("Invalid API policy: " + policy);
- }
- runtimeFlags |= policyBits;
- }
-
- String invokeWith = null;
- if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
- // Debuggable apps may include a wrapper script with their library directory.
- String wrapperFileName = app.info.nativeLibraryDir + "/wrap.sh";
- StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
- try {
- if (new File(wrapperFileName).exists()) {
- invokeWith = "/system/bin/logwrapper " + wrapperFileName;
- }
- } finally {
- StrictMode.setThreadPolicy(oldPolicy);
- }
- }
-
- String requiredAbi = (abiOverride != null) ? abiOverride : app.info.primaryCpuAbi;
- if (requiredAbi == null) {
- requiredAbi = Build.SUPPORTED_ABIS[0];
- }
-
- String instructionSet = null;
- if (app.info.primaryCpuAbi != null) {
- instructionSet = VMRuntime.getInstructionSet(app.info.primaryCpuAbi);
- }
-
- app.gids = gids;
- app.setRequiredAbi(requiredAbi);
- app.instructionSet = instructionSet;
-
- // the per-user SELinux context must be set
- if (TextUtils.isEmpty(app.info.seInfoUser)) {
- Slog.wtf(TAG, "SELinux tag not defined",
- new IllegalStateException("SELinux tag not defined for "
- + app.info.packageName + " (uid " + app.uid + ")"));
- }
- final String seInfo = app.info.seInfo
- + (TextUtils.isEmpty(app.info.seInfoUser) ? "" : app.info.seInfoUser);
- // Start the process. It will either succeed and return a result containing
- // the PID of the new process, or else throw a RuntimeException.
- final String entryPoint = "android.app.ActivityThread";
-
- return startProcessLocked(hostingType, hostingNameStr, entryPoint, app, uid, gids,
- runtimeFlags, mountExternal, seInfo, requiredAbi, instructionSet, invokeWith,
- startTime);
- } catch (RuntimeException e) {
- Slog.e(TAG, "Failure starting process " + app.processName, e);
-
- // Something went very wrong while trying to start this process; one
- // common case is when the package is frozen due to an active
- // upgrade. To recover, clean up any active bookkeeping related to
- // starting this process. (We already invoked this method once when
- // the package was initially frozen through KILL_APPLICATION_MSG, so
- // it doesn't hurt to use it again.)
- forceStopPackageLocked(app.info.packageName, UserHandle.getAppId(app.uid), false,
- false, true, false, false, app.userId, "start failure");
- return false;
- }
- }
-
- @GuardedBy("this")
- private boolean startProcessLocked(String hostingType, String hostingNameStr, String entryPoint,
- ProcessRecord app, int uid, int[] gids, int runtimeFlags, int mountExternal,
- String seInfo, String requiredAbi, String instructionSet, String invokeWith,
- long startTime) {
- app.pendingStart = true;
- app.killedByAm = false;
- app.removed = false;
- app.killed = false;
- final long startSeq = app.startSeq = ++mProcStartSeqCounter;
- app.setStartParams(uid, hostingType, hostingNameStr, seInfo, startTime);
- if (mConstants.FLAG_PROCESS_START_ASYNC) {
- if (DEBUG_PROCESSES) Slog.i(TAG_PROCESSES,
- "Posting procStart msg for " + app.toShortString());
- mProcStartHandler.post(() -> {
- try {
- synchronized (ActivityManagerService.this) {
- final String reason = isProcStartValidLocked(app, startSeq);
- if (reason != null) {
- Slog.w(TAG_PROCESSES, app + " not valid anymore,"
- + " don't start process, " + reason);
- app.pendingStart = false;
- return;
- }
- app.setUsingWrapper(invokeWith != null
- || SystemProperties.get("wrap." + app.processName) != null);
- mPendingStarts.put(startSeq, app);
- }
- final ProcessStartResult startResult = startProcess(app.hostingType, entryPoint,
- app, app.startUid, gids, runtimeFlags, mountExternal, app.seInfo,
- requiredAbi, instructionSet, invokeWith, app.startTime);
- synchronized (ActivityManagerService.this) {
- handleProcessStartedLocked(app, startResult, startSeq);
- }
- } catch (RuntimeException e) {
- synchronized (ActivityManagerService.this) {
- Slog.e(TAG, "Failure starting process " + app.processName, e);
- mPendingStarts.remove(startSeq);
- app.pendingStart = false;
- forceStopPackageLocked(app.info.packageName, UserHandle.getAppId(app.uid),
- false, false, true, false, false, app.userId, "start failure");
- }
- }
- });
- return true;
- } else {
- try {
- final ProcessStartResult startResult = startProcess(hostingType, entryPoint, app,
- uid, gids, runtimeFlags, mountExternal, seInfo, requiredAbi, instructionSet,
- invokeWith, startTime);
- handleProcessStartedLocked(app, startResult.pid, startResult.usingWrapper,
- startSeq, false);
- } catch (RuntimeException e) {
- Slog.e(TAG, "Failure starting process " + app.processName, e);
- app.pendingStart = false;
- forceStopPackageLocked(app.info.packageName, UserHandle.getAppId(app.uid),
- false, false, true, false, false, app.userId, "start failure");
- }
- return app.pid > 0;
- }
- }
-
- private ProcessStartResult startProcess(String hostingType, String entryPoint,
- ProcessRecord app, int uid, int[] gids, int runtimeFlags, int mountExternal,
- String seInfo, String requiredAbi, String instructionSet, String invokeWith,
- long startTime) {
- try {
- final String[] packageNames = mContext.getPackageManager().getPackagesForUid(uid);
- final String[] visibleVolIds = LocalServices.getService(StorageManagerInternal.class)
- .getVisibleVolumesForUser(UserHandle.getUserId(uid));
- Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Start proc: " +
- app.processName);
- checkTime(startTime, "startProcess: asking zygote to start proc");
- final ProcessStartResult startResult;
- if (hostingType.equals("webview_service")) {
- startResult = startWebView(entryPoint,
- app.processName, uid, uid, gids, runtimeFlags, mountExternal,
- app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
- app.info.dataDir, null, app.info.packageName,
- packageNames, visibleVolIds,
- new String[] {PROC_START_SEQ_IDENT + app.startSeq});
- }
- else {
- startResult = Process.start(entryPoint,
- app.processName, uid, uid, gids, runtimeFlags, mountExternal,
- app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
- app.info.dataDir, invokeWith, app.info.packageName,
- packageNames, visibleVolIds,
- new String[] {PROC_START_SEQ_IDENT + app.startSeq});
- }
-
- if (mPerfServiceStartHint == null) {
- mPerfServiceStartHint = new BoostFramework();
- }
- if (mPerfServiceStartHint != null) {
- mPerfServiceStartHint.perfHint(BoostFramework.VENDOR_HINT_FIRST_LAUNCH_BOOST, app.processName, -1, BoostFramework.Launch.TYPE_SERVICE_START);
- }
-
- checkTime(startTime, "startProcess: returned from zygote!");
- return startResult;
- } finally {
- Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
- }
- }
-
- @GuardedBy("this")
- private String isProcStartValidLocked(ProcessRecord app, long expectedStartSeq) {
- StringBuilder sb = null;
- if (app.killedByAm) {
- if (sb == null) sb = new StringBuilder();
- sb.append("killedByAm=true;");
- }
- if (mProcessNames.get(app.processName, app.uid) != app) {
- if (sb == null) sb = new StringBuilder();
- sb.append("No entry in mProcessNames;");
- }
- if (!app.pendingStart) {
- if (sb == null) sb = new StringBuilder();
- sb.append("pendingStart=false;");
- }
- if (app.startSeq > expectedStartSeq) {
- if (sb == null) sb = new StringBuilder();
- sb.append("seq=" + app.startSeq + ",expected=" + expectedStartSeq + ";");
- }
- return sb == null ? null : sb.toString();
- }
-
- @GuardedBy("this")
- private boolean handleProcessStartedLocked(ProcessRecord pending,
- ProcessStartResult startResult, long expectedStartSeq) {
- // Indicates that this process start has been taken care of.
- if (mPendingStarts.get(expectedStartSeq) == null) {
- if (pending.pid == startResult.pid) {
- pending.setUsingWrapper(startResult.usingWrapper);
- // TODO: Update already existing clients of usingWrapper
- }
- return false;
- }
- return handleProcessStartedLocked(pending, startResult.pid, startResult.usingWrapper,
- expectedStartSeq, false);
- }
-
- @GuardedBy("this")
- private boolean handleProcessStartedLocked(ProcessRecord app, int pid, boolean usingWrapper,
- long expectedStartSeq, boolean procAttached) {
- mPendingStarts.remove(expectedStartSeq);
- final String reason = isProcStartValidLocked(app, expectedStartSeq);
- if (reason != null) {
- Slog.w(TAG_PROCESSES, app + " start not valid, killing pid=" + pid
- + ", " + reason);
- app.pendingStart = false;
- Process.killProcessQuiet(pid);
- Process.killProcessGroup(app.uid, app.pid);
- return false;
- }
- mBatteryStatsService.noteProcessStart(app.processName, app.info.uid);
- checkTime(app.startTime, "startProcess: done updating battery stats");
-
- EventLog.writeEvent(EventLogTags.AM_PROC_START,
- UserHandle.getUserId(app.startUid), pid, app.startUid,
- app.processName, app.hostingType,
- app.hostingNameStr != null ? app.hostingNameStr : "");
-
- try {
- AppGlobals.getPackageManager().logAppProcessStartIfNeeded(app.processName, app.uid,
- app.seInfo, app.info.sourceDir, pid);
- } catch (RemoteException ex) {
- // Ignore
- }
-
- if (app.isPersistent()) {
- Watchdog.getInstance().processStarted(app.processName, pid);
- }
-
- checkTime(app.startTime, "startProcess: building log message");
- StringBuilder buf = mStringBuilder;
- buf.setLength(0);
- buf.append("Start proc ");
- buf.append(pid);
- buf.append(':');
- buf.append(app.processName);
- buf.append('/');
- UserHandle.formatUid(buf, app.startUid);
- if (app.isolatedEntryPoint != null) {
- buf.append(" [");
- buf.append(app.isolatedEntryPoint);
- buf.append("]");
- }
- buf.append(" for ");
- buf.append(app.hostingType);
- if (app.hostingNameStr != null) {
- buf.append(" ");
- buf.append(app.hostingNameStr);
- }
- reportUidInfoMessageLocked(TAG, buf.toString(), app.startUid);
- app.setPid(pid);
- app.setUsingWrapper(usingWrapper);
- app.pendingStart = false;
- checkTime(app.startTime, "startProcess: starting to update pids map");
- ProcessRecord oldApp;
- synchronized (mPidsSelfLocked) {
- oldApp = mPidsSelfLocked.get(pid);
- }
- // If there is already an app occupying that pid that hasn't been cleaned up
- if (oldApp != null && !app.isolated) {
- // Clean up anything relating to this pid first
- Slog.w(TAG, "Reusing pid " + pid
- + " while app is still mapped to it");
- cleanUpApplicationRecordLocked(oldApp, false, false, -1,
- true /*replacingPid*/);
- }
- synchronized (mPidsSelfLocked) {
- this.mPidsSelfLocked.put(pid, app);
- if (!procAttached) {
- Message msg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
- msg.obj = app;
- mHandler.sendMessageDelayed(msg, usingWrapper
- ? PROC_START_TIMEOUT_WITH_WRAPPER : PROC_START_TIMEOUT);
- }
- }
- checkTime(app.startTime, "startProcess: done updating pids map");
- return true;
- }
-
void updateUsageStats(ComponentName activity, int uid, int userId, boolean resumed) {
if (DEBUG_SWITCH) Slog.d(TAG_SWITCH,
"updateUsageStats: comp=" + activity + "res=" + resumed);
@@ -3756,14 +2709,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);
}
@@ -3798,8 +2743,8 @@ public class ActivityManagerService extends IActivityManager.Stub
int procState = ActivityManager.PROCESS_STATE_NONEXISTENT;
synchronized (this) {
- for (int i=mLruProcesses.size()-1; i>=0; i--) {
- final ProcessRecord proc = mLruProcesses.get(i);
+ for (int i=mProcessList.mLruProcesses.size()-1; i>=0; i--) {
+ final ProcessRecord proc = mProcessList.mLruProcesses.get(i);
if (procState > proc.setProcState) {
if (proc.pkgList.containsKey(packageName) ||
(proc.pkgDeps != null && proc.pkgDeps.contains(packageName))) {
@@ -3827,7 +2772,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");
}
@@ -4093,9 +3038,35 @@ public class ActivityManagerService extends IActivityManager.Stub
public final int startActivityAsUser(IApplicationThread caller, String callingPackage,
Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, int userId) {
- return mActivityTaskManager.startActivityAsUser(caller, callingPackage, intent,
- resolvedType, resultTo, resultWho, requestCode, startFlags, profilerInfo, bOptions,
- userId);
+ synchronized (this) {
+ /**
+ * Flags like {@link android.app.ActivityManager#START_FLAG_DEBUG} maybe be set on this
+ * call when called/invoked from the shell command. To avoid deadlock, we go ahead and
+ * acquire the AMS lock now since ATMS will need to synchronously call back into AMS
+ * later to modify process settings due to the flags.
+ * TODO(b/80414790): Investigate a better way of untangling this.
+ */
+ return mActivityTaskManager.startActivityAsUser(caller, callingPackage, intent,
+ resolvedType, resultTo, resultWho, requestCode, startFlags, profilerInfo,
+ bOptions, userId);
+ }
+ }
+
+ WaitResult startActivityAndWait(IApplicationThread caller, String callingPackage,
+ Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
+ int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, int userId) {
+ synchronized (this) {
+ /**
+ * Flags like {@link android.app.ActivityManager#START_FLAG_DEBUG} maybe be set on this
+ * call when called/invoked from the shell command. To avoid deadlock, we go ahead and
+ * acquire the AMS lock now since ATMS will need to synchronously call back into AMS
+ * later to modify process settings due to the flags.
+ * TODO(b/80414790): Investigate a better way of untangling this.
+ */
+ return mActivityTaskManager.startActivityAndWait(caller, callingPackage, intent,
+ resolvedType, resultTo, resultWho, requestCode, startFlags, profilerInfo,
+ bOptions, userId);
+ }
}
@Override
@@ -4209,7 +3180,7 @@ public class ActivityManagerService extends IActivityManager.Stub
* to the process.
*/
@GuardedBy("this")
- private final void handleAppDiedLocked(ProcessRecord app,
+ final void handleAppDiedLocked(ProcessRecord app,
boolean restarting, boolean allowRestart) {
int pid = app.pid;
boolean kept = cleanUpApplicationRecordLocked(app, restarting, allowRestart, -1,
@@ -4225,45 +3196,13 @@ public class ActivityManagerService extends IActivityManager.Stub
clearProfilerLocked();
}
- // Remove this application's activities from active lists.
- boolean hasVisibleActivities = mStackSupervisor.handleAppDiedLocked(app.getWindowProcessController());
-
- app.clearRecentTasks();
- app.clearActivities();
-
- if (app.getActiveInstrumentation() != null) {
+ mAtmInternal.handleAppDied(app.getWindowProcessController(), restarting, () -> {
Slog.w(TAG, "Crash of app " + app.processName
- + " running instrumentation " + app.getActiveInstrumentation().mClass);
+ + " running instrumentation " + app.getActiveInstrumentation().mClass);
Bundle info = new Bundle();
info.putString("shortMsg", "Process crashed.");
finishInstrumentationLocked(app, Activity.RESULT_CANCELED, info);
- }
-
- mWindowManager.deferSurfaceLayout();
- try {
- if (!restarting && hasVisibleActivities
- && !mStackSupervisor.resumeFocusedStacksTopActivitiesLocked()) {
- // If there was nothing to resume, and we are not already restarting this process, but
- // there is a visible activity that is hosted by the process... then make sure all
- // visible activities are running, taking care of restarting this process.
- mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
- }
- } finally {
- mWindowManager.continueSurfaceLayout();
- }
-
- }
-
- private final int getLRURecordIndexForAppLocked(IApplicationThread thread) {
- final IBinder threadBinder = thread.asBinder();
- // Find the application record.
- for (int i=mLruProcesses.size()-1; i>=0; i--) {
- final ProcessRecord rec = mLruProcesses.get(i);
- if (rec.thread != null && rec.thread.asBinder() == threadBinder) {
- return i;
- }
- }
- return -1;
+ });
}
ProcessRecord getRecordForAppLocked(IApplicationThread thread) {
@@ -4271,15 +3210,14 @@ public class ActivityManagerService extends IActivityManager.Stub
return null;
}
- int appIndex = getLRURecordIndexForAppLocked(thread);
- if (appIndex >= 0) {
- return mLruProcesses.get(appIndex);
- }
+ ProcessRecord record = mProcessList.getLRURecordForAppLocked(thread);
+ if (record != null) return record;
// Validation: if it isn't in the LRU list, it shouldn't exist, but let's
// double-check that.
final IBinder threadBinder = thread.asBinder();
- final ArrayMap<String, SparseArray<ProcessRecord>> pmap = mProcessNames.getMap();
+ final ArrayMap<String, SparseArray<ProcessRecord>> pmap =
+ mProcessList.mProcessNames.getMap();
for (int i = pmap.size()-1; i >= 0; i--) {
final SparseArray<ProcessRecord> procs = pmap.valueAt(i);
for (int j = procs.size()-1; j >= 0; j--) {
@@ -4299,17 +3237,7 @@ public class ActivityManagerService extends IActivityManager.Stub
// If there are no longer any background processes running,
// and the app that died was not running instrumentation,
// then tell everyone we are now low on memory.
- boolean haveBg = false;
- for (int i=mLruProcesses.size()-1; i>=0; i--) {
- ProcessRecord rec = mLruProcesses.get(i);
- if (rec.thread != null
- && rec.setProcState >= PROCESS_STATE_CACHED_ACTIVITY) {
- haveBg = true;
- break;
- }
- }
-
- if (!haveBg) {
+ if (!mProcessList.haveBackgroundProcessLocked()) {
boolean doReport = "1".equals(SystemProperties.get(SYSTEM_DEBUGGABLE, "0"));
if (doReport) {
long now = SystemClock.uptimeMillis();
@@ -4320,11 +3248,12 @@ public class ActivityManagerService extends IActivityManager.Stub
}
}
final ArrayList<ProcessMemInfo> memInfos
- = doReport ? new ArrayList<ProcessMemInfo>(mLruProcesses.size()) : null;
- EventLog.writeEvent(EventLogTags.AM_LOW_MEMORY, mLruProcesses.size());
+ = doReport ? new ArrayList<ProcessMemInfo>(mProcessList.getLruSizeLocked())
+ : null;
+ EventLog.writeEvent(EventLogTags.AM_LOW_MEMORY, mProcessList.getLruSizeLocked());
long now = SystemClock.uptimeMillis();
- for (int i=mLruProcesses.size()-1; i>=0; i--) {
- ProcessRecord rec = mLruProcesses.get(i);
+ for (int i = mProcessList.mLruProcesses.size() - 1; i >= 0; i--) {
+ ProcessRecord rec = mProcessList.mLruProcesses.get(i);
if (rec == dyingProc || rec.thread == null) {
continue;
}
@@ -4381,7 +3310,7 @@ public class ActivityManagerService extends IActivityManager.Stub
if (!fromBinderDied) {
killProcessQuiet(pid);
}
- killProcessGroup(app.uid, pid);
+ ProcessList.killProcessGroup(app.uid, pid);
app.killed = true;
}
@@ -4808,7 +3737,7 @@ public class ActivityManagerService extends IActivityManager.Stub
return;
}
synchronized (this) {
- killPackageProcessesLocked(packageName, appId, targetUserId,
+ mProcessList.killPackageProcessesLocked(packageName, appId, targetUserId,
ProcessList.SERVICE_ADJ, false, true, true, false, "kill background");
}
}
@@ -4831,30 +3760,7 @@ public class ActivityManagerService extends IActivityManager.Stub
final long callingId = Binder.clearCallingIdentity();
try {
synchronized (this) {
- final ArrayList<ProcessRecord> procs = new ArrayList<>();
- final int NP = mProcessNames.getMap().size();
- for (int ip = 0; ip < NP; ip++) {
- final SparseArray<ProcessRecord> apps = mProcessNames.getMap().valueAt(ip);
- final int NA = apps.size();
- for (int ia = 0; ia < NA; ia++) {
- final ProcessRecord app = apps.valueAt(ia);
- if (app.isPersistent()) {
- // We don't kill persistent processes.
- continue;
- }
- if (app.removed) {
- procs.add(app);
- } else if (app.setAdj >= ProcessList.CACHED_APP_MIN_ADJ) {
- app.removed = true;
- procs.add(app);
- }
- }
- }
-
- final int N = procs.size();
- for (int i = 0; i < N; i++) {
- removeProcessLocked(procs.get(i), false, true, "kill all background");
- }
+ mProcessList.killAllBackgroundProcessesLocked();
mAllowLowerMemLevel = true;
@@ -4888,27 +3794,7 @@ public class ActivityManagerService extends IActivityManager.Stub
final long callingId = Binder.clearCallingIdentity();
try {
synchronized (this) {
- final ArrayList<ProcessRecord> procs = new ArrayList<>();
- final int NP = mProcessNames.getMap().size();
- for (int ip = 0; ip < NP; ip++) {
- final SparseArray<ProcessRecord> apps = mProcessNames.getMap().valueAt(ip);
- final int NA = apps.size();
- for (int ia = 0; ia < NA; ia++) {
- final ProcessRecord app = apps.valueAt(ia);
- if (app.removed) {
- procs.add(app);
- } else if ((minTargetSdk < 0 || app.info.targetSdkVersion < minTargetSdk)
- && (maxProcState < 0 || app.setProcState > maxProcState)) {
- app.removed = true;
- procs.add(app);
- }
- }
- }
-
- final int N = procs.size();
- for (int i = 0; i < N; i++) {
- removeProcessLocked(procs.get(i), false, true, "kill all background except");
- }
+ mProcessList.killAllBackgroundProcessesExceptLocked(minTargetSdk, maxProcState);
}
} finally {
Binder.restoreCallingIdentity(callingId);
@@ -5025,48 +3911,7 @@ public class ActivityManagerService extends IActivityManager.Stub
@Override
public void closeSystemDialogs(String reason) {
- enforceNotIsolatedCaller("closeSystemDialogs");
-
- final int pid = Binder.getCallingPid();
- final int uid = Binder.getCallingUid();
- final long origId = Binder.clearCallingIdentity();
- try {
- synchronized (this) {
- // Only allow this from foreground processes, so that background
- // applications can't abuse it to prevent system UI from being shown.
- if (uid >= FIRST_APPLICATION_UID) {
- ProcessRecord proc;
- synchronized (mPidsSelfLocked) {
- proc = mPidsSelfLocked.get(pid);
- }
- if (proc.curRawAdj > ProcessList.PERCEPTIBLE_APP_ADJ) {
- Slog.w(TAG, "Ignoring closeSystemDialogs " + reason
- + " from background process " + proc);
- return;
- }
- }
- closeSystemDialogsLocked(reason);
- }
- } finally {
- Binder.restoreCallingIdentity(origId);
- }
- }
-
- @GuardedBy("this")
- void closeSystemDialogsLocked(String reason) {
- Intent intent = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
- intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
- | Intent.FLAG_RECEIVER_FOREGROUND);
- if (reason != null) {
- intent.putExtra("reason", reason);
- }
- mWindowManager.closeSystemDialogs(reason);
-
- mStackSupervisor.closeSystemDialogsLocked();
-
- broadcastIntentLocked(null, null, intent, null, null, 0, null, null, null,
- OP_NONE, null, false, false,
- -1, SYSTEM_UID, UserHandle.USER_ALL);
+ mAtmInternal.closeSystemDialogs(reason);
}
@Override
@@ -5247,81 +4092,6 @@ public class ActivityManagerService extends IActivityManager.Stub
null, false, false, MY_PID, SYSTEM_UID, UserHandle.getUserId(uid));
}
-
- @GuardedBy("this")
- private final boolean killPackageProcessesLocked(String packageName, int appId,
- int userId, int minOomAdj, boolean callerWillRestart, boolean allowRestart,
- boolean doit, boolean evenPersistent, String reason) {
- ArrayList<ProcessRecord> procs = new ArrayList<>();
-
- // Remove all processes this package may have touched: all with the
- // same UID (except for the system or root user), and all whose name
- // matches the package name.
- final int NP = mProcessNames.getMap().size();
- for (int ip=0; ip<NP; ip++) {
- SparseArray<ProcessRecord> apps = mProcessNames.getMap().valueAt(ip);
- final int NA = apps.size();
- for (int ia=0; ia<NA; ia++) {
- ProcessRecord app = apps.valueAt(ia);
- if (app.isPersistent() && !evenPersistent) {
- // we don't kill persistent processes
- continue;
- }
- if (app.removed) {
- if (doit) {
- procs.add(app);
- }
- continue;
- }
-
- // Skip process if it doesn't meet our oom adj requirement.
- if (app.setAdj < minOomAdj) {
- continue;
- }
-
- // If no package is specified, we call all processes under the
- // give user id.
- if (packageName == null) {
- if (userId != UserHandle.USER_ALL && app.userId != userId) {
- continue;
- }
- if (appId >= 0 && UserHandle.getAppId(app.uid) != appId) {
- continue;
- }
- // Package has been specified, we want to hit all processes
- // that match it. We need to qualify this by the processes
- // that are running under the specified app and user ID.
- } else {
- final boolean isDep = app.pkgDeps != null
- && app.pkgDeps.contains(packageName);
- if (!isDep && UserHandle.getAppId(app.uid) != appId) {
- continue;
- }
- if (userId != UserHandle.USER_ALL && app.userId != userId) {
- continue;
- }
- if (!app.pkgList.containsKey(packageName) && !isDep) {
- continue;
- }
- }
-
- // Process has passed all conditions, kill it!
- if (!doit) {
- return true;
- }
- app.removed = true;
- procs.add(app);
- }
- }
-
- int N = procs.size();
- for (int i=0; i<N; i++) {
- removeProcessLocked(procs.get(i), callerWillRestart, allowRestart, reason);
- }
- updateOomAdjLocked();
- return N > 0;
- }
-
private void cleanupDisabledPackageComponentsLocked(
String packageName, int userId, boolean killProcess, String[] changedClasses) {
@@ -5381,15 +4151,8 @@ public class ActivityManagerService extends IActivityManager.Stub
return;
}
- // Clean-up disabled activities.
- if (mStackSupervisor.finishDisabledPackageActivitiesLocked(
- packageName, disabledClasses, true, false, userId) && mBooted) {
- mStackSupervisor.resumeFocusedStacksTopActivitiesLocked();
- mStackSupervisor.scheduleIdleLocked();
- }
-
- // Clean-up disabled tasks
- mActivityTaskManager.getRecentTasks().cleanupDisabledPackageTasksLocked(packageName, disabledClasses, userId);
+ mAtmInternal.cleanupDisabledPackageComponents(
+ packageName, disabledClasses, userId, mBooted);
// Clean-up disabled services.
mServices.bringDownDisabledPackageServicesLocked(
@@ -5453,19 +4216,12 @@ public class ActivityManagerService extends IActivityManager.Stub
mAppErrors.resetProcessCrashTimeLocked(packageName == null, appId, userId);
}
- boolean didSomething = killPackageProcessesLocked(packageName, appId, userId,
+ boolean didSomething = mProcessList.killPackageProcessesLocked(packageName, appId, userId,
ProcessList.INVALID_ADJ, callerWillRestart, true, doit, evenPersistent,
packageName == null ? ("stop user " + userId) : ("stop " + packageName));
- didSomething |= mActivityTaskManager.getActivityStartController().clearPendingActivityLaunches(packageName);
-
- if (mStackSupervisor.finishDisabledPackageActivitiesLocked(
- packageName, null, doit, evenPersistent, userId)) {
- if (!doit) {
- return true;
- }
- didSomething = true;
- }
+ didSomething |=
+ mAtmInternal.onForceStopPackage(packageName, doit, evenPersistent, userId);
if (mServices.bringDownDisabledPackageServicesLocked(
packageName, null, userId, evenPersistent, true, doit)) {
@@ -5515,136 +4271,17 @@ public class ActivityManagerService extends IActivityManager.Stub
}
}
if (mBooted) {
- mStackSupervisor.resumeFocusedStacksTopActivitiesLocked();
- mStackSupervisor.scheduleIdleLocked();
+ mAtmInternal.resumeTopActivities(true /* scheduleIdle */);
}
}
return didSomething;
}
- private final ProcessRecord removeProcessNameLocked(final String name, final int uid) {
- return removeProcessNameLocked(name, uid, null);
- }
-
- private final ProcessRecord removeProcessNameLocked(final String name, final int uid,
- final ProcessRecord expecting) {
- ProcessRecord old = mProcessNames.get(name, uid);
- // Only actually remove when the currently recorded value matches the
- // record that we expected; if it doesn't match then we raced with a
- // newly created process and we don't want to destroy the new one.
- if ((expecting == null) || (old == expecting)) {
- mProcessNames.remove(name, uid);
- }
- if (old != null && old.uidRecord != null) {
- old.uidRecord.numProcs--;
- if (old.uidRecord.numProcs == 0) {
- // No more processes using this uid, tell clients it is gone.
- if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS,
- "No more processes in " + old.uidRecord);
- enqueueUidChangeLocked(old.uidRecord, -1, UidRecord.CHANGE_GONE);
- EventLogTags.writeAmUidStopped(uid);
- mActiveUids.remove(uid);
- noteUidProcessState(uid, ActivityManager.PROCESS_STATE_NONEXISTENT);
- }
- old.uidRecord = null;
- }
- mIsolatedProcesses.remove(uid);
- return old;
- }
-
- private final void addProcessNameLocked(ProcessRecord proc) {
- // We shouldn't already have a process under this name, but just in case we
- // need to clean up whatever may be there now.
- ProcessRecord old = removeProcessNameLocked(proc.processName, proc.uid);
- if (old == proc && proc.isPersistent()) {
- // We are re-adding a persistent process. Whatevs! Just leave it there.
- Slog.w(TAG, "Re-adding persistent process " + proc);
- } else if (old != null) {
- Slog.wtf(TAG, "Already have existing proc " + old + " when adding " + proc);
- }
- UidRecord uidRec = mActiveUids.get(proc.uid);
- if (uidRec == null) {
- uidRec = new UidRecord(proc.uid);
- // This is the first appearance of the uid, report it now!
- if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS,
- "Creating new process uid: " + uidRec);
- if (Arrays.binarySearch(mDeviceIdleTempWhitelist, UserHandle.getAppId(proc.uid)) >= 0
- || mPendingTempWhitelist.indexOfKey(proc.uid) >= 0) {
- uidRec.setWhitelist = uidRec.curWhitelist = true;
- }
- uidRec.updateHasInternetPermission();
- mActiveUids.put(proc.uid, uidRec);
- EventLogTags.writeAmUidRunning(uidRec.uid);
- noteUidProcessState(uidRec.uid, uidRec.curProcState);
- }
- proc.uidRecord = uidRec;
-
- // Reset render thread tid if it was already set, so new process can set it again.
- proc.renderThreadTid = 0;
- uidRec.numProcs++;
- mProcessNames.put(proc.processName, proc.uid, proc);
- if (proc.isolated) {
- mIsolatedProcesses.put(proc.uid, proc);
- }
- }
-
- @GuardedBy("this")
- boolean removeProcessLocked(ProcessRecord app,
- boolean callerWillRestart, boolean allowRestart, String reason) {
- final String name = app.processName;
- final int uid = app.uid;
- if (DEBUG_PROCESSES) Slog.d(TAG_PROCESSES,
- "Force removing proc " + app.toShortString() + " (" + name + "/" + uid + ")");
-
- ProcessRecord old = mProcessNames.get(name, uid);
- if (old != app) {
- // This process is no longer active, so nothing to do.
- Slog.w(TAG, "Ignoring remove of inactive process: " + app);
- return false;
- }
- removeProcessNameLocked(name, uid);
- mAtmInternal.clearHeavyWeightProcessIfEquals(app.getWindowProcessController());
-
- boolean needRestart = false;
- if ((app.pid > 0 && app.pid != MY_PID) || (app.pid == 0 && app.pendingStart)) {
- int pid = app.pid;
- if (pid > 0) {
- synchronized (mPidsSelfLocked) {
- mPidsSelfLocked.remove(pid);
- mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
- }
- mBatteryStatsService.noteProcessFinish(app.processName, app.info.uid);
- if (app.isolated) {
- mBatteryStatsService.removeIsolatedUid(app.uid, app.info.uid);
- getPackageManagerInternalLocked().removeIsolatedUid(app.uid);
- }
- }
- boolean willRestart = false;
- if (app.isPersistent() && !app.isolated) {
- if (!callerWillRestart) {
- willRestart = true;
- } else {
- needRestart = true;
- }
- }
- app.kill(reason, true);
- handleAppDiedLocked(app, willRestart, allowRestart);
- if (willRestart) {
- removeLruProcessLocked(app);
- addAppLocked(app.info, null, false, null /* ABI override */);
- }
- } else {
- mRemovedProcesses.add(app);
- }
-
- return needRestart;
- }
-
@GuardedBy("this")
private final void processContentProviderPublishTimedOutLocked(ProcessRecord app) {
cleanupAppInLaunchingProvidersLocked(app, true);
- removeProcessLocked(app, false, true, "timeout publishing content providers");
+ mProcessList.removeProcessLocked(app, false, true, "timeout publishing content providers");
}
private final void processStartTimedOutLocked(ProcessRecord app) {
@@ -5662,7 +4299,7 @@ public class ActivityManagerService extends IActivityManager.Stub
Slog.w(TAG, "Process " + app + " failed to attach");
EventLog.writeEvent(EventLogTags.AM_PROCESS_START_TIMEOUT, app.userId,
pid, app.uid, app.processName);
- removeProcessNameLocked(app.processName, app.uid);
+ mProcessList.removeProcessNameLocked(app.processName, app.uid);
mAtmInternal.clearHeavyWeightProcessIfEquals(app.getWindowProcessController());
mBatteryStatsService.noteProcessFinish(app.processName, app.info.uid);
// Take care of any launching providers waiting for this process.
@@ -5718,9 +4355,10 @@ public class ActivityManagerService extends IActivityManager.Stub
// It's possible that process called attachApplication before we got a chance to
// update the internal state.
if (app == null && startSeq > 0) {
- final ProcessRecord pending = mPendingStarts.get(startSeq);
+ final ProcessRecord pending = mProcessList.mPendingStarts.get(startSeq);
if (pending != null && pending.startUid == callingUid
- && handleProcessStartedLocked(pending, pid, pending.isUsingWrapper(),
+ && mProcessList.handleProcessStartedLocked(pending, pid, pending
+ .isUsingWrapper(),
startSeq, true)) {
app = pending;
}
@@ -5762,7 +4400,7 @@ public class ActivityManagerService extends IActivityManager.Stub
app.deathRecipient = adr;
} catch (RemoteException e) {
app.resetPackageList(mProcessStats);
- startProcessLocked(app, "link fail", processName);
+ mProcessList.startProcessLocked(app, "link fail", processName);
return false;
}
@@ -5940,7 +4578,7 @@ public class ActivityManagerService extends IActivityManager.Stub
}
checkTime(startTime, "attachApplicationLocked: immediately before bindApplication");
- mStackSupervisor.getActivityMetricsLogger().notifyBindApplication(app);
+ mAtmInternal.preBindApplication(app.getWindowProcessController());
final ActiveInstrumentation instr2 = app.getActiveInstrumentation();
if (app.isolatedEntryPoint != null) {
// This is an isolated process which should just call an entry point instead of
@@ -5973,7 +4611,7 @@ public class ActivityManagerService extends IActivityManager.Stub
profilerInfo = null;
}
checkTime(startTime, "attachApplicationLocked: immediately after bindApplication");
- updateLruProcessLocked(app, false, null);
+ mProcessList.updateLruProcessLocked(app, false, null);
checkTime(startTime, "attachApplicationLocked: after updateLruProcessLocked");
app.lastRequestedGc = app.lastLowMemory = SystemClock.uptimeMillis();
} catch (Exception e) {
@@ -5984,7 +4622,7 @@ public class ActivityManagerService extends IActivityManager.Stub
app.resetPackageList(mProcessStats);
app.unlinkDeathRecipient();
- startProcessLocked(app, "bind fail", processName);
+ mProcessList.startProcessLocked(app, "bind fail", processName);
return false;
}
@@ -6000,9 +4638,7 @@ public class ActivityManagerService extends IActivityManager.Stub
// See if the top visible activity is waiting to run in this process...
if (normalMode) {
try {
- if (mStackSupervisor.attachApplicationLocked(app)) {
- didSomething = true;
- }
+ didSomething = mAtmInternal.attachApplication(app.getWindowProcessController());
} catch (Exception e) {
Slog.wtf(TAG, "Exception thrown launching activities in " + app, e);
badApp = true;
@@ -6196,7 +4832,7 @@ public class ActivityManagerService extends IActivityManager.Stub
for (int ip=0; ip<NP; ip++) {
if (DEBUG_PROCESSES) Slog.v(TAG_PROCESSES, "Starting process on hold: "
+ procs.get(ip));
- startProcessLocked(procs.get(ip), "on-hold", null);
+ mProcessList.startProcessLocked(procs.get(ip), "on-hold", null);
}
}
if (mFactoryTest == FactoryTest.FACTORY_TEST_LOW_LEVEL) {
@@ -6697,7 +5333,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;
}
@@ -6981,7 +5617,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;
@@ -7018,11 +5654,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);
@@ -7158,19 +5789,7 @@ public class ActivityManagerService extends IActivityManager.Stub
@Override
public void getMemoryInfo(ActivityManager.MemoryInfo outInfo) {
- final long homeAppMem = mProcessList.getMemLevel(ProcessList.HOME_APP_ADJ);
- final long cachedAppMem = mProcessList.getMemLevel(ProcessList.CACHED_APP_MIN_ADJ);
- outInfo.availMem = getFreeMemory();
- outInfo.totalMem = getTotalMemory();
- outInfo.threshold = homeAppMem;
- outInfo.lowMemory = outInfo.availMem < (homeAppMem + ((cachedAppMem-homeAppMem)/2));
- outInfo.hiddenAppThreshold = cachedAppMem;
- outInfo.secondaryServerThreshold = mProcessList.getMemLevel(
- ProcessList.SERVICE_ADJ);
- outInfo.visibleAppThreshold = mProcessList.getMemLevel(
- ProcessList.VISIBLE_APP_ADJ);
- outInfo.foregroundAppThreshold = mProcessList.getMemLevel(
- ProcessList.FOREGROUND_APP_ADJ);
+ mProcessList.getMemoryInfo(outInfo);
}
// =========================================================
@@ -7562,7 +6181,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;
}
@@ -7606,7 +6225,7 @@ public class ActivityManagerService extends IActivityManager.Stub
return false;
}
- private void checkTime(long startTime, String where) {
+ void checkTime(long startTime, String where) {
long now = SystemClock.uptimeMillis();
if ((now-startTime) > 50) {
// If we are taking more than 50ms, log about it.
@@ -7648,6 +6267,7 @@ public class ActivityManagerService extends IActivityManager.Stub
ContentProviderRecord cpr;
ContentProviderConnection conn = null;
ProviderInfo cpi = null;
+ boolean providerRunning = false;
synchronized(this) {
long startTime = SystemClock.uptimeMillis();
@@ -7687,8 +6307,6 @@ public class ActivityManagerService extends IActivityManager.Stub
}
}
- boolean providerRunning = false;
-
if (cpr != null && cpr.proc != null) {
providerRunning = !cpr.proc.killed;
@@ -7766,7 +6384,7 @@ public class ActivityManagerService extends IActivityManager.Stub
// back up on the LRU list. This is good because
// content providers are often expensive to start.
checkTime(startTime, "getContentProviderImpl: before updateLruProcess");
- updateLruProcessLocked(cpr.proc, false, null);
+ mProcessList.updateLruProcessLocked(cpr.proc, false, null);
checkTime(startTime, "getContentProviderImpl: after updateLruProcess");
}
}
@@ -8013,6 +6631,7 @@ public class ActivityManagerService extends IActivityManager.Stub
}
// Wait for the provider to be published...
+ final long timeout = SystemClock.uptimeMillis() + CONTENT_PROVIDER_WAIT_TIMEOUT;
synchronized (cpr) {
while (cpr.provider == null) {
if (cpr.launchingApp == null) {
@@ -8027,13 +6646,22 @@ public class ActivityManagerService extends IActivityManager.Stub
return null;
}
try {
+ final long wait = Math.max(0L, timeout - SystemClock.uptimeMillis());
if (DEBUG_MU) Slog.v(TAG_MU,
"Waiting to start provider " + cpr
- + " launchingApp=" + cpr.launchingApp);
+ + " launchingApp=" + cpr.launchingApp + " for " + wait + " ms");
if (conn != null) {
conn.waiting = true;
}
- cpr.wait();
+ cpr.wait(wait);
+ if (cpr.provider == null) {
+ Slog.wtf(TAG, "Timeout waiting for provider "
+ + cpi.applicationInfo.packageName + "/"
+ + cpi.applicationInfo.uid + " for provider "
+ + name
+ + " providerRunning=" + providerRunning);
+ return null;
+ }
} catch (InterruptedException ex) {
} finally {
if (conn != null) {
@@ -8393,8 +7021,8 @@ public class ActivityManagerService extends IActivityManager.Stub
mHandler.post(new Runnable() {
@Override
public void run() {
- mAppErrors.appNotResponding(host, null, null, false,
- "ContentProvider not responding");
+ host.appNotResponding(
+ null, null, null, null, false, "ContentProvider not responding");
}
});
}
@@ -8402,7 +7030,7 @@ public class ActivityManagerService extends IActivityManager.Stub
public final void installSystemProviders() {
List<ProviderInfo> providers;
synchronized (this) {
- ProcessRecord app = mProcessNames.get("system", SYSTEM_UID);
+ ProcessRecord app = mProcessList.mProcessNames.get("system", SYSTEM_UID);
providers = generateApplicationProvidersLocked(app);
if (providers != null) {
for (int i=providers.size()-1; i>=0; i--) {
@@ -8464,9 +7092,10 @@ public class ActivityManagerService extends IActivityManager.Stub
final int matchFlags = GET_PROVIDERS | MATCH_DIRECT_BOOT_UNAWARE;
synchronized (this) {
- final int NP = mProcessNames.getMap().size();
+ final int NP = mProcessList.mProcessNames.getMap().size();
for (int ip = 0; ip < NP; ip++) {
- final SparseArray<ProcessRecord> apps = mProcessNames.getMap().valueAt(ip);
+ final SparseArray<ProcessRecord> apps = mProcessList.mProcessNames.getMap().valueAt
+ (ip);
final int NA = apps.size();
for (int ia = 0; ia < NA; ia++) {
final ProcessRecord app = apps.valueAt(ia);
@@ -8572,67 +7201,6 @@ public class ActivityManagerService extends IActivityManager.Stub
// GLOBAL MANAGEMENT
// =========================================================
- @GuardedBy("this")
- final ProcessRecord newProcessRecordLocked(ApplicationInfo info, String customProcess,
- boolean isolated, int isolatedUid) {
- String proc = customProcess != null ? customProcess : info.processName;
- final int userId = UserHandle.getUserId(info.uid);
- int uid = info.uid;
- if (isolated) {
- if (isolatedUid == 0) {
- int stepsLeft = LAST_ISOLATED_UID - FIRST_ISOLATED_UID + 1;
- while (true) {
- if (mNextIsolatedProcessUid < FIRST_ISOLATED_UID
- || mNextIsolatedProcessUid > LAST_ISOLATED_UID) {
- mNextIsolatedProcessUid = FIRST_ISOLATED_UID;
- }
- uid = UserHandle.getUid(userId, mNextIsolatedProcessUid);
- mNextIsolatedProcessUid++;
- if (mIsolatedProcesses.indexOfKey(uid) < 0) {
- // No process for this uid, use it.
- break;
- }
- stepsLeft--;
- if (stepsLeft <= 0) {
- return null;
- }
- }
- } else {
- // Special case for startIsolatedProcess (internal only), where
- // the uid of the isolated process is specified by the caller.
- uid = isolatedUid;
- }
- getPackageManagerInternalLocked().addIsolatedUid(uid, info.uid);
-
- // Register the isolated UID with this application so BatteryStats knows to
- // attribute resource usage to the application.
- //
- // NOTE: This is done here before addProcessNameLocked, which will tell BatteryStats
- // about the process state of the isolated UID *before* it is registered with the
- // owning application.
- mBatteryStatsService.addIsolatedUid(uid, info.uid);
- StatsLog.write(StatsLog.ISOLATED_UID_CHANGED, info.uid, uid,
- StatsLog.ISOLATED_UID_CHANGED__EVENT__CREATED);
- }
- final ProcessRecord r = new ProcessRecord(this, info, proc, uid, getGlobalConfiguration());
- if (!mBooted && !mBooting
- && userId == UserHandle.USER_SYSTEM
- && (info.flags & PERSISTENT_MASK) == PERSISTENT_MASK) {
- // The system process is initialized to SCHED_GROUP_DEFAULT in init.rc.
- r.setCurrentSchedulingGroup(ProcessList.SCHED_GROUP_DEFAULT);
- r.setSchedGroup = ProcessList.SCHED_GROUP_DEFAULT;
- r.setPersistent(true);
- r.maxAdj = ProcessList.PERSISTENT_PROC_ADJ;
- }
- if (isolated && isolatedUid != 0) {
- // Special case for startIsolatedProcess (internal only) - assume the process
- // is required by the system server to prevent it being killed.
- r.maxAdj = ProcessList.PERSISTENT_SERVICE_ADJ;
- }
- addProcessNameLocked(r);
- return r;
- }
-
private boolean uidOnBackgroundWhitelist(final int uid) {
final int appId = UserHandle.getAppId(uid);
final int[] whitelist = mBackgroundAppIdWhitelist;
@@ -8693,6 +7261,7 @@ public class ActivityManagerService extends IActivityManager.Stub
abiOverride);
}
+ // TODO: Move to ProcessList?
@GuardedBy("this")
final ProcessRecord addAppLocked(ApplicationInfo info, String customProcess, boolean isolated,
boolean disableHiddenApiChecks, String abiOverride) {
@@ -8705,8 +7274,8 @@ public class ActivityManagerService extends IActivityManager.Stub
}
if (app == null) {
- app = newProcessRecordLocked(info, customProcess, isolated, 0);
- updateLruProcessLocked(app, false, null);
+ app = mProcessList.newProcessRecordLocked(info, customProcess, isolated, 0);
+ mProcessList.updateLruProcessLocked(app, false, null);
updateOomAdjLocked();
}
@@ -8726,7 +7295,7 @@ public class ActivityManagerService extends IActivityManager.Stub
}
if (app.thread == null && mPersistentStartingProcesses.indexOf(app) < 0) {
mPersistentStartingProcesses.add(app);
- startProcessLocked(app, "added application",
+ mProcessList.startProcessLocked(app, "added application",
customProcess != null ? customProcess : app.processName, disableHiddenApiChecks,
abiOverride);
}
@@ -8843,51 +7412,12 @@ public class ActivityManagerService extends IActivityManager.Stub
@Override
public void notifyLockedProfile(@UserIdInt int userId) {
- try {
- if (!AppGlobals.getPackageManager().isUidPrivileged(Binder.getCallingUid())) {
- throw new SecurityException("Only privileged app can call notifyLockedProfile");
- }
- } catch (RemoteException ex) {
- throw new SecurityException("Fail to check is caller a privileged app", ex);
- }
-
- synchronized (this) {
- final long ident = Binder.clearCallingIdentity();
- try {
- if (mUserController.shouldConfirmCredentials(userId)) {
- if (mActivityTaskManager.mKeyguardController.isKeyguardLocked()) {
- // Showing launcher to avoid user entering credential twice.
- final int currentUserId = mUserController.getCurrentUserId();
- mAtmInternal.startHomeActivity(currentUserId, "notifyLockedProfile");
- }
- mStackSupervisor.lockAllProfileTasks(userId);
- }
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- }
+ mAtmInternal.notifyLockedProfile(userId, mUserController.getCurrentUserId());
}
@Override
public void startConfirmDeviceCredentialIntent(Intent intent, Bundle options) {
- enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "startConfirmDeviceCredentialIntent");
- synchronized (this) {
- final long ident = Binder.clearCallingIdentity();
- try {
- intent.addFlags(FLAG_ACTIVITY_NEW_TASK |
- FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS |
- FLAG_ACTIVITY_TASK_ON_HOME);
- ActivityOptions activityOptions = options != null
- ? new ActivityOptions(options)
- : ActivityOptions.makeBasic();
- activityOptions.setLaunchTaskId(
- mStackSupervisor.getDefaultDisplayHomeActivity().getTask().taskId);
- mContext.startActivityAsUser(intent, activityOptions.toBundle(),
- UserHandle.CURRENT);
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- }
+ mAtmInternal.startConfirmDeviceCredentialIntent(intent, options);
}
@Override
@@ -9397,11 +7927,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;
}
}
@@ -9629,7 +8159,7 @@ public class ActivityManagerService extends IActivityManager.Stub
synchronized (this) {
final long identity = Binder.clearCallingIdentity();
try {
- killPackageProcessesLocked(null, appId, userId,
+ mProcessList.killPackageProcessesLocked(null, appId, userId,
ProcessList.PERSISTENT_PROC_ADJ, false, true, true, true,
reason != null ? reason : "kill uid");
} finally {
@@ -9773,14 +8303,20 @@ public class ActivityManagerService extends IActivityManager.Stub
// If at least 1/3 of our time since the last idle period has been spent
// with RAM low, then we want to kill processes.
boolean doKilling = lowRamSinceLastIdle > (timeSinceLastIdle/3);
-
- for (int i = mLruProcesses.size() - 1 ; i >= 0 ; i--) {
- ProcessRecord proc = mLruProcesses.get(i);
+ // If the processes' memory has increased by more than 1% of the total memory,
+ // or 10 MB, whichever is greater, then the processes' are eligible to be killed.
+ final long totalMemoryInKb = getTotalMemory() / 1000;
+ final long memoryGrowthThreshold =
+ Math.max(totalMemoryInKb / 100, MINIMUM_MEMORY_GROWTH_THRESHOLD);
+
+ for (int i = mProcessList.mLruProcesses.size() - 1 ; i >= 0 ; i--) {
+ ProcessRecord proc = mProcessList.mLruProcesses.get(i);
if (proc.notCachedSinceIdle) {
if (proc.setProcState >= ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE
&& proc.setProcState <= ActivityManager.PROCESS_STATE_SERVICE) {
if (doKilling && proc.initialIdlePss != 0
- && proc.lastPss > ((proc.initialIdlePss*3)/2)) {
+ && proc.lastPss > ((proc.initialIdlePss * 3) / 2)
+ && proc.lastPss > (proc.initialIdlePss + memoryGrowthThreshold)) {
sb = new StringBuilder(128);
sb.append("Kill");
sb.append(proc.processName);
@@ -9904,7 +8440,7 @@ public class ActivityManagerService extends IActivityManager.Stub
for (int i=procsToKill.size()-1; i>=0; i--) {
ProcessRecord proc = procsToKill.get(i);
Slog.i(TAG, "Removing system update proc: " + proc);
- removeProcessLocked(proc, true, false, "system update done");
+ mProcessList.removeProcessLocked(proc, true, false, "system update done");
}
}
@@ -9995,7 +8531,7 @@ public class ActivityManagerService extends IActivityManager.Stub
} finally {
Binder.restoreCallingIdentity(ident);
}
- mStackSupervisor.resumeFocusedStacksTopActivitiesLocked();
+ mAtmInternal.resumeTopActivities(false /* scheduleIdle */);
mUserController.sendUserSwitchBroadcasts(-1, currentUserId);
BinderInternal.nSetBinderProxyCountWatermarks(6000,5500);
@@ -10094,16 +8630,17 @@ public class ActivityManagerService extends IActivityManager.Stub
: StatsLog.APP_CRASH_OCCURRED__FOREGROUND_STATE__UNKNOWN
);
- final int relaunchReason = r == null ? ActivityRecord.RELAUNCH_REASON_NONE
+ final int relaunchReason = r == null ? RELAUNCH_REASON_NONE
: r.getWindowProcessController().computeRelaunchReason();
- final String relaunchReasonString = ActivityRecord.relaunchReasonToString(relaunchReason);
+ final String relaunchReasonString = relaunchReasonToString(relaunchReason);
if (crashInfo.crashTag == null) {
crashInfo.crashTag = relaunchReasonString;
} else {
crashInfo.crashTag = crashInfo.crashTag + " " + relaunchReasonString;
}
- addErrorToDropBox(eventType, r, processName, null, null, null, null, null, crashInfo);
+ addErrorToDropBox(
+ eventType, r, processName, null, null, null, null, null, null, crashInfo);
mAppErrors.crashApplication(r, crashInfo);
}
@@ -10275,7 +8812,7 @@ public class ActivityManagerService extends IActivityManager.Stub
StatsLog.write(StatsLog.WTF_OCCURRED, callingUid, tag, processName,
callingPid);
- addErrorToDropBox("wtf", r, processName, null, null, tag, null, null, crashInfo);
+ addErrorToDropBox("wtf", r, processName, null, null, null, tag, null, null, crashInfo);
return r;
}
@@ -10290,22 +8827,7 @@ public class ActivityManagerService extends IActivityManager.Stub
}
synchronized (this) {
- final int NP = mProcessNames.getMap().size();
- for (int ip=0; ip<NP; ip++) {
- SparseArray<ProcessRecord> apps = mProcessNames.getMap().valueAt(ip);
- final int NA = apps.size();
- for (int ia=0; ia<NA; ia++) {
- ProcessRecord p = apps.valueAt(ia);
- if (p.thread != null && p.thread.asBinder() == app) {
- return p;
- }
- }
- }
-
- Slog.w(TAG, "Can't find mystery application for " + reason
- + " from pid=" + Binder.getCallingPid()
- + " uid=" + Binder.getCallingUid() + ": " + app);
- return null;
+ return mProcessList.findAppProcessLocked(app, reason);
}
}
@@ -10331,6 +8853,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");
@@ -10373,17 +8896,18 @@ public class ActivityManagerService extends IActivityManager.Stub
* Write a description of an error (crash, WTF, ANR) to the drop box.
* @param eventType to include in the drop box tag ("crash", "wtf", etc.)
* @param process which caused the error, null means the system server
- * @param activity which triggered the error, null if unknown
- * @param parent activity related to the error, null if unknown
+ * @param activityShortComponentName which triggered the error, null if unknown
+ * @param parentShortComponentName activity related to the error, null if unknown
+ * @param parentProcess parent process
* @param subject line related to the error, null if absent
* @param report in long form describing the error, null if absent
* @param dataFile text file to include in the report, null if none
* @param crashInfo giving an application stack trace, null if absent
*/
public void addErrorToDropBox(String eventType,
- ProcessRecord process, String processName, ActivityRecord activity,
- ActivityRecord parent, String subject,
- final String report, final File dataFile,
+ ProcessRecord process, String processName, String activityShortComponentName,
+ String parentShortComponentName, ProcessRecord parentProcess,
+ String subject, final String report, final File dataFile,
final ApplicationErrorReport.CrashInfo crashInfo) {
// NOTE -- this must never acquire the ActivityManagerService lock,
// otherwise the watchdog may be prevented from resetting the system.
@@ -10413,14 +8937,16 @@ public class ActivityManagerService extends IActivityManager.Stub
.append(process.isInterestingToUserLocked() ? "Yes" : "No")
.append("\n");
}
- if (activity != null) {
- sb.append("Activity: ").append(activity.shortComponentName).append("\n");
+ if (activityShortComponentName != null) {
+ sb.append("Activity: ").append(activityShortComponentName).append("\n");
}
- if (parent != null && parent.app != null && parent.app.getPid() != process.pid) {
- sb.append("Parent-Process: ").append(parent.app.mName).append("\n");
- }
- if (parent != null && parent != activity) {
- sb.append("Parent-Activity: ").append(parent.shortComponentName).append("\n");
+ if (parentShortComponentName != null) {
+ if (parentProcess != null && parentProcess.pid != process.pid) {
+ sb.append("Parent-Process: ").append(parentProcess.processName).append("\n");
+ }
+ if (!parentShortComponentName.equals(activityShortComponentName)) {
+ sb.append("Parent-Activity: ").append(parentShortComponentName).append("\n");
+ }
}
if (subject != null) {
sb.append("Subject: ").append(subject).append("\n");
@@ -10517,8 +9043,8 @@ public class ActivityManagerService extends IActivityManager.Stub
synchronized (this) {
// iterate across all processes
- for (int i=mLruProcesses.size()-1; i>=0; i--) {
- ProcessRecord app = mLruProcesses.get(i);
+ for (int i=mProcessList.mLruProcesses.size()-1; i>=0; i--) {
+ ProcessRecord app = mProcessList.mLruProcesses.get(i);
if (!allUsers && app.userId != userId) {
continue;
}
@@ -10551,44 +9077,6 @@ public class ActivityManagerService extends IActivityManager.Stub
return errList;
}
- static int procStateToImportance(int procState, int memAdj,
- ActivityManager.RunningAppProcessInfo currApp,
- int clientTargetSdk) {
- int imp = ActivityManager.RunningAppProcessInfo.procStateToImportanceForTargetSdk(
- procState, clientTargetSdk);
- if (imp == ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND) {
- currApp.lru = memAdj;
- } else {
- currApp.lru = 0;
- }
- return imp;
- }
-
- @GuardedBy("this")
- private void fillInProcMemInfoLocked(ProcessRecord app,
- ActivityManager.RunningAppProcessInfo outInfo,
- int clientTargetSdk) {
- outInfo.pid = app.pid;
- outInfo.uid = app.info.uid;
- if (mAtmInternal.isHeavyWeightProcess(app.getWindowProcessController())) {
- outInfo.flags |= ActivityManager.RunningAppProcessInfo.FLAG_CANT_SAVE_STATE;
- }
- if (app.isPersistent()) {
- outInfo.flags |= ActivityManager.RunningAppProcessInfo.FLAG_PERSISTENT;
- }
- if (app.hasActivities()) {
- outInfo.flags |= ActivityManager.RunningAppProcessInfo.FLAG_HAS_ACTIVITIES;
- }
- outInfo.lastTrimLevel = app.trimMemoryLevel;
- int adj = app.curAdj;
- int procState = app.curProcState;
- outInfo.importance = procStateToImportance(procState, adj, outInfo, clientTargetSdk);
- outInfo.importanceReasonCode = app.adjTypeCode;
- outInfo.processState = app.curProcState;
- outInfo.isFocused = (app == getTopAppLocked());
- outInfo.lastActivityTime = app.lastActivityTime;
- }
-
@Override
public List<ActivityManager.RunningAppProcessInfo> getRunningAppProcesses() {
enforceNotIsolatedCaller("getRunningAppProcesses");
@@ -10596,8 +9084,6 @@ public class ActivityManagerService extends IActivityManager.Stub
final int callingUid = Binder.getCallingUid();
final int clientTargetSdk = mPackageManagerInt.getUidTargetSdkVersion(callingUid);
- // Lazy instantiation of list
- List<ActivityManager.RunningAppProcessInfo> runList = null;
final boolean allUsers = ActivityManager.checkUidPermission(INTERACT_ACROSS_USERS_FULL,
callingUid) == PackageManager.PERMISSION_GRANTED;
final int userId = UserHandle.getUserId(callingUid);
@@ -10606,44 +9092,9 @@ public class ActivityManagerService extends IActivityManager.Stub
synchronized (this) {
// Iterate across all processes
- for (int i = mLruProcesses.size() - 1; i >= 0; i--) {
- ProcessRecord app = mLruProcesses.get(i);
- if ((!allUsers && app.userId != userId)
- || (!allUids && app.uid != callingUid)) {
- continue;
- }
- if ((app.thread != null) && (!app.isCrashing() && !app.isNotResponding())) {
- // Generate process state info for running application
- ActivityManager.RunningAppProcessInfo currApp =
- new ActivityManager.RunningAppProcessInfo(app.processName,
- app.pid, app.getPackageList());
- fillInProcMemInfoLocked(app, currApp, clientTargetSdk);
- if (app.adjSource instanceof ProcessRecord) {
- currApp.importanceReasonPid = ((ProcessRecord)app.adjSource).pid;
- currApp.importanceReasonImportance =
- ActivityManager.RunningAppProcessInfo.procStateToImportance(
- app.adjSourceProcState);
- } else if (app.adjSource instanceof ActivityServiceConnectionsHolder) {
- ActivityServiceConnectionsHolder r =
- (ActivityServiceConnectionsHolder) app.adjSource;
- final int pid = r.getActivityPid();
- if (pid != -1) {
- currApp.importanceReasonPid = pid;
- }
- }
- if (app.adjTarget instanceof ComponentName) {
- currApp.importanceReasonComponent = (ComponentName)app.adjTarget;
- }
- //Slog.v(TAG, "Proc " + app.processName + ": imp=" + currApp.importance
- // + " lru=" + currApp.lru);
- if (runList == null) {
- runList = new ArrayList<>();
- }
- runList.add(currApp);
- }
- }
+ return mProcessList.getRunningAppProcessesLocked(allUsers, userId, allUids,
+ callingUid, clientTargetSdk);
}
- return runList;
}
@Override
@@ -10690,7 +9141,7 @@ public class ActivityManagerService extends IActivityManager.Stub
proc = mPidsSelfLocked.get(Binder.getCallingPid());
}
if (proc != null) {
- fillInProcMemInfoLocked(proc, outState, clientTargetSdk);
+ mProcessList.fillInProcMemInfoLocked(proc, outState, clientTargetSdk);
}
}
}
@@ -10775,24 +9226,26 @@ public class ActivityManagerService extends IActivityManager.Stub
if (dumpAll) {
pw.println("-------------------------------------------------------------------------------");
}
- if (mActivityTaskManager.getRecentTasks() != null) {
- mActivityTaskManager.getRecentTasks().dump(pw, dumpAll, dumpPackage);
- }
+ mAtmInternal.dump(
+ DUMP_RECENTS_CMD, fd, pw, args, opti, dumpAll, dumpClient, dumpPackage);
pw.println();
if (dumpAll) {
pw.println("-------------------------------------------------------------------------------");
}
- dumpLastANRLocked(pw);
+ mAtmInternal.dump(
+ DUMP_LASTANR_CMD, fd, pw, args, opti, dumpAll, dumpClient, dumpPackage);
pw.println();
if (dumpAll) {
pw.println("-------------------------------------------------------------------------------");
}
- dumpActivityStarterLocked(pw, dumpPackage);
+ mAtmInternal.dump(
+ DUMP_STARTER_CMD, fd, pw, args, opti, dumpAll, dumpClient, dumpPackage);
pw.println();
if (dumpAll) {
pw.println("-------------------------------------------------------------------------------");
}
- dumpActivityContainersLocked(pw);
+ mAtmInternal.dump(
+ DUMP_CONTAINERS_CMD, fd, pw, args, opti, dumpAll, dumpClient, dumpPackage);
// Activities section is dumped as part of the Critical priority dump. Exclude the
// section if priority is Normal.
if (!dumpNormalPriority) {
@@ -10800,7 +9253,8 @@ public class ActivityManagerService extends IActivityManager.Stub
if (dumpAll) {
pw.println("-------------------------------------------------------------------------------");
}
- dumpActivitiesLocked(fd, pw, args, opti, dumpAll, dumpClient, dumpPackage);
+ mAtmInternal.dump(
+ DUMP_ACTIVITIES_CMD, fd, pw, args, opti, dumpAll, dumpClient, dumpPackage);
}
if (mAssociations.size() > 0) {
pw.println();
@@ -10889,9 +9343,7 @@ public class ActivityManagerService extends IActivityManager.Stub
if ("activities".equals(cmd) || "a".equals(cmd)) {
// output proto is ActivityManagerServiceDumpActivitiesProto
- synchronized (this) {
- writeActivitiesToProtoLocked(proto);
- }
+ mAtmInternal.writeActivitiesToProto(proto);
} else if ("broadcasts".equals(cmd) || "b".equals(cmd)) {
// output proto is ActivityManagerServiceDumpBroadcastsProto
synchronized (this) {
@@ -10930,7 +9382,7 @@ public class ActivityManagerService extends IActivityManager.Stub
// default option, dump everything, output is ActivityManagerServiceProto
synchronized (this) {
long activityToken = proto.start(ActivityManagerServiceProto.ACTIVITIES);
- writeActivitiesToProtoLocked(proto);
+ mAtmInternal.writeActivitiesToProto(proto);
proto.end(activityToken);
long broadcastToken = proto.start(ActivityManagerServiceProto.BROADCASTS);
@@ -10957,32 +9409,12 @@ public class ActivityManagerService extends IActivityManager.Stub
if (opti < args.length) {
String cmd = args[opti];
opti++;
- if ("activities".equals(cmd) || "a".equals(cmd)) {
- synchronized (this) {
- dumpActivitiesLocked(fd, pw, args, opti, true, dumpClient, dumpPackage);
- }
- } else if ("lastanr".equals(cmd)) {
- synchronized (this) {
- dumpLastANRLocked(pw);
- }
- } else if ("lastanr-traces".equals(cmd)) {
- synchronized (this) {
- dumpLastANRTracesLocked(pw);
- }
- } else if ("starter".equals(cmd)) {
- synchronized (this) {
- dumpActivityStarterLocked(pw, dumpPackage);
- }
- } else if ("containers".equals(cmd)) {
- synchronized (this) {
- dumpActivityContainersLocked(pw);
- }
- } else if ("recents".equals(cmd) || "r".equals(cmd)) {
- synchronized (this) {
- if (mActivityTaskManager.getRecentTasks() != null) {
- mActivityTaskManager.getRecentTasks().dump(pw, true /* dumpAll */, dumpPackage);
- }
- }
+ if (DUMP_ACTIVITIES_CMD.equals(cmd) || DUMP_ACTIVITIES_SHORT_CMD.equals(cmd)
+ || DUMP_LASTANR_CMD.equals(cmd) || DUMP_LASTANR_TRACES_CMD.equals(cmd)
+ || DUMP_STARTER_CMD.equals(cmd) || DUMP_CONTAINERS_CMD.equals(cmd)
+ || DUMP_RECENTS_CMD.equals(cmd) || DUMP_RECENTS_SHORT_CMD.equals(cmd)) {
+ mAtmInternal.dump(
+ cmd, fd, pw, args, opti, true /* dumpAll */, dumpClient, dumpPackage);
} else if ("binder-proxies".equals(cmd)) {
if (opti >= args.length) {
dumpBinderProxies(pw);
@@ -11118,8 +9550,8 @@ public class ActivityManagerService extends IActivityManager.Stub
LockGuard.dump(fd, pw, args);
} else {
// Dumping a single activity?
- if (!dumpActivity(fd, pw, cmd, args, opti, dumpAll, dumpVisibleStacksOnly,
- dumpFocusedStackOnly)) {
+ if (!mAtmInternal.dumpActivity(fd, pw, cmd, args, opti, dumpAll,
+ dumpVisibleStacksOnly, dumpFocusedStackOnly)) {
ActivityManagerShellCommand shell = new ActivityManagerShellCommand(this, true);
int res = shell.exec(this, null, fd, null, args, null,
new ResultReceiver(null));
@@ -11156,96 +9588,6 @@ public class ActivityManagerService extends IActivityManager.Stub
Binder.restoreCallingIdentity(origId);
}
- private void writeActivitiesToProtoLocked(ProtoOutputStream proto) {
- // The output proto of "activity --proto activities" is ActivityManagerServiceDumpActivitiesProto
- mStackSupervisor.writeToProto(proto, ActivityManagerServiceDumpActivitiesProto.ACTIVITY_STACK_SUPERVISOR);
- }
-
- private void dumpLastANRLocked(PrintWriter pw) {
- pw.println("ACTIVITY MANAGER LAST ANR (dumpsys activity lastanr)");
- if (mLastANRState == null) {
- pw.println(" <no ANR has occurred since boot>");
- } else {
- pw.println(mLastANRState);
- }
- }
-
- private void dumpLastANRTracesLocked(PrintWriter pw) {
- pw.println("ACTIVITY MANAGER LAST ANR TRACES (dumpsys activity lastanr-traces)");
-
- final File[] files = new File(ANR_TRACE_DIR).listFiles();
- if (ArrayUtils.isEmpty(files)) {
- pw.println(" <no ANR has occurred since boot>");
- return;
- }
- // Find the latest file.
- File latest = null;
- for (File f : files) {
- if ((latest == null) || (latest.lastModified() < f.lastModified())) {
- latest = f;
- }
- }
- pw.print("File: ");
- pw.print(latest.getName());
- pw.println();
- try (BufferedReader in = new BufferedReader(new FileReader(latest))) {
- String line;
- while ((line = in.readLine()) != null) {
- pw.println(line);
- }
- } catch (IOException e) {
- pw.print("Unable to read: ");
- pw.print(e);
- pw.println();
- }
- }
-
- private void dumpActivityContainersLocked(PrintWriter pw) {
- pw.println("ACTIVITY MANAGER STARTER (dumpsys activity containers)");
- mStackSupervisor.dumpChildrenNames(pw, " ");
- pw.println(" ");
- }
-
- private void dumpActivityStarterLocked(PrintWriter pw, String dumpPackage) {
- pw.println("ACTIVITY MANAGER STARTER (dumpsys activity starter)");
- mActivityTaskManager.getActivityStartController().dump(pw, "", dumpPackage);
- }
-
- void dumpActivitiesLocked(FileDescriptor fd, PrintWriter pw, String[] args,
- int opti, boolean dumpAll, boolean dumpClient, String dumpPackage) {
- dumpActivitiesLocked(fd, pw, args, opti, dumpAll, dumpClient, dumpPackage,
- "ACTIVITY MANAGER ACTIVITIES (dumpsys activity activities)");
- }
-
- void dumpActivitiesLocked(FileDescriptor fd, PrintWriter pw, String[] args,
- int opti, boolean dumpAll, boolean dumpClient, String dumpPackage, String header) {
- pw.println(header);
-
- boolean printedAnything = mStackSupervisor.dumpActivitiesLocked(fd, pw, dumpAll, dumpClient,
- dumpPackage);
- boolean needSep = printedAnything;
-
- boolean printed = ActivityStackSupervisor.printThisActivity(pw,
- mStackSupervisor.getTopResumedActivity(), dumpPackage, needSep,
- " ResumedActivity: ");
- if (printed) {
- printedAnything = true;
- needSep = false;
- }
-
- if (dumpPackage == null) {
- if (needSep) {
- pw.println();
- }
- printedAnything = true;
- mStackSupervisor.dump(pw, " ");
- }
-
- if (!printedAnything) {
- pw.println(" (nothing)");
- }
- }
-
void dumpAssociationsLocked(FileDescriptor fd, PrintWriter pw, String[] args,
int opti, boolean dumpAll, boolean dumpClient, String dumpPackage) {
pw.println("ACTIVITY MANAGER ASSOCIATIONS (dumpsys activity associations)");
@@ -11416,6 +9758,7 @@ public class ActivityManagerService extends IActivityManager.Stub
"Counts of Binder Proxies held by SYSTEM");
}
+ // TODO: Move to ProcessList?
@GuardedBy("this")
void dumpProcessesLocked(FileDescriptor fd, PrintWriter pw, String[] args,
int opti, boolean dumpAll, String dumpPackage, int dumpAppId) {
@@ -11425,9 +9768,9 @@ public class ActivityManagerService extends IActivityManager.Stub
pw.println("ACTIVITY MANAGER RUNNING PROCESSES (dumpsys activity processes)");
if (dumpAll) {
- final int NP = mProcessNames.getMap().size();
+ final int NP = mProcessList.mProcessNames.getMap().size();
for (int ip=0; ip<NP; ip++) {
- SparseArray<ProcessRecord> procs = mProcessNames.getMap().valueAt(ip);
+ SparseArray<ProcessRecord> procs = mProcessList.mProcessNames.getMap().valueAt(ip);
final int NA = procs.size();
for (int ia=0; ia<NA; ia++) {
ProcessRecord r = procs.valueAt(ia);
@@ -11449,10 +9792,10 @@ public class ActivityManagerService extends IActivityManager.Stub
}
}
- if (mIsolatedProcesses.size() > 0) {
+ if (mProcessList.mIsolatedProcesses.size() > 0) {
boolean printed = false;
- for (int i=0; i<mIsolatedProcesses.size(); i++) {
- ProcessRecord r = mIsolatedProcesses.valueAt(i);
+ for (int i=0; i<mProcessList.mIsolatedProcesses.size(); i++) {
+ ProcessRecord r = mProcessList.mIsolatedProcesses.valueAt(i);
if (dumpPackage != null && !r.pkgList.containsKey(dumpPackage)) {
continue;
}
@@ -11505,17 +9848,13 @@ public class ActivityManagerService extends IActivityManager.Stub
}
}
- if (mLruProcesses.size() > 0) {
+ if (mProcessList.getLruSizeLocked() > 0) {
if (needSep) {
pw.println();
}
- pw.print(" Process LRU list (sorted by oom_adj, "); pw.print(mLruProcesses.size());
- pw.print(" total, non-act at ");
- pw.print(mLruProcesses.size()-mLruProcessActivityStart);
- pw.print(", non-svc at ");
- pw.print(mLruProcesses.size()-mLruProcessServiceStart);
- pw.println("):");
- dumpProcessOomList(pw, this, mLruProcesses, " ", "Proc", "PERS", false, dumpPackage);
+ mProcessList.dumpLruListHeaderLocked(pw);
+ dumpProcessOomList(pw, this, mProcessList.mLruProcesses, " ", "Proc", "PERS", false,
+ dumpPackage);
needSep = true;
}
@@ -11569,11 +9908,11 @@ public class ActivityManagerService extends IActivityManager.Stub
"Starting Norm", "Restarting PERS", dumpPackage);
}
- if (mRemovedProcesses.size() > 0) {
+ if (mProcessList.mRemovedProcesses.size() > 0) {
if (needSep) pw.println();
needSep = true;
pw.println(" Processes that are being removed:");
- dumpProcessList(pw, this, mRemovedProcesses, " ",
+ dumpProcessList(pw, this, mProcessList.mRemovedProcesses, " ",
"Removed Norm", "Removed PERS", dumpPackage);
}
@@ -11594,71 +9933,20 @@ public class ActivityManagerService extends IActivityManager.Stub
needSep = false;
mUserController.dump(pw, dumpAll);
}
- if (mActivityTaskManager.mHomeProcess != null && (dumpPackage == null
- || mActivityTaskManager.mHomeProcess.mPkgList.contains(dumpPackage))) {
- if (needSep) {
- pw.println();
- needSep = false;
- }
- pw.println(" mHomeProcess: " + mActivityTaskManager.mHomeProcess);
- }
- if (mActivityTaskManager.mPreviousProcess != null && (dumpPackage == null
- || mActivityTaskManager.mPreviousProcess.mPkgList.contains(dumpPackage))) {
- if (needSep) {
- pw.println();
- needSep = false;
- }
- pw.println(" mPreviousProcess: " + mActivityTaskManager.mPreviousProcess);
- }
- if (dumpAll && (mActivityTaskManager.mPreviousProcess == null || dumpPackage == null
- || mActivityTaskManager.mPreviousProcess.mPkgList.contains(dumpPackage))) {
- StringBuilder sb = new StringBuilder(128);
- sb.append(" mPreviousProcessVisibleTime: ");
- TimeUtils.formatDuration(mActivityTaskManager.mPreviousProcessVisibleTime, sb);
- pw.println(sb);
- }
- if (mActivityTaskManager.mHeavyWeightProcess != null && (dumpPackage == null
- || mActivityTaskManager.mHeavyWeightProcess.mPkgList.contains(dumpPackage))) {
- if (needSep) {
- pw.println();
- needSep = false;
- }
- pw.println(" mHeavyWeightProcess: " + mActivityTaskManager.mHeavyWeightProcess);
- }
- if (dumpAll && mPendingStarts.size() > 0) {
+
+ needSep = mAtmInternal.dumpForProcesses(fd, pw, dumpAll, dumpPackage, dumpAppId, needSep,
+ mTestPssMode, mWakefulness);
+
+ if (dumpAll && mProcessList.mPendingStarts.size() > 0) {
if (needSep) pw.println();
needSep = true;
pw.println(" mPendingStarts: ");
- for (int i = 0, len = mPendingStarts.size(); i < len; ++i ) {
- pw.println(" " + mPendingStarts.keyAt(i) + ": " + mPendingStarts.valueAt(i));
+ for (int i = 0, len = mProcessList.mPendingStarts.size(); i < len; ++i ) {
+ pw.println(" " + mProcessList.mPendingStarts.keyAt(i) + ": "
+ + mProcessList.mPendingStarts.valueAt(i));
}
}
- if (dumpPackage == null) {
- pw.println(" mGlobalConfiguration: " + getGlobalConfiguration());
- mStackSupervisor.dumpDisplayConfigs(pw, " ");
- }
if (dumpAll) {
- if (dumpPackage == null) {
- pw.println(" mConfigWillChange: "
- + mActivityTaskManager.getTopDisplayFocusedStack().mConfigWillChange);
- }
- if (mActivityTaskManager.mCompatModePackages.getPackages().size() > 0) {
- boolean printed = false;
- for (Map.Entry<String, Integer> entry
- : mActivityTaskManager.mCompatModePackages.getPackages().entrySet()) {
- String pkg = entry.getKey();
- int mode = entry.getValue();
- if (dumpPackage != null && !dumpPackage.equals(pkg)) {
- continue;
- }
- if (!printed) {
- pw.println(" mScreenCompatPackages:");
- printed = true;
- }
- pw.print(" "); pw.print(pkg); pw.print(": ");
- pw.print(mode); pw.println();
- }
- }
final int NI = mUidObservers.getRegisteredCallbackCount();
boolean printed = false;
for (int i=0; i<NI; i++) {
@@ -11715,11 +10003,6 @@ public class ActivityManagerService extends IActivityManager.Stub
}
}
}
- if (dumpPackage == null) {
- pw.println(" mWakefulness="
- + PowerManagerInternal.wakefulnessToString(mWakefulness));
- mActivityTaskManager.dumpSleepStates(pw, mTestPssMode);
- }
if (mDebugApp != null || mOrigDebugApp != null || mDebugTransient
|| mOrigWaitForDebugger) {
if (dumpPackage == null || dumpPackage.equals(mDebugApp)
@@ -11733,9 +10016,6 @@ public class ActivityManagerService extends IActivityManager.Stub
+ " mOrigWaitForDebugger=" + mOrigWaitForDebugger);
}
}
- if (mActivityTaskManager.mCurAppTimeTracker != null) {
- mActivityTaskManager.mCurAppTimeTracker.dumpWithHeader(pw, " ", true);
- }
if (mMemWatchProcesses.getMap().size() > 0) {
pw.println(" Mem watch processes:");
final ArrayMap<String, SparseArray<Pair<Long, String>>> procs
@@ -11800,40 +10080,10 @@ public class ActivityManagerService extends IActivityManager.Stub
pw.println(" mNativeDebuggingApp=" + mNativeDebuggingApp);
}
}
- if (mActivityTaskManager.mAllowAppSwitchUids.size() > 0) {
- boolean printed = false;
- for (int i = 0; i < mActivityTaskManager.mAllowAppSwitchUids.size(); i++) {
- ArrayMap<String, Integer> types = mActivityTaskManager.mAllowAppSwitchUids.valueAt(i);
- for (int j = 0; j < types.size(); j++) {
- if (dumpPackage == null ||
- UserHandle.getAppId(types.valueAt(j).intValue()) == dumpAppId) {
- if (needSep) {
- pw.println();
- needSep = false;
- }
- if (!printed) {
- pw.println(" mAllowAppSwitchUids:");
- printed = true;
- }
- pw.print(" User ");
- pw.print(mActivityTaskManager.mAllowAppSwitchUids.keyAt(i));
- pw.print(": Type ");
- pw.print(types.keyAt(j));
- pw.print(" = ");
- UserHandle.formatUid(pw, types.valueAt(j).intValue());
- pw.println();
- }
- }
- }
- }
if (dumpPackage == null) {
if (mAlwaysFinishActivities) {
pw.println(" mAlwaysFinishActivities=" + mAlwaysFinishActivities);
}
- if (mActivityTaskManager.mController != null) {
- pw.println(" mController=" + mActivityTaskManager.mController
- + " mControllerIsAMonkey=" + mActivityTaskManager.mControllerIsAMonkey);
- }
if (dumpAll) {
pw.println(" Total persistent processes: " + numPers);
pw.println(" mProcessesReady=" + mProcessesReady
@@ -11846,11 +10096,9 @@ public class ActivityManagerService extends IActivityManager.Stub
pw.print(" mLastPowerCheckUptime=");
TimeUtils.formatDuration(mLastPowerCheckUptime, pw);
pw.println("");
- pw.println(" mGoingToSleep=" + mStackSupervisor.mGoingToSleep);
- pw.println(" mLaunchingActivity=" + mStackSupervisor.mLaunchingActivity);
- pw.println(" mAdjSeq=" + mAdjSeq + " mLruSeq=" + mLruSeq);
+ pw.println(" mAdjSeq=" + mAdjSeq + " mLruSeq=" + mProcessList.mLruSeq);
pw.println(" mNumNonCachedProcs=" + mNumNonCachedProcs
- + " (" + mLruProcesses.size() + " total)"
+ + " (" + mProcessList.getLruSizeLocked() + " total)"
+ " mNumCachedHiddenProcs=" + mNumCachedHiddenProcs
+ " mNumServiceProcs=" + mNumServiceProcs
+ " mNewNumServiceProcs=" + mNewNumServiceProcs);
@@ -11896,9 +10144,9 @@ public class ActivityManagerService extends IActivityManager.Stub
void writeProcessesToProtoLocked(ProtoOutputStream proto, String dumpPackage) {
int numPers = 0;
- final int NP = mProcessNames.getMap().size();
+ final int NP = mProcessList.mProcessNames.getMap().size();
for (int ip=0; ip<NP; ip++) {
- SparseArray<ProcessRecord> procs = mProcessNames.getMap().valueAt(ip);
+ SparseArray<ProcessRecord> procs = mProcessList.mProcessNames.getMap().valueAt(ip);
final int NA = procs.size();
for (int ia = 0; ia<NA; ia++) {
ProcessRecord r = procs.valueAt(ia);
@@ -11912,8 +10160,8 @@ public class ActivityManagerService extends IActivityManager.Stub
}
}
- for (int i=0; i<mIsolatedProcesses.size(); i++) {
- ProcessRecord r = mIsolatedProcesses.valueAt(i);
+ for (int i=0; i<mProcessList.mIsolatedProcesses.size(); i++) {
+ ProcessRecord r = mProcessList.mIsolatedProcesses.valueAt(i);
if (dumpPackage != null && !r.pkgList.containsKey(dumpPackage)) {
continue;
}
@@ -11946,14 +10194,17 @@ public class ActivityManagerService extends IActivityManager.Stub
uidRec.writeToProto(proto, ActivityManagerServiceDumpProcessesProto.VALIDATE_UIDS);
}
- if (mLruProcesses.size() > 0) {
+ if (mProcessList.getLruSizeLocked() > 0) {
long lruToken = proto.start(ActivityManagerServiceDumpProcessesProto.LRU_PROCS);
- int total = mLruProcesses.size();
+ int total = mProcessList.getLruSizeLocked();
proto.write(ActivityManagerServiceDumpProcessesProto.LruProcesses.SIZE, total);
- proto.write(ActivityManagerServiceDumpProcessesProto.LruProcesses.NON_ACT_AT, total-mLruProcessActivityStart);
- proto.write(ActivityManagerServiceDumpProcessesProto.LruProcesses.NON_SVC_AT, total-mLruProcessServiceStart);
- writeProcessOomListToProto(proto, ActivityManagerServiceDumpProcessesProto.LruProcesses.LIST, this,
- mLruProcesses,false, dumpPackage);
+ proto.write(ActivityManagerServiceDumpProcessesProto.LruProcesses.NON_ACT_AT,
+ total - mProcessList.mLruProcessActivityStart);
+ proto.write(ActivityManagerServiceDumpProcessesProto.LruProcesses.NON_SVC_AT,
+ total - mProcessList.mLruProcessServiceStart);
+ writeProcessOomListToProto(proto,
+ ActivityManagerServiceDumpProcessesProto.LruProcesses.LIST, this,
+ mProcessList.mLruProcesses,false, dumpPackage);
proto.end(lruToken);
}
@@ -11964,7 +10215,8 @@ public class ActivityManagerService extends IActivityManager.Stub
if (!r.pkgList.containsKey(dumpPackage)) {
continue;
}
- r.writeToProto(proto, ActivityManagerServiceDumpProcessesProto.PIDS_SELF_LOCKED);
+ r.writeToProto(proto,
+ ActivityManagerServiceDumpProcessesProto.PIDS_SELF_LOCKED);
}
}
}
@@ -11978,7 +10230,8 @@ public class ActivityManagerService extends IActivityManager.Stub
|| !r.pkgList.containsKey(dumpPackage))) {
continue;
}
- it.writeToProto(proto, ActivityManagerServiceDumpProcessesProto.IMPORTANT_PROCS);
+ it.writeToProto(proto,
+ ActivityManagerServiceDumpProcessesProto.IMPORTANT_PROCS);
}
}
}
@@ -11988,11 +10241,12 @@ public class ActivityManagerService extends IActivityManager.Stub
if (dumpPackage != null && !dumpPackage.equals(r.info.packageName)) {
continue;
}
- r.writeToProto(proto, ActivityManagerServiceDumpProcessesProto.PERSISTENT_STARTING_PROCS);
+ r.writeToProto(proto,
+ ActivityManagerServiceDumpProcessesProto.PERSISTENT_STARTING_PROCS);
}
- for (int i=0; i<mRemovedProcesses.size(); i++) {
- ProcessRecord r = mRemovedProcesses.get(i);
+ for (int i = 0; i < mProcessList.mRemovedProcesses.size(); i++) {
+ ProcessRecord r = mProcessList.mRemovedProcesses.get(i);
if (dumpPackage != null && !dumpPackage.equals(r.info.packageName)) {
continue;
}
@@ -12009,39 +10263,10 @@ public class ActivityManagerService extends IActivityManager.Stub
writeProcessesToGcToProto(proto, ActivityManagerServiceDumpProcessesProto.GC_PROCS, dumpPackage);
mAppErrors.writeToProto(proto, ActivityManagerServiceDumpProcessesProto.APP_ERRORS, dumpPackage);
+ mAtmInternal.writeProcessesToProto(proto, dumpPackage);
if (dumpPackage == null) {
mUserController.writeToProto(proto, ActivityManagerServiceDumpProcessesProto.USER_CONTROLLER);
- getGlobalConfiguration().writeToProto(proto, ActivityManagerServiceDumpProcessesProto.GLOBAL_CONFIGURATION);
- proto.write(ActivityManagerServiceDumpProcessesProto.CONFIG_WILL_CHANGE, mActivityTaskManager.getTopDisplayFocusedStack().mConfigWillChange);
- }
-
- if (mActivityTaskManager.mHomeProcess != null && (dumpPackage == null
- || mActivityTaskManager.mHomeProcess.mPkgList.contains(dumpPackage))) {
- ((ProcessRecord) mActivityTaskManager.mHomeProcess.mOwner).writeToProto(proto, ActivityManagerServiceDumpProcessesProto.HOME_PROC);
- }
-
- if (mActivityTaskManager.mPreviousProcess != null && (dumpPackage == null
- || mActivityTaskManager.mPreviousProcess.mPkgList.contains(dumpPackage))) {
- ((ProcessRecord) mActivityTaskManager.mPreviousProcess.mOwner).writeToProto(proto, ActivityManagerServiceDumpProcessesProto.PREVIOUS_PROC);
- proto.write(ActivityManagerServiceDumpProcessesProto.PREVIOUS_PROC_VISIBLE_TIME_MS, mActivityTaskManager.mPreviousProcessVisibleTime);
- }
-
- if (mActivityTaskManager.mHeavyWeightProcess != null && (dumpPackage == null
- || mActivityTaskManager.mHeavyWeightProcess.mPkgList.contains(dumpPackage))) {
- ((ProcessRecord) mActivityTaskManager.mHeavyWeightProcess.mOwner).writeToProto(proto, ActivityManagerServiceDumpProcessesProto.HEAVY_WEIGHT_PROC);
- }
-
- for (Map.Entry<String, Integer> entry
- : mActivityTaskManager.mCompatModePackages.getPackages().entrySet()) {
- String pkg = entry.getKey();
- int mode = entry.getValue();
- if (dumpPackage == null || dumpPackage.equals(pkg)) {
- long compatToken = proto.start(ActivityManagerServiceDumpProcessesProto.SCREEN_COMPAT_PACKAGES);
- proto.write(ActivityManagerServiceDumpProcessesProto.ScreenCompatPackage.PACKAGE, pkg);
- proto.write(ActivityManagerServiceDumpProcessesProto.ScreenCompatPackage.MODE, mode);
- proto.end(compatToken);
- }
}
final int NI = mUidObservers.getRegisteredCallbackCount();
@@ -12074,8 +10299,6 @@ public class ActivityManagerService extends IActivityManager.Stub
PowerManagerInternal.wakefulnessToProtoEnum(mWakefulness));
proto.write(ActivityManagerServiceDumpProcessesProto.SleepStatus.TEST_PSS_MODE, mTestPssMode);
proto.end(sleepToken);
-
- mActivityTaskManager.writeSleepStateToProto(proto);
}
if (mDebugApp != null || mOrigDebugApp != null || mDebugTransient
@@ -12091,11 +10314,6 @@ public class ActivityManagerService extends IActivityManager.Stub
}
}
- if (mActivityTaskManager.mCurAppTimeTracker != null) {
- mActivityTaskManager.mCurAppTimeTracker.writeToProto(
- proto, ActivityManagerServiceDumpProcessesProto.CURRENT_TRACKER, true);
- }
-
if (mMemWatchProcesses.getMap().size() > 0) {
final long token = proto.start(ActivityManagerServiceDumpProcessesProto.MEM_WATCH_PROCESSES);
ArrayMap<String, SparseArray<Pair<Long, String>>> procs = mMemWatchProcesses.getMap();
@@ -12152,12 +10370,6 @@ public class ActivityManagerService extends IActivityManager.Stub
if (dumpPackage == null) {
proto.write(ActivityManagerServiceDumpProcessesProto.ALWAYS_FINISH_ACTIVITIES, mAlwaysFinishActivities);
- if (mActivityTaskManager.mController != null) {
- final long token = proto.start(ActivityManagerServiceDumpProcessesProto.CONTROLLER);
- proto.write(ActivityManagerServiceDumpProcessesProto.Controller.CONTROLLER, mActivityTaskManager.mController.toString());
- proto.write(ActivityManagerServiceDumpProcessesProto.Controller.IS_A_MONKEY, mActivityTaskManager.mControllerIsAMonkey);
- proto.end(token);
- }
proto.write(ActivityManagerServiceDumpProcessesProto.TOTAL_PERSISTENT_PROCS, numPers);
proto.write(ActivityManagerServiceDumpProcessesProto.PROCESSES_READY, mProcessesReady);
proto.write(ActivityManagerServiceDumpProcessesProto.SYSTEM_READY, mSystemReady);
@@ -12167,10 +10379,8 @@ public class ActivityManagerService extends IActivityManager.Stub
proto.write(ActivityManagerServiceDumpProcessesProto.CALL_FINISH_BOOTING, mCallFinishBooting);
proto.write(ActivityManagerServiceDumpProcessesProto.BOOT_ANIMATION_COMPLETE, mBootAnimationComplete);
proto.write(ActivityManagerServiceDumpProcessesProto.LAST_POWER_CHECK_UPTIME_MS, mLastPowerCheckUptime);
- mStackSupervisor.mGoingToSleep.writeToProto(proto, ActivityManagerServiceDumpProcessesProto.GOING_TO_SLEEP);
- mStackSupervisor.mLaunchingActivity.writeToProto(proto, ActivityManagerServiceDumpProcessesProto.LAUNCHING_ACTIVITY);
proto.write(ActivityManagerServiceDumpProcessesProto.ADJ_SEQ, mAdjSeq);
- proto.write(ActivityManagerServiceDumpProcessesProto.LRU_SEQ, mLruSeq);
+ proto.write(ActivityManagerServiceDumpProcessesProto.LRU_SEQ, mProcessList.mLruSeq);
proto.write(ActivityManagerServiceDumpProcessesProto.NUM_NON_CACHED_PROCS, mNumNonCachedProcs);
proto.write(ActivityManagerServiceDumpProcessesProto.NUM_SERVICE_PROCS, mNumServiceProcs);
proto.write(ActivityManagerServiceDumpProcessesProto.NEW_NUM_SERVICE_PROCS, mNewNumServiceProcs);
@@ -12251,7 +10461,7 @@ public class ActivityManagerService extends IActivityManager.Stub
int opti, boolean dumpAll) {
boolean needSep = false;
- if (mLruProcesses.size() > 0) {
+ if (mProcessList.getLruSizeLocked() > 0) {
if (needSep) pw.println();
needSep = true;
pw.println(" OOM levels:");
@@ -12271,13 +10481,16 @@ public class ActivityManagerService extends IActivityManager.Stub
printOomLevel(pw, "CACHED_APP_MAX_ADJ", ProcessList.CACHED_APP_MAX_ADJ);
if (needSep) pw.println();
- pw.print(" Process OOM control ("); pw.print(mLruProcesses.size());
+ pw.print(" Process OOM control ("); pw.print(mProcessList.getLruSizeLocked());
pw.print(" total, non-act at ");
- pw.print(mLruProcesses.size()-mLruProcessActivityStart);
+ pw.print(mProcessList.getLruSizeLocked()
+ - mProcessList.mLruProcessActivityStart);
pw.print(", non-svc at ");
- pw.print(mLruProcesses.size()-mLruProcessServiceStart);
+ pw.print(mProcessList.getLruSizeLocked()
+ - mProcessList.mLruProcessServiceStart);
pw.println("):");
- dumpProcessOomList(pw, this, mLruProcesses, " ", "Proc", "PERS", true, null);
+ dumpProcessOomList(pw, this, mProcessList.mLruProcesses, " ", "Proc", "PERS", true,
+ null);
needSep = true;
}
@@ -12395,95 +10608,6 @@ public class ActivityManagerService extends IActivityManager.Stub
}
}
- /**
- * There are three things that cmd can be:
- * - a flattened component name that matches an existing activity
- * - the cmd arg isn't the flattened component name of an existing activity:
- * dump all activity whose component contains the cmd as a substring
- * - A hex number of the ActivityRecord object instance.
- *
- * @param dumpVisibleStacksOnly dump activity with {@param name} only if in a visible stack
- * @param dumpFocusedStackOnly dump activity with {@param name} only if in the focused stack
- */
- protected boolean dumpActivity(FileDescriptor fd, PrintWriter pw, String name, String[] args,
- int opti, boolean dumpAll, boolean dumpVisibleStacksOnly, boolean dumpFocusedStackOnly) {
- ArrayList<ActivityRecord> activities;
-
- synchronized (this) {
- activities = mStackSupervisor.getDumpActivitiesLocked(name, dumpVisibleStacksOnly,
- dumpFocusedStackOnly);
- }
-
- if (activities.size() <= 0) {
- return false;
- }
-
- String[] newArgs = new String[args.length - opti];
- System.arraycopy(args, opti, newArgs, 0, args.length - opti);
-
- TaskRecord lastTask = null;
- boolean needSep = false;
- for (int i=activities.size()-1; i>=0; i--) {
- ActivityRecord r = activities.get(i);
- if (needSep) {
- pw.println();
- }
- needSep = true;
- synchronized (this) {
- final TaskRecord task = r.getTask();
- if (lastTask != task) {
- lastTask = task;
- pw.print("TASK "); pw.print(lastTask.affinity);
- pw.print(" id="); pw.print(lastTask.taskId);
- pw.print(" userId="); pw.println(lastTask.userId);
- if (dumpAll) {
- lastTask.dump(pw, " ");
- }
- }
- }
- dumpActivity(" ", fd, pw, activities.get(i), newArgs, dumpAll);
- }
- return true;
- }
-
- /**
- * Invokes IApplicationThread.dumpActivity() on the thread of the specified activity if
- * there is a thread associated with the activity.
- */
- private void dumpActivity(String prefix, FileDescriptor fd, PrintWriter pw,
- final ActivityRecord r, String[] args, boolean dumpAll) {
- String innerPrefix = prefix + " ";
- synchronized (this) {
- pw.print(prefix); pw.print("ACTIVITY "); pw.print(r.shortComponentName);
- pw.print(" "); pw.print(Integer.toHexString(System.identityHashCode(r)));
- pw.print(" pid=");
- if (r.hasProcess()) pw.println(r.app.getPid());
- else pw.println("(not running)");
- if (dumpAll) {
- r.dump(pw, innerPrefix);
- }
- }
- if (r.attachedToProcess()) {
- // flush anything that is already in the PrintWriter since the thread is going
- // to write to the file descriptor directly
- pw.flush();
- try {
- TransferPipe tp = new TransferPipe();
- try {
- r.app.getThread().dumpActivity(tp.getWriteFd(),
- r.appToken, innerPrefix, args);
- tp.go(fd);
- } finally {
- tp.kill();
- }
- } catch (IOException e) {
- pw.println(innerPrefix + "Failure while dumping the activity: " + e);
- } catch (RemoteException e) {
- pw.println(innerPrefix + "Got a RemoteException while dumping the activity");
- }
- }
- }
-
void writeBroadcastsToProtoLocked(ProtoOutputStream proto) {
if (mRegisteredReceivers.size() > 0) {
Iterator it = mRegisteredReceivers.values().iterator();
@@ -12808,12 +10932,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);
@@ -12834,12 +10959,12 @@ public class ActivityManagerService extends IActivityManager.Stub
if (inclDetails) {
long detailToken = proto.start(ProcessOomProto.DETAIL);
proto.write(ProcessOomProto.Detail.MAX_ADJ, r.maxAdj);
- proto.write(ProcessOomProto.Detail.CUR_RAW_ADJ, r.curRawAdj);
+ proto.write(ProcessOomProto.Detail.CUR_RAW_ADJ, r.getCurRawAdj());
proto.write(ProcessOomProto.Detail.SET_RAW_ADJ, r.setRawAdj);
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(
@@ -12905,14 +11030,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(" #");
@@ -12960,13 +11085,14 @@ public class ActivityManagerService extends IActivityManager.Stub
pw.print(prefix);
pw.print(" ");
pw.print("oom: max="); pw.print(r.maxAdj);
- pw.print(" curRaw="); pw.print(r.curRawAdj);
+ pw.print(" curRaw="); pw.print(r.getCurRawAdj());
pw.print(" setRaw="); pw.print(r.setRawAdj);
pw.print(" cur="); pw.print(r.curAdj);
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);
@@ -12999,35 +11125,9 @@ public class ActivityManagerService extends IActivityManager.Stub
ArrayList<ProcessRecord> collectProcesses(PrintWriter pw, int start, boolean allPkgs,
String[] args) {
- ArrayList<ProcessRecord> procs;
synchronized (this) {
- if (args != null && args.length > start
- && args[start].charAt(0) != '-') {
- procs = new ArrayList<ProcessRecord>();
- int pid = -1;
- try {
- pid = Integer.parseInt(args[start]);
- } catch (NumberFormatException e) {
- }
- for (int i=mLruProcesses.size()-1; i>=0; i--) {
- ProcessRecord proc = mLruProcesses.get(i);
- if (proc.pid > 0 && proc.pid == pid) {
- procs.add(proc);
- } else if (allPkgs && proc.pkgList != null
- && proc.pkgList.containsKey(args[start])) {
- procs.add(proc);
- } else if (proc.processName.equals(args[start])) {
- procs.add(proc);
- }
- }
- if (procs.size() <= 0) {
- return null;
- }
- } else {
- procs = new ArrayList<ProcessRecord>(mLruProcesses);
- }
+ return mProcessList.collectProcessesLocked(start, allPkgs, args);
}
- return procs;
}
final void dumpGraphicsHardwareUsage(FileDescriptor fd,
@@ -14621,13 +12721,13 @@ public class ActivityManagerService extends IActivityManager.Stub
mServices.newServiceDumperLocked(null, catPw, emptyArgs, 0,
false, null).dumpLocked();
catPw.println();
- dumpActivitiesLocked(null, catPw, emptyArgs, 0, false, false, null);
+ mAtmInternal.dump(DUMP_ACTIVITIES_CMD, null, catPw, emptyArgs, 0, false, false, null);
catPw.flush();
}
dropBuilder.append(catSw.toString());
StatsLog.write(StatsLog.LOW_MEM_REPORTED);
addErrorToDropBox("lowmem", null, "system_server", null,
- null, tag.toString(), dropBuilder.toString(), null, null);
+ null, null, tag.toString(), dropBuilder.toString(), null, null);
//Slog.i(TAG, "Sent to dropbox:");
//Slog.i(TAG, dropBuilder.toString());
synchronized (ActivityManagerService.this) {
@@ -14722,7 +12822,7 @@ public class ActivityManagerService extends IActivityManager.Stub
* app that was passed in must remain on the process lists.
*/
@GuardedBy("this")
- private final boolean cleanUpApplicationRecordLocked(ProcessRecord app,
+ final boolean cleanUpApplicationRecordLocked(ProcessRecord app,
boolean restarting, boolean allowRestart, int index, boolean replacingPid) {
if (index >= 0) {
removeLruProcessLocked(app);
@@ -14756,11 +12856,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);
@@ -14862,7 +12962,7 @@ public class ActivityManagerService extends IActivityManager.Stub
if (DEBUG_PROCESSES || DEBUG_CLEANUP) Slog.v(TAG_CLEANUP,
"Removing non-persistent process during cleanup: " + app);
if (!replacingPid) {
- removeProcessNameLocked(app.processName, app.uid, app);
+ mProcessList.removeProcessNameLocked(app.processName, app.uid, app);
}
mAtmInternal.clearHeavyWeightProcessIfEquals(app.getWindowProcessController());
} else if (!app.removed) {
@@ -14886,9 +12986,9 @@ public class ActivityManagerService extends IActivityManager.Stub
if (index < 0) {
ProcessList.remove(app.pid);
}
- addProcessNameLocked(app);
+ mProcessList.addProcessNameLocked(app);
app.pendingStart = false;
- startProcessLocked(app, "restart", app.processName);
+ mProcessList.startProcessLocked(app, "restart", app.processName);
return true;
} else if (app.pid > 0 && app.pid != MY_PID) {
// Goodbye!
@@ -15625,15 +13725,7 @@ public class ActivityManagerService extends IActivityManager.Stub
}
private final void sendPackageBroadcastLocked(int cmd, String[] packages, int userId) {
- for (int i = mLruProcesses.size() - 1 ; i >= 0 ; i--) {
- ProcessRecord r = mLruProcesses.get(i);
- if (r.thread != null && (userId == UserHandle.USER_ALL || r.userId == userId)) {
- try {
- r.thread.dispatchPackageBroadcast(cmd, packages);
- } catch (RemoteException ex) {
- }
- }
- }
+ mProcessList.sendPackageBroadcastLocked(cmd, packages, userId);
}
private List<ResolveInfo> collectReceiverComponents(Intent intent, String resolvedType,
@@ -16042,8 +14134,10 @@ public class ActivityManagerService extends IActivityManager.Stub
}
} else {
if (killProcess) {
- killPackageProcessesLocked(ssp, UserHandle.getAppId(
- intent.getIntExtra(Intent.EXTRA_UID, -1)),
+ final int extraUid = intent.getIntExtra(Intent.EXTRA_UID,
+ -1);
+ mProcessList.killPackageProcessesLocked(ssp,
+ UserHandle.getAppId(extraUid),
userId, ProcessList.INVALID_ADJ,
false, true, true, false, "change " + ssp);
}
@@ -16084,7 +14178,7 @@ public class ActivityManagerService extends IActivityManager.Stub
+ " ssp=" + ssp + " data=" + data);
return ActivityManager.BROADCAST_SUCCESS;
}
- mStackSupervisor.updateActivityApplicationInfoLocked(aInfo);
+ mAtmInternal.onPackageReplaced(aInfo);
mServices.updateServiceApplicationInfoLocked(aInfo);
sendPackageBroadcastLocked(ApplicationThreadConstants.PACKAGE_REPLACED,
new String[] {ssp}, userId);
@@ -17032,7 +15126,7 @@ public class ActivityManagerService extends IActivityManager.Stub
}
}
- private void noteUidProcessState(final int uid, final int state) {
+ void noteUidProcessState(final int uid, final int state) {
mBatteryStatsService.noteUidProcessState(uid, state);
mAppOpsService.updateUidProcState(uid, state);
if (mTrackingAssociations) {
@@ -17064,6 +15158,7 @@ public class ActivityManagerService extends IActivityManager.Stub
private final ComputeOomAdjWindowCallback mTmpComputeOomAdjWindowCallback =
new ComputeOomAdjWindowCallback();
+ /** These methods are called inline during computeOomAdjLocked(), on the same thread */
private final class ComputeOomAdjWindowCallback
implements WindowProcessController.ComputeOomAdjCallback {
@@ -17202,8 +15297,9 @@ 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.curAdj=app.curRawAdj=ProcessList.CACHED_APP_MAX_ADJ;
+ app.setCurProcState(ActivityManager.PROCESS_STATE_CACHED_EMPTY);
+ app.curAdj = ProcessList.CACHED_APP_MAX_ADJ;
+ app.setCurRawAdj(ProcessList.CACHED_APP_MAX_ADJ);
app.completedAdjSeq = app.adjSeq;
return false;
}
@@ -17219,7 +15315,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
@@ -17229,10 +15325,10 @@ public class ActivityManagerService extends IActivityManager.Stub
}
app.adjType = "fixed";
app.adjSeq = mAdjSeq;
- app.curRawAdj = app.maxAdj;
- app.foregroundActivities = false;
+ app.setCurRawAdj(app.maxAdj);
+ 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
@@ -17242,7 +15338,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";
@@ -17252,11 +15348,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);
}
}
@@ -17392,7 +15488,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;
@@ -17506,7 +15602,7 @@ public class ActivityManagerService extends IActivityManager.Stub
// there are applications dependent on our services or providers, but
// this gives us a baseline and makes sure we don't get into an
// infinite recursion.
- app.curRawAdj = adj;
+ app.setCurRawAdj(adj);
app.hasStartedServices = false;
app.adjSeq = mAdjSeq;
@@ -17621,8 +15717,8 @@ public class ActivityManagerService extends IActivityManager.Stub
continue;
}
}
- int clientAdj = client.curRawAdj;
- int clientProcState = client.curProcState;
+ int clientAdj = client.getCurRawAdj();
+ 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
@@ -17783,8 +15879,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;
@@ -17863,8 +15959,8 @@ public class ActivityManagerService extends IActivityManager.Stub
continue;
}
}
- int clientAdj = client.curRawAdj;
- int clientProcState = client.curProcState;
+ int clientAdj = client.getCurRawAdj();
+ 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.
@@ -18025,7 +16121,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";
@@ -18065,7 +16161,7 @@ public class ActivityManagerService extends IActivityManager.Stub
}
}
- app.curRawAdj = adj;
+ app.setCurRawAdj(adj);
//Slog.i(TAG, "OOM ADJ " + app + ": pid=" + app.pid +
// " adj=" + adj + " curAdj=" + app.curAdj + " maxAdj=" + app.maxAdj);
@@ -18092,12 +16188,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;
}
/**
@@ -18244,12 +16340,12 @@ public class ActivityManagerService extends IActivityManager.Stub
for (int i = mPendingPssProcesses.size() - 1; i >= 0; i--) {
ProcessList.abortNextPssTime(mPendingPssProcesses.get(i).procStateMemTracker);;
}
- mPendingPssProcesses.ensureCapacity(mLruProcesses.size());
+ mPendingPssProcesses.ensureCapacity(mProcessList.getLruSizeLocked());
mPendingPssProcesses.clear();
- for (int i = mLruProcesses.size() - 1; i >= 0; i--) {
- ProcessRecord app = mLruProcesses.get(i);
+ for (int i = mProcessList.getLruSizeLocked() - 1; i >= 0; i--) {
+ ProcessRecord app = mProcessList.mLruProcesses.get(i);
if (app.thread == null
- || app.curProcState == ActivityManager.PROCESS_STATE_NONEXISTENT) {
+ || app.getCurProcState() == ActivityManager.PROCESS_STATE_NONEXISTENT) {
continue;
}
if (memLowered || (always && now >
@@ -18258,7 +16354,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);
}
@@ -18308,8 +16404,7 @@ public class ActivityManagerService extends IActivityManager.Stub
processingBroadcasts = true;
}
}
- return !processingBroadcasts
- && (mAtmInternal.isSleeping() || mStackSupervisor.allResumedActivitiesIdle());
+ return !processingBroadcasts && mAtmInternal.canGcNow();
}
/**
@@ -18324,7 +16419,7 @@ public class ActivityManagerService extends IActivityManager.Stub
if (canGcNowLocked()) {
while (mProcessesToGc.size() > 0) {
ProcessRecord proc = mProcessesToGc.remove(0);
- if (proc.curRawAdj > ProcessList.PERCEPTIBLE_APP_ADJ || proc.reportLowMemory) {
+ if (proc.getCurRawAdj() > ProcessList.PERCEPTIBLE_APP_ADJ || proc.reportLowMemory) {
if ((proc.lastRequestedGc+mConstants.GC_MIN_INTERVAL)
<= SystemClock.uptimeMillis()) {
// To avoid spamming the system, we will GC processes one
@@ -18424,10 +16519,10 @@ public class ActivityManagerService extends IActivityManager.Stub
final long curUptime = SystemClock.uptimeMillis();
final long uptimeSince = curUptime - mLastPowerCheckUptime;
mLastPowerCheckUptime = curUptime;
- int i = mLruProcesses.size();
+ int i = mProcessList.mLruProcesses.size();
while (i > 0) {
i--;
- ProcessRecord app = mLruProcesses.get(i);
+ ProcessRecord app = mProcessList.mLruProcesses.get(i);
if (app.setProcState >= ActivityManager.PROCESS_STATE_HOME) {
if (app.lastCpuTime <= 0) {
continue;
@@ -18451,7 +16546,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)
@@ -18489,20 +16584,8 @@ public class ActivityManagerService extends IActivityManager.Stub
long nowElapsed) {
boolean success = true;
- if (app.curRawAdj != app.setRawAdj) {
- String seempStr = "app_uid=" + app.uid
- + ",app_pid=" + app.pid + ",oom_adj=" + app.curAdj
- + ",setAdj=" + app.setAdj + ",hasShownUi=" + (app.hasShownUi ? 1 : 0)
- + ",cached=" + (app.cached ? 1 : 0)
- + ",fA=" + (app.foregroundActivities ? 1 : 0)
- + ",fS=" + (app.hasForegroundServices() ? 1 : 0)
- + ",systemNoUi=" + (app.systemNoUi ? 1 : 0)
- + ",curSchedGroup=" + app.getCurrentSchedulingGroup()
- + ",curProcState=" + app.curProcState + ",setProcState=" + app.setProcState
- + ",killed=" + (app.killed ? 1 : 0) + ",killedByAm=" + (app.killedByAm ? 1 : 0)
- + ",isDebugging=" + (app.isDebugging() ? 1 : 0);
- android.util.SeempLog.record_str(385, seempStr);
- app.setRawAdj = app.curRawAdj;
+ if (app.getCurRawAdj() != app.setRawAdj) {
+ app.setRawAdj = app.getCurRawAdj();
}
int changes = 0;
@@ -18625,12 +16708,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) {
@@ -18644,7 +16727,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
@@ -18654,46 +16737,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
@@ -18702,7 +16784,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;
}
@@ -18711,7 +16793,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.
@@ -18865,7 +16947,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();
@@ -18885,7 +16967,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;
@@ -18894,24 +16976,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++) {
@@ -18922,13 +17006,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;
}
}
@@ -18988,13 +17072,14 @@ public class ActivityManagerService extends IActivityManager.Stub
// TODO(b/111541062): This method is only used for updating OOM adjustments. We need to update
// the logic there and in mBatteryStatsService to make them aware of multiple resumed activities
- private ActivityRecord resumedAppLocked() {
- final ActivityRecord act = mStackSupervisor.getTopResumedActivity();
+ ProcessRecord getTopAppLocked() {
+ final WindowProcessController wpc = mAtmInternal != null ? mAtmInternal.getTopApp() : null;
+ final ProcessRecord r = wpc != null ? (ProcessRecord) wpc.mOwner : null;
String pkg;
int uid;
- if (act != null) {
- pkg = act.packageName;
- uid = act.info.applicationInfo.uid;
+ if (r != null) {
+ pkg = r.processName;
+ uid = r.info.uid;
} else {
pkg = null;
uid = -1;
@@ -19020,7 +17105,7 @@ public class ActivityManagerService extends IActivityManager.Stub
}
}
- return act;
+ return r;
}
/**
@@ -19032,9 +17117,7 @@ public class ActivityManagerService extends IActivityManager.Stub
*/
@GuardedBy("this")
final boolean updateOomAdjLocked(ProcessRecord app, boolean oomAdjAll) {
- final ActivityRecord TOP_ACT = resumedAppLocked();
- final ProcessRecord TOP_APP = TOP_ACT != null && TOP_ACT.hasProcess()
- ? (ProcessRecord) TOP_ACT.app.mOwner : null;
+ final ProcessRecord TOP_APP = getTopAppLocked();
final boolean wasCached = app.cached;
mAdjSeq++;
@@ -19043,12 +17126,12 @@ public class ActivityManagerService extends IActivityManager.Stub
// If our app is currently cached, we know it, and that is it. Otherwise,
// we don't know it yet, and it needs to now be cached we will then
// need to do a complete oom adj.
- final int cachedAdj = app.curRawAdj >= ProcessList.CACHED_APP_MIN_ADJ
- ? app.curRawAdj : ProcessList.UNKNOWN_ADJ;
+ final int cachedAdj = app.getCurRawAdj() >= ProcessList.CACHED_APP_MIN_ADJ
+ ? app.getCurRawAdj() : ProcessList.UNKNOWN_ADJ;
boolean success = updateOomAdjLocked(app, cachedAdj, TOP_APP, false,
SystemClock.uptimeMillis());
if (oomAdjAll
- && (wasCached != app.cached || app.curRawAdj == ProcessList.UNKNOWN_ADJ)) {
+ && (wasCached != app.cached || app.getCurRawAdj() == ProcessList.UNKNOWN_ADJ)) {
// Changed to/from cached state, so apps after it in the LRU
// list may also be changed.
updateOomAdjLocked();
@@ -19057,23 +17140,13 @@ public class ActivityManagerService extends IActivityManager.Stub
}
@GuardedBy("this")
- ProcessRecord getTopAppLocked() {
- final ActivityRecord TOP_ACT = resumedAppLocked();
- if (TOP_ACT != null && TOP_ACT.hasProcess()) {
- return (ProcessRecord) TOP_ACT.app.mOwner;
- } else {
- return null;
- }
- }
-
- @GuardedBy("this")
final void updateOomAdjLocked() {
mOomAdjProfiler.oomAdjStarted();
final ProcessRecord TOP_APP = getTopAppLocked();
final long now = SystemClock.uptimeMillis();
final long nowElapsed = SystemClock.elapsedRealtime();
final long oldTime = now - ProcessList.MAX_EMPTY_TIME;
- final int N = mLruProcesses.size();
+ final int N = mProcessList.getLruSizeLocked();
// Reset state in all uid records.
for (int i=mActiveUids.size()-1; i>=0; i--) {
@@ -19083,8 +17156,8 @@ public class ActivityManagerService extends IActivityManager.Stub
uidRec.reset();
}
- if (mStackSupervisor != null) {
- mStackSupervisor.rankTaskLayersIfNeeded();
+ if (mAtmInternal != null) {
+ mAtmInternal.rankTaskLayersIfNeeded();
}
mAdjSeq++;
@@ -19137,7 +17210,11 @@ public class ActivityManagerService extends IActivityManager.Stub
// need to reset cycle state before calling computeOomAdjLocked because of service connections
for (int i=N-1; i>=0; i--) {
- ProcessRecord app = mLruProcesses.get(i);
+ ProcessRecord app = mProcessList.mLruProcesses.get(i);
+ app.containsCycle = false;
+ }
+ for (int i=N-1; i>=0; i--) {
+ ProcessRecord app = mProcessList.mLruProcesses.get(i);
if (mEnableBServicePropagation && app.serviceb
&& (app.curAdj == ProcessList.SERVICE_B_ADJ)) {
numBServices++;
@@ -19176,14 +17253,14 @@ 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:
// This process is a cached process holding activities...
// assign it the next cached value for that type, and then
// step that cached level.
- app.curRawAdj = curCachedAdj;
+ app.setCurRawAdj(curCachedAdj);
app.curAdj = app.modifyRawOomAdj(curCachedAdj);
if (DEBUG_LRU && false) Slog.d(TAG_LRU, "Assigning activity LRU #" + i
+ " adj: " + app.curAdj + " (curCachedAdj=" + curCachedAdj
@@ -19206,7 +17283,7 @@ public class ActivityManagerService extends IActivityManager.Stub
// long-running services that have dropped down to the
// cached level will be treated as empty (since their process
// state is still as a service), which is what we want.
- app.curRawAdj = curEmptyAdj;
+ app.setCurRawAdj(curEmptyAdj);
app.curAdj = app.modifyRawOomAdj(curEmptyAdj);
if (DEBUG_LRU && false) Slog.d(TAG_LRU, "Assigning empty LRU #" + i
+ " adj: " + app.curAdj + " (curEmptyAdj=" + curEmptyAdj
@@ -19240,7 +17317,7 @@ public class ActivityManagerService extends IActivityManager.Stub
retryCycles = false;
for (int i=0; i<N; i++) {
- ProcessRecord app = mLruProcesses.get(i);
+ ProcessRecord app = mProcessList.mLruProcesses.get(i);
if (!app.killedByAm && app.thread != null && app.containsCycle == true) {
app.adjSeq--;
app.completedAdjSeq--;
@@ -19248,7 +17325,7 @@ public class ActivityManagerService extends IActivityManager.Stub
}
for (int i=0; i<N; i++) {
- ProcessRecord app = mLruProcesses.get(i);
+ ProcessRecord app = mProcessList.mLruProcesses.get(i);
if (!app.killedByAm && app.thread != null && app.containsCycle == true) {
if (computeOomAdjLocked(app, ProcessList.UNKNOWN_ADJ, TOP_APP, true, now)) {
@@ -19259,12 +17336,12 @@ public class ActivityManagerService extends IActivityManager.Stub
}
for (int i=N-1; i>=0; i--) {
- ProcessRecord app = mLruProcesses.get(i);
+ ProcessRecord app = mProcessList.mLruProcesses.get(i);
if (!app.killedByAm && app.thread != null) {
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++;
@@ -19305,8 +17382,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;
@@ -19314,7 +17391,7 @@ public class ActivityManagerService extends IActivityManager.Stub
}
}
- if (app.curProcState >= ActivityManager.PROCESS_STATE_HOME
+ if (app.getCurProcState() >= ActivityManager.PROCESS_STATE_HOME
&& !app.killedByAm) {
numTrimming++;
}
@@ -19358,9 +17435,9 @@ public class ActivityManagerService extends IActivityManager.Stub
// has gone down since last time.
if (DEBUG_OOM_ADJ) Slog.d(TAG_OOM_ADJ, "oom: memFactor=" + memFactor
+ " last=" + mLastMemoryLevel + " allowLow=" + mAllowLowerMemLevel
- + " numProcs=" + mLruProcesses.size() + " last=" + mLastNumProcesses);
+ + " numProcs=" + mProcessList.getLruSizeLocked() + " last=" + mLastNumProcesses);
if (memFactor > mLastMemoryLevel) {
- if (!mAllowLowerMemLevel || mLruProcesses.size() >= mLastNumProcesses) {
+ if (!mAllowLowerMemLevel || mProcessList.getLruSizeLocked() >= mLastNumProcesses) {
memFactor = mLastMemoryLevel;
if (DEBUG_OOM_ADJ) Slog.d(TAG_OOM_ADJ, "Keeping last mem factor!");
}
@@ -19370,7 +17447,7 @@ public class ActivityManagerService extends IActivityManager.Stub
StatsLog.write(StatsLog.MEMORY_FACTOR_STATE_CHANGED, memFactor);
}
mLastMemoryLevel = memFactor;
- mLastNumProcesses = mLruProcesses.size();
+ mLastNumProcesses = mProcessList.getLruSizeLocked();
boolean allChanged = mProcessStats.setMemFactorLocked(
memFactor, mAtmInternal != null ? !mAtmInternal.isSleeping() : true, now);
final int trackerMemFactor = mProcessStats.getMemFactorLocked();
@@ -19398,12 +17475,12 @@ public class ActivityManagerService extends IActivityManager.Stub
if (factor < minFactor) factor = minFactor;
int curLevel = ComponentCallbacks2.TRIM_MEMORY_COMPLETE;
for (int i=N-1; i>=0; i--) {
- ProcessRecord app = mLruProcesses.get(i);
+ ProcessRecord app = mProcessList.mLruProcesses.get(i);
if (allChanged || app.procStateChanged) {
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 {
@@ -19426,7 +17503,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) {
@@ -19441,8 +17518,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.
@@ -19456,7 +17533,7 @@ public class ActivityManagerService extends IActivityManager.Stub
} catch (RemoteException e) {
}
}
- app.pendingUiClean = false;
+ app.setPendingUiClean(false);
}
if (app.trimMemoryLevel < fgTrimLevel && app.thread != null) {
try {
@@ -19476,13 +17553,13 @@ public class ActivityManagerService extends IActivityManager.Stub
mLowRamStartTime = 0;
}
for (int i=N-1; i>=0; i--) {
- ProcessRecord app = mLruProcesses.get(i);
+ ProcessRecord app = mProcessList.mLruProcesses.get(i);
if (allChanged || app.procStateChanged) {
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 {
@@ -19494,7 +17571,7 @@ public class ActivityManagerService extends IActivityManager.Stub
} catch (RemoteException e) {
}
}
- app.pendingUiClean = false;
+ app.setPendingUiClean(false);
}
app.trimMemoryLevel = 0;
}
@@ -19503,7 +17580,7 @@ public class ActivityManagerService extends IActivityManager.Stub
if (mAlwaysFinishActivities) {
// Need to do this on its own message because the stack may not
// be in a consistent state at this point.
- mStackSupervisor.scheduleDestroyAllActivities(null, "always-finish");
+ mAtmInternal.scheduleDestroyAllActivities("always-finish");
}
if (allChanged) {
@@ -19740,7 +17817,7 @@ public class ActivityManagerService extends IActivityManager.Stub
continue;
}
synchronized (uidRec.networkStateLock) {
- uidRec.curProcStateSeq = ++mProcStateSeqCounter;
+ uidRec.curProcStateSeq = ++mProcessList.mProcStateSeqCounter; // TODO: use method
if (blockState == NETWORK_STATE_BLOCK) {
if (blockingUids == null) {
blockingUids = new ArrayList<>();
@@ -19763,8 +17840,8 @@ public class ActivityManagerService extends IActivityManager.Stub
return;
}
- for (int i = mLruProcesses.size() - 1; i >= 0; --i) {
- final ProcessRecord app = mLruProcesses.get(i);
+ for (int i = mProcessList.mLruProcesses.size() - 1; i >= 0; --i) {
+ final ProcessRecord app = mProcessList.mLruProcesses.get(i);
if (!blockingUids.contains(app.uid)) {
continue;
}
@@ -19962,8 +18039,8 @@ public class ActivityManagerService extends IActivityManager.Stub
final void trimApplicationsLocked() {
// First remove any unused application processes whose package
// has been removed.
- for (int i=mRemovedProcesses.size()-1; i>=0; i--) {
- final ProcessRecord app = mRemovedProcesses.get(i);
+ for (int i = mProcessList.mRemovedProcesses.size() - 1; i >= 0; i--) {
+ final ProcessRecord app = mProcessList.mRemovedProcesses.get(i);
if (!app.hasActivitiesOrRecentTasks()
&& app.curReceivers.isEmpty() && app.services.size() == 0) {
Slog.i(
@@ -19981,7 +18058,7 @@ public class ActivityManagerService extends IActivityManager.Stub
}
}
cleanUpApplicationRecordLocked(app, false, true, -1, false /*replacingPid*/);
- mRemovedProcesses.remove(i);
+ mProcessList.mRemovedProcesses.remove(i);
if (app.isPersistent()) {
addAppLocked(app.info, null, false, null /* ABI override */);
@@ -20007,8 +18084,8 @@ public class ActivityManagerService extends IActivityManager.Stub
+ android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES);
}
- for (int i = mLruProcesses.size() - 1 ; i >= 0 ; i--) {
- ProcessRecord r = mLruProcesses.get(i);
+ for (int i = mProcessList.mLruProcesses.size() - 1 ; i >= 0 ; i--) {
+ ProcessRecord r = mProcessList.mLruProcesses.get(i);
if (r.thread != null && r.isPersistent()) {
sendSignal(r.pid, sig);
}
@@ -20135,7 +18212,7 @@ public class ActivityManagerService extends IActivityManager.Stub
if (proc == null) {
ArrayMap<String, SparseArray<ProcessRecord>> all
- = mProcessNames.getMap();
+ = mProcessList.mProcessNames.getMap();
SparseArray<ProcessRecord> procs = all.get(process);
if (procs != null && procs.size() > 0) {
proc = procs.valueAt(0);
@@ -20265,15 +18342,8 @@ public class ActivityManagerService extends IActivityManager.Stub
}
void onCoreSettingsChange(Bundle settings) {
- for (int i = mLruProcesses.size() - 1; i >= 0; i--) {
- ProcessRecord processRecord = mLruProcesses.get(i);
- try {
- if (processRecord.thread != null) {
- processRecord.thread.setCoreSettings(settings);
- }
- } catch (RemoteException re) {
- /* ignore */
- }
+ synchronized (this) {
+ mProcessList.updateCoreSettingsLocked(settings);
}
}
@@ -20405,8 +18475,8 @@ public class ActivityManagerService extends IActivityManager.Stub
+ android.Manifest.permission.SET_ACTIVITY_WATCHER);
}
- for (int i = 0; i < mLruProcesses.size(); i++) {
- ProcessRecord process = mLruProcesses.get(i);
+ for (int i = 0; i < mProcessList.mLruProcesses.size(); i++) {
+ ProcessRecord process = mProcessList.mLruProcesses.get(i);
if (!processSanityChecksLocked(process)) {
continue;
}
@@ -20438,7 +18508,7 @@ public class ActivityManagerService extends IActivityManager.Stub
PrintWriter pw = new FastPrintWriter(new FileOutputStream(fd.getFileDescriptor()));
pw.println("Binder transaction traces for all processes.\n");
- for (ProcessRecord process : mLruProcesses) {
+ for (ProcessRecord process : mProcessList.mLruProcesses) {
if (!processSanityChecksLocked(process)) {
continue;
}
@@ -20499,9 +18569,10 @@ public class ActivityManagerService extends IActivityManager.Stub
public void killForegroundAppsForUser(int userHandle) {
synchronized (ActivityManagerService.this) {
final ArrayList<ProcessRecord> procs = new ArrayList<>();
- final int NP = mProcessNames.getMap().size();
+ final int NP = mProcessList.mProcessNames.getMap().size();
for (int ip = 0; ip < NP; ip++) {
- final SparseArray<ProcessRecord> apps = mProcessNames.getMap().valueAt(ip);
+ final SparseArray<ProcessRecord> apps =
+ mProcessList.mProcessNames.getMap().valueAt(ip);
final int NA = apps.size();
for (int ia = 0; ia < NA; ia++) {
final ProcessRecord app = apps.valueAt(ia);
@@ -20511,7 +18582,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);
}
@@ -20520,7 +18591,7 @@ public class ActivityManagerService extends IActivityManager.Stub
final int N = procs.size();
for (int i = 0; i < N; i++) {
- removeProcessLocked(procs.get(i), false, true, "kill all fg");
+ mProcessList.removeProcessLocked(procs.get(i), false, true, "kill all fg");
}
}
}
@@ -20582,10 +18653,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);
}
@@ -20641,36 +18712,6 @@ public class ActivityManagerService extends IActivityManager.Stub
}
@Override
- public void saveANRState(String reason) {
- synchronized (ActivityManagerService.this) {
- final StringWriter sw = new StringWriter();
- final PrintWriter pw = new FastPrintWriter(sw, false, 1024);
- pw.println(" ANR time: " + DateFormat.getDateTimeInstance().format(new Date()));
- if (reason != null) {
- pw.println(" Reason: " + reason);
- }
- pw.println();
- mActivityTaskManager.getActivityStartController().dump(pw, " ", null);
- pw.println();
- pw.println("-------------------------------------------------------------------------------");
- dumpActivitiesLocked(null /* fd */, pw, null /* args */, 0 /* opti */,
- true /* dumpAll */, false /* dumpClient */, null /* dumpPackage */,
- "" /* header */);
- pw.println();
- pw.close();
-
- mLastANRState = sw.toString();
- }
- }
-
- @Override
- public void clearSavedANRState() {
- synchronized (ActivityManagerService.this) {
- mLastANRState = null;
- }
- }
-
- @Override
public boolean isRuntimeRestarted() {
return mSystemServiceManager.isRuntimeRestarted();
}
@@ -20736,6 +18777,28 @@ public class ActivityManagerService extends IActivityManager.Stub
}
@Override
+ public List<ProcessMemoryState> getMemoryStateForNativeProcesses() {
+ List<ProcessMemoryState> processMemoryStates = new ArrayList<>();
+ int[] pids = getPidsForCommands(MEMORY_STAT_INTERESTING_NATIVE_PROCESSES);
+ for (int i = 0; i < pids.length; i++) {
+ int pid = pids[i];
+ MemoryStat memoryStat = readMemoryStatFromProcfs(pid);
+ if (memoryStat == null) {
+ continue;
+ }
+ int uid = getUidForPid(pid);
+ String processName = readCmdlineFromProcfs(pid);
+ int oomScore = -1; // Unused, not included in the NativeProcessMemoryState atom.
+ ProcessMemoryState processMemoryState = new ProcessMemoryState(uid, processName,
+ oomScore, memoryStat.pgfault, memoryStat.pgmajfault,
+ memoryStat.rssInBytes, memoryStat.cacheInBytes, memoryStat.swapInBytes,
+ memoryStat.rssHighWatermarkInBytes);
+ processMemoryStates.add(processMemoryState);
+ }
+ return processMemoryStates;
+ }
+
+ @Override
public int handleIncomingUser(int callingPid, int callingUid, int userId,
boolean allowAll, int allowMode, String name, String callerPackage) {
return mUserController.handleIncomingUser(callingPid, callingUid, userId, allowAll,
@@ -20763,10 +18826,6 @@ public class ActivityManagerService extends IActivityManager.Stub
ActivityManagerService.this.trimApplications();
}
- public void closeSystemDialogs(String reason) {
- ActivityManagerService.this.closeSystemDialogs(reason);
- }
-
public void killProcessesForRemovedTask(ArrayList<Object> procsToKill) {
synchronized (ActivityManagerService.this) {
for (int i = 0; i < procsToKill.size(); i++) {
@@ -20790,8 +18849,8 @@ public class ActivityManagerService extends IActivityManager.Stub
if (packageName == null) return false;
synchronized (ActivityManagerService.this) {
- for (int i = 0; i < mLruProcesses.size(); i++) {
- final ProcessRecord pr = mLruProcesses.get(i);
+ for (int i = 0; i < mProcessList.mLruProcesses.size(); i++) {
+ final ProcessRecord pr = mProcessList.mLruProcesses.get(i);
if (pr.uid != uid) {
continue;
}
@@ -20970,6 +19029,223 @@ 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);
+ }
+ }
+
+ @Override
+ public long inputDispatchingTimedOut(int pid, boolean aboveSystem, String reason) {
+ synchronized (ActivityManagerService.this) {
+ return ActivityManagerService.this.inputDispatchingTimedOut(
+ pid, aboveSystem, reason);
+ }
+ }
+
+ @Override
+ public boolean inputDispatchingTimedOut(Object proc, String activityShortComponentName,
+ ApplicationInfo aInfo, String parentShortComponentName, Object parentProc,
+ boolean aboveSystem, String reason) {
+ return ActivityManagerService.this.inputDispatchingTimedOut((ProcessRecord) proc,
+ activityShortComponentName, aInfo, parentShortComponentName,
+ (WindowProcessController) parentProc, aboveSystem, reason);
+
+ }
+
+ @Override
+ public void broadcastGlobalConfigurationChanged(int changes, boolean initLocale) {
+ synchronized (ActivityManagerService.this) {
+ Intent intent = new Intent(Intent.ACTION_CONFIGURATION_CHANGED);
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
+ | Intent.FLAG_RECEIVER_REPLACE_PENDING
+ | Intent.FLAG_RECEIVER_FOREGROUND
+ | Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS);
+ broadcastIntentLocked(null, null, intent, null, null, 0, null, null, null,
+ OP_NONE, null, false, false, MY_PID, SYSTEM_UID,
+ UserHandle.USER_ALL);
+ if ((changes & ActivityInfo.CONFIG_LOCALE) != 0) {
+ intent = new Intent(Intent.ACTION_LOCALE_CHANGED);
+ intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND
+ | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND
+ | Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS);
+ if (initLocale || !mProcessesReady) {
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+ }
+ broadcastIntentLocked(null, null, intent, null, null, 0, null, null, null,
+ OP_NONE, null, false, false, MY_PID, SYSTEM_UID,
+ UserHandle.USER_ALL);
+ }
+
+ // Send a broadcast to PackageInstallers if the configuration change is interesting
+ // for the purposes of installing additional splits.
+ if (!initLocale && isSplitConfigurationChange(changes)) {
+ intent = new Intent(Intent.ACTION_SPLIT_CONFIGURATION_CHANGED);
+ intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING
+ | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
+
+ // Typically only app stores will have this permission.
+ String[] permissions =
+ new String[] { android.Manifest.permission.INSTALL_PACKAGES };
+ broadcastIntentLocked(null, null, intent, null, null, 0, null, null,
+ permissions, OP_NONE, null, false, false, MY_PID, SYSTEM_UID,
+ UserHandle.USER_ALL);
+ }
+ }
+ }
+
+ /**
+ * Returns true if this configuration change is interesting enough to send an
+ * {@link Intent#ACTION_SPLIT_CONFIGURATION_CHANGED} broadcast.
+ */
+ private boolean isSplitConfigurationChange(int configDiff) {
+ return (configDiff & (ActivityInfo.CONFIG_LOCALE | ActivityInfo.CONFIG_DENSITY)) != 0;
+ }
+
+ @Override
+ public void broadcastCloseSystemDialogs(String reason) {
+ synchronized (ActivityManagerService.this) {
+ final Intent intent = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
+ | Intent.FLAG_RECEIVER_FOREGROUND);
+ if (reason != null) {
+ intent.putExtra("reason", reason);
+ }
+
+ broadcastIntentLocked(null, null, intent, null, null, 0, null, null, null,
+ OP_NONE, null, false, false, -1, SYSTEM_UID, UserHandle.USER_ALL);
+ }
+ }
+
+ @Override
+ public void killAllBackgroundProcessesExcept(int minTargetSdk, int maxProcState) {
+ synchronized (ActivityManagerService.this) {
+ ActivityManagerService.this.killAllBackgroundProcessesExcept(
+ minTargetSdk, maxProcState);
+ }
+ }
+
+ @Override
+ public void startProcess(String processName, ApplicationInfo info,
+ boolean knownToBeDead, String hostingType, ComponentName hostingName) {
+ synchronized (ActivityManagerService.this) {
+ startProcessLocked(processName, info, knownToBeDead, 0 /* intentFlags */,
+ hostingType, hostingName, false /* allowWhileBooting */,
+ false /* isolated */, true /* keepIfLarge */);
+ }
+ }
+
+ @Override
+ public void setDebugFlagsForStartingActivity(ActivityInfo aInfo, int startFlags,
+ ProfilerInfo profilerInfo) {
+ synchronized (ActivityManagerService.this) {
+ if ((startFlags & ActivityManager.START_FLAG_DEBUG) != 0) {
+ setDebugApp(aInfo.processName, true, false);
+ }
+
+ if ((startFlags & ActivityManager.START_FLAG_NATIVE_DEBUGGING) != 0) {
+ setNativeDebuggingAppLocked(aInfo.applicationInfo, aInfo.processName);
+ }
+
+ if ((startFlags & ActivityManager.START_FLAG_TRACK_ALLOCATION) != 0) {
+ setTrackAllocationApp(aInfo.applicationInfo, aInfo.processName);
+ }
+
+ if (profilerInfo != null) {
+ setProfileApp(aInfo.applicationInfo, aInfo.processName, profilerInfo);
+ }
+ }
+ }
+ }
+
+ long inputDispatchingTimedOut(int pid, final boolean aboveSystem, String reason) {
+ if (checkCallingPermission(FILTER_EVENTS) != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Requires permission " + FILTER_EVENTS);
+ }
+ ProcessRecord proc;
+ long timeout;
+ synchronized (this) {
+ synchronized (mPidsSelfLocked) {
+ proc = mPidsSelfLocked.get(pid);
+ }
+ timeout = proc != null ? proc.getInputDispatchingTimeout() : KEY_DISPATCHING_TIMEOUT_MS;
+ }
+
+ if (inputDispatchingTimedOut(proc, null, null, null, null, aboveSystem, reason)) {
+ return -1;
+ }
+
+ return timeout;
+ }
+
+ /**
+ * Handle input dispatching timeouts.
+ * @return whether input dispatching should be aborted or not.
+ */
+ boolean inputDispatchingTimedOut(ProcessRecord proc, String activityShortComponentName,
+ ApplicationInfo aInfo, String parentShortComponentName,
+ WindowProcessController parentProcess, boolean aboveSystem, String reason) {
+ if (checkCallingPermission(FILTER_EVENTS) != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Requires permission " + FILTER_EVENTS);
+ }
+
+ final String annotation;
+ if (reason == null) {
+ annotation = "Input dispatching timed out";
+ } else {
+ annotation = "Input dispatching timed out (" + reason + ")";
+ }
+
+ if (proc != null) {
+ synchronized (this) {
+ if (proc.isDebugging()) {
+ return false;
+ }
+
+ if (proc.getActiveInstrumentation() != null) {
+ Bundle info = new Bundle();
+ info.putString("shortMsg", "keyDispatchingTimedOut");
+ info.putString("longMsg", annotation);
+ finishInstrumentationLocked(proc, Activity.RESULT_CANCELED, info);
+ return true;
+ }
+ }
+ proc.appNotResponding(activityShortComponentName, aInfo,
+ parentShortComponentName, parentProcess, aboveSystem, annotation);
+ }
+
+ return true;
}
/**
@@ -21092,8 +19368,8 @@ public class ActivityManagerService extends IActivityManager.Stub
}
try {
synchronized(this) {
- killPackageProcessesLocked(packageName, UserHandle.getAppId(pkgUid), userId,
- ProcessList.FOREGROUND_APP_ADJ, false, true, true, false,
+ mProcessList.killPackageProcessesLocked(packageName, UserHandle.getAppId(pkgUid),
+ userId, ProcessList.FOREGROUND_APP_ADJ, false, true, true, false,
"dep: " + packageName);
}
} finally {
@@ -21123,33 +19399,9 @@ public class ActivityManagerService extends IActivityManager.Stub
void updateApplicationInfoLocked(@NonNull List<String> packagesToUpdate, int userId) {
final boolean updateFrameworkRes = packagesToUpdate.contains("android");
- for (int i = mLruProcesses.size() - 1; i >= 0; i--) {
- final ProcessRecord app = mLruProcesses.get(i);
- if (app.thread == null) {
- continue;
- }
- if (userId != UserHandle.USER_ALL && app.userId != userId) {
- continue;
- }
+ mProcessList.updateApplicationInfoLocked(packagesToUpdate, userId, updateFrameworkRes);
- final int packageCount = app.pkgList.size();
- for (int j = 0; j < packageCount; j++) {
- final String packageName = app.pkgList.keyAt(j);
- if (updateFrameworkRes || packagesToUpdate.contains(packageName)) {
- try {
- final ApplicationInfo ai = AppGlobals.getPackageManager()
- .getApplicationInfo(packageName, STOCK_PM_FLAGS, app.userId);
- if (ai != null) {
- app.thread.scheduleApplicationInfoChanged(ai);
- }
- } catch (RemoteException e) {
- Slog.w(TAG, String.format("Failed to update %s ApplicationInfo for %s",
- packageName, app));
- }
- }
- }
- }
if (updateFrameworkRes) {
// Update system server components that need to know about changed overlays. Because the
// overlay is applied in ActivityThread, we need to serialize through its thread too.
@@ -21171,7 +19423,8 @@ public class ActivityManagerService extends IActivityManager.Stub
public void attachAgent(String process, String path) {
try {
synchronized (this) {
- ProcessRecord proc = findProcessLocked(process, UserHandle.USER_SYSTEM, "attachAgent");
+ ProcessRecord proc = findProcessLocked(process, UserHandle.USER_SYSTEM,
+ "attachAgent");
if (proc == null || proc.thread == null) {
throw new IllegalArgumentException("Unknown process: " + process);
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index 40c555f8c2e6..692b2d433dbc 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;
@@ -481,12 +481,12 @@ final class ActivityManagerShellCommand extends ShellCommand {
options.setLockTaskEnabled(true);
}
if (mWaitOption) {
- result = mTaskInterface.startActivityAndWait(null, null, intent, mimeType,
+ result = mInternal.startActivityAndWait(null, null, intent, mimeType,
null, null, 0, mStartFlags, profilerInfo,
options != null ? options.toBundle() : null, mUserId);
res = result.result;
} else {
- res = mTaskInterface.startActivityAsUser(null, null, intent, mimeType,
+ res = mInternal.startActivityAsUser(null, null, intent, mimeType,
null, null, 0, mStartFlags, profilerInfo,
options != null ? options.toBundle() : null, mUserId);
}
diff --git a/services/core/java/com/android/server/am/ActivityMetricsLogger.java b/services/core/java/com/android/server/am/ActivityMetricsLogger.java
index 729182a6ace4..ae73f000e2fc 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;
@@ -111,11 +111,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.
@@ -156,7 +156,6 @@ class ActivityMetricsLogger {
private final H mHandler;
private ArtManagerInternal mArtManagerInternal;
- private boolean mDrawingTraceActive;
private final StringBuilder mStringBuilder = new StringBuilder();
public static BoostFramework mPerfFirstDraw = null;
@@ -234,14 +233,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);
@@ -355,18 +354,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;
}
@@ -375,7 +380,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;
@@ -500,7 +504,6 @@ class ActivityMetricsLogger {
if (mWindowingModeTransitionInfo.size() == 0) {
reset(true /* abort */, info);
}
- stopFullyDrawnTraceIfNeeded();
}
}
}
@@ -508,14 +511,14 @@ class ActivityMetricsLogger {
/**
* Notifies the tracker that we called immediately before we call bindApplication on the client.
*
- * @param app The client into which we'll call bindApplication.
+ * @param appInfo The client into which we'll call bindApplication.
*/
- void notifyBindApplication(ProcessRecord app) {
+ void notifyBindApplication(ApplicationInfo appInfo) {
for (int i = mWindowingModeTransitionInfo.size() - 1; i >= 0; i--) {
final WindowingModeTransitionInfo info = mWindowingModeTransitionInfo.valueAt(i);
// App isn't attached to record yet, so match with info.
- if (info.launchedActivity.appInfo == app.info) {
+ if (info.launchedActivity.appInfo == appInfo) {
info.bindApplicationDelayMs = calculateCurrentDelay();
}
}
@@ -723,6 +726,13 @@ class ActivityMetricsLogger {
if (info == null) {
return null;
}
+
+ // Record the handling of the reportFullyDrawn callback in the trace system. This is not
+ // actually used to trace this function, but instead the logical task that this function
+ // fullfils (handling reportFullyDrawn() callbacks).
+ Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
+ "ActivityManager:ReportingFullyDrawn " + info.launchedActivity.packageName);
+
final LogMaker builder = new LogMaker(APP_TRANSITION_REPORTED_DRAWN);
builder.setPackageName(r.packageName);
builder.addTaggedData(FIELD_CLASS_NAME, r.info.name);
@@ -744,7 +754,11 @@ class ActivityMetricsLogger {
info.launchedActivity.info.name,
info.currentTransitionProcessRunning,
startupTimeMs);
- stopFullyDrawnTraceIfNeeded();
+
+ // Ends the trace started at the beginning of this function. This is located here to allow
+ // the trace slice to have a noticable duration.
+ Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
+
final WindowingModeTransitionInfoSnapshot infoSnapshot =
new WindowingModeTransitionInfoSnapshot(info, r, (int) startupTimeMs);
BackgroundThread.getHandler().post(() -> logAppFullyDrawn(infoSnapshot));
@@ -765,7 +779,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,
@@ -800,31 +814,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);
@@ -911,10 +925,7 @@ class ActivityMetricsLogger {
}
/**
- * Starts traces for app launch and draw times. We stop the fully drawn trace if its already
- * active since the app may not have reported fully drawn in the previous launch.
- *
- * See {@link android.app.Activity#reportFullyDrawn()}
+ * Starts traces for app launch.
*
* @param info
* */
@@ -922,14 +933,11 @@ class ActivityMetricsLogger {
if (info == null) {
return;
}
- stopFullyDrawnTraceIfNeeded();
int transitionType = getTransitionType(info);
if (!info.launchTraceActive && transitionType == TYPE_TRANSITION_WARM_LAUNCH
|| transitionType == TYPE_TRANSITION_COLD_LAUNCH) {
Trace.asyncTraceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "launching: "
+ info.launchedActivity.packageName, 0);
- Trace.asyncTraceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "drawing", 0);
- mDrawingTraceActive = true;
info.launchTraceActive = true;
}
}
@@ -944,11 +952,4 @@ class ActivityMetricsLogger {
info.launchTraceActive = false;
}
}
-
- void stopFullyDrawnTraceIfNeeded() {
- if (mDrawingTraceActive) {
- Trace.asyncTraceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER, "drawing", 0);
- mDrawingTraceActive = false;
- }
- }
}
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 2040eadf7df3..934336dee814 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -81,20 +81,23 @@ import static android.content.res.Configuration.UI_MODE_TYPE_VR_HEADSET;
import static android.os.Build.VERSION_CODES.HONEYCOMB;
import static android.os.Build.VERSION_CODES.O;
import static android.os.Process.SYSTEM_UID;
+import static android.view.Display.INVALID_DISPLAY;
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;
@@ -112,11 +115,14 @@ import static com.android.server.am.ActivityStack.LAUNCH_TICK;
import static com.android.server.am.ActivityStack.LAUNCH_TICK_MSG;
import static com.android.server.am.ActivityStack.PAUSE_TIMEOUT_MSG;
import static com.android.server.am.ActivityStack.STOP_TIMEOUT_MSG;
+import static com.android.server.am.ActivityTaskManagerService.RELAUNCH_REASON_FREE_RESIZE;
+import static com.android.server.am.ActivityTaskManagerService.RELAUNCH_REASON_NONE;
+import static com.android.server.am.ActivityTaskManagerService.RELAUNCH_REASON_WINDOWING_MODE_RESIZE;
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;
@@ -215,12 +221,13 @@ import android.util.BoostFramework;
* 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";
@@ -343,12 +350,6 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
int mStartingWindowState = STARTING_WINDOW_NOT_SHOWN;
boolean mTaskOverlay = false; // Task is always on-top of other activities in the task.
- // This activity is not being relaunched, or being relaunched for a non-resize reason.
- static final int RELAUNCH_REASON_NONE = 0;
- // This activity is being relaunched due to windowing mode change.
- static final int RELAUNCH_REASON_WINDOWING_MODE_RESIZE = 1;
- // This activity is being relaunched due to a free-resize operation.
- static final int RELAUNCH_REASON_FREE_RESIZE = 2;
// Marking the reason why this activity is being relaunched. Mainly used to track that this
// activity is being relaunched to fulfill a resize request due to compatibility issues, e.g. in
// pre-NYC apps that don't have a sense of being resized.
@@ -885,13 +886,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;
@@ -961,8 +961,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;
}
@@ -1387,6 +1387,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
@@ -1783,7 +1819,7 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
}
setVisible(true);
sleeping = false;
- app.setPendingUiClean(true);
+ app.postPendingUiCleanMsg(true);
if (reportToClient) {
makeClientVisible();
} else {
@@ -2131,12 +2167,16 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
windowFromSameProcessAsActivity =
!hasProcess() || app.getPid() == windowPid || windowPid == -1;
}
+
if (windowFromSameProcessAsActivity) {
- return service.inputDispatchingTimedOut(anrApp, anrActivity, this, false, reason);
+ return service.mAmInternal.inputDispatchingTimedOut(anrApp.mOwner,
+ anrActivity.shortComponentName, anrActivity.appInfo, shortComponentName,
+ app, false, reason);
} else {
// In this case another process added windows using this activity token. So, we call the
// generic service input dispatch timed out method so that the right process is blamed.
- return service.inputDispatchingTimedOut(windowPid, false /* aboveSystem */, reason) < 0;
+ return service.mAmInternal.inputDispatchingTimedOut(
+ windowPid, false /* aboveSystem */, reason) < 0;
}
}
@@ -2228,12 +2268,13 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
}
/**
- * @return display id to which this record is attached, -1 if not attached.
+ * @return display id to which this record is attached,
+ * {@link android.view.Display#INVALID_DISPLAY} if not attached.
*/
int getDisplayId() {
final ActivityStack stack = getStack();
if (stack == null) {
- return -1;
+ return INVALID_DISPLAY;
}
return stack.mDisplayId;
}
@@ -2298,6 +2339,11 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
// We don't show starting window for overlay activities.
return;
}
+ if (pendingOptions != null
+ && pendingOptions.getAnimationType() == ActivityOptions.ANIM_SCENE_TRANSITION) {
+ // Don't show starting window when using shared element transition.
+ return;
+ }
final CompatibilityInfo compatInfo =
service.compatibilityInfoForPackageLocked(info.applicationInfo);
@@ -3023,17 +3069,6 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
mWindowContainerController.registerRemoteAnimations(definition);
}
- static String relaunchReasonToString(int relaunchReason) {
- switch (relaunchReason) {
- case RELAUNCH_REASON_WINDOWING_MODE_RESIZE:
- return "window_resize";
- case RELAUNCH_REASON_FREE_RESIZE:
- return "free_resize";
- default:
- return null;
- }
- }
-
@Override
public String toString() {
if (stringName != null) {
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 1c681fe165aa..37b4f24e2e15 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -48,41 +48,41 @@ 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.ActivityRecord.RELAUNCH_REASON_FREE_RESIZE;
-import static com.android.server.am.ActivityRecord.RELAUNCH_REASON_WINDOWING_MODE_RESIZE;
+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.ActivityTaskManagerService.RELAUNCH_REASON_FREE_RESIZE;
+import static com.android.server.am.ActivityTaskManagerService.RELAUNCH_REASON_WINDOWING_MODE_RESIZE;
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.FINISHING;
@@ -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;
@@ -175,7 +176,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;
@@ -230,7 +231,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
}
@Override
- protected ConfigurationContainer getChildAt(int index) {
+ protected TaskRecord getChildAt(int index) {
return mTaskHistory.get(index);
}
@@ -368,12 +369,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;
@@ -1528,8 +1529,6 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
prev.getTask().touchActiveTime();
clearLaunchTime(prev);
- mStackSupervisor.getActivityMetricsLogger().stopFullyDrawnTraceIfNeeded();
-
mService.updateCpuStats();
if (prev.attachedToProcess()) {
@@ -3504,8 +3503,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;
}
@@ -4739,7 +4740,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 533a564fb60b..4b32d073766b 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -21,8 +21,12 @@ import static android.Manifest.permission.INTERNAL_SYSTEM_WINDOW;
import static android.Manifest.permission.START_ANY_ACTIVITY;
import static android.app.ActivityManager.LOCK_TASK_MODE_LOCKED;
import static android.app.ActivityManager.START_DELIVERED_TO_TOP;
+import static android.app.ActivityManager.START_FLAG_DEBUG;
+import static android.app.ActivityManager.START_FLAG_NATIVE_DEBUGGING;
+import static android.app.ActivityManager.START_FLAG_TRACK_ALLOCATION;
import static android.app.ActivityManager.START_TASK_TO_FRONT;
import static android.app.ActivityTaskManager.INVALID_STACK_ID;
+import static android.app.ActivityTaskManager.INVALID_TASK_ID;
import static android.app.ITaskStackListener.FORCED_RESIZEABLE_REASON_SECONDARY_DISPLAY;
import static android.app.ITaskStackListener.FORCED_RESIZEABLE_REASON_SPLIT_SCREEN;
import static android.app.WaitResult.INVALID_DELAY;
@@ -53,30 +57,7 @@ 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.ActivityRecord.RELAUNCH_REASON_NONE;
+
import static com.android.server.am.ActivityStack.ActivityState.DESTROYED;
import static com.android.server.am.ActivityStack.ActivityState.INITIALIZING;
import static com.android.server.am.ActivityStack.ActivityState.PAUSED;
@@ -92,13 +73,35 @@ 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 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.ActivityTaskManagerService.RELAUNCH_REASON_NONE;
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;
@@ -113,6 +116,7 @@ import android.app.ActivityManager.StackInfo;
import android.app.ActivityManagerInternal;
import android.app.ActivityOptions;
import android.app.AppOpsManager;
+import android.app.IApplicationThread;
import android.app.ProfilerInfo;
import android.app.ResultInfo;
import android.app.WaitResult;
@@ -199,8 +203,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;
@@ -790,15 +793,16 @@ 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);
}
boolean canStartHomeOnDisplay(ActivityInfo homeActivity, int displayId) {
- if (displayId == DEFAULT_DISPLAY) {
- // No restrictions to default display.
+ if (displayId == DEFAULT_DISPLAY || (displayId != INVALID_DISPLAY
+ && displayId == mService.mVr2dDisplayId)) {
+ // No restrictions to default display or vr 2d display.
return true;
}
@@ -1002,8 +1006,8 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
return candidateTaskId;
}
- boolean attachApplicationLocked(ProcessRecord app) throws RemoteException {
- final String processName = app.processName;
+ boolean attachApplicationLocked(WindowProcessController app) throws RemoteException {
+ final String processName = app.mName;
boolean didSomething = false;
for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
final ActivityDisplay display = mActivityDisplays.get(displayNdx);
@@ -1017,7 +1021,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
final int size = mTmpActivityList.size();
for (int i = 0; i < size; i++) {
final ActivityRecord activity = mTmpActivityList.get(i);
- if (activity.app == null && app.uid == activity.info.applicationInfo.uid
+ if (activity.app == null && app.mUid == activity.info.applicationInfo.uid
&& processName.equals(activity.processName)) {
try {
if (realStartActivityLocked(activity, app,
@@ -1307,20 +1311,17 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
// Don't debug things in the system process
if (!aInfo.processName.equals("system")) {
- if ((startFlags & ActivityManager.START_FLAG_DEBUG) != 0) {
- mService.mAm.setDebugApp(aInfo.processName, true, false);
- }
-
- if ((startFlags & ActivityManager.START_FLAG_NATIVE_DEBUGGING) != 0) {
- mService.mAm.setNativeDebuggingAppLocked(aInfo.applicationInfo, aInfo.processName);
- }
-
- if ((startFlags & ActivityManager.START_FLAG_TRACK_ALLOCATION) != 0) {
- mService.mAm.setTrackAllocationApp(aInfo.applicationInfo, aInfo.processName);
- }
-
- if (profilerInfo != null) {
- mService.mAm.setProfileApp(aInfo.applicationInfo, aInfo.processName, profilerInfo);
+ if ((startFlags & (START_FLAG_DEBUG | START_FLAG_NATIVE_DEBUGGING
+ | START_FLAG_TRACK_ALLOCATION)) != 0 || profilerInfo != null) {
+ /**
+ * Assume safe to call into AMS synchronously because the call that set these
+ * flags should have originated from AMS which will already have its lock held.
+ * @see ActivityManagerService#startActivityAndWait(IApplicationThread, String,
+ * Intent, String, IBinder, String, int, int, ProfilerInfo, Bundle, int)
+ * TODO(b/80414790): Investigate a better way of untangling this.
+ */
+ mService.mAmInternal.setDebugFlagsForStartingActivity(
+ aInfo, startFlags, profilerInfo);
}
}
final String intentLaunchToken = intent.getLaunchToken();
@@ -1367,7 +1368,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
return resolveActivity(intent, rInfo, startFlags, profilerInfo);
}
- final boolean realStartActivityLocked(ActivityRecord r, ProcessRecord app,
+ private boolean realStartActivityLocked(ActivityRecord r, WindowProcessController proc,
boolean andResume, boolean checkConfig) throws RemoteException {
if (!allPausedActivitiesComplete()) {
@@ -1386,7 +1387,6 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
beginDeferResume();
try {
- final WindowProcessController proc = app.getWindowProcessController();
r.startFreezingScreenLocked(proc, 0);
// schedule launch ticks to collect information about slow apps.
@@ -1422,15 +1422,15 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
final int applicationInfoUid =
(r.info.applicationInfo != null) ? r.info.applicationInfo.uid : -1;
- if ((r.userId != app.userId) || (r.appInfo.uid != applicationInfoUid)) {
+ if ((r.userId != proc.mUserId) || (r.appInfo.uid != applicationInfoUid)) {
Slog.wtf(TAG,
"User ID for activity changing for " + r
+ " appInfo.uid=" + r.appInfo.uid
+ " info.ai.uid=" + applicationInfoUid
- + " old=" + r.app + " new=" + app);
+ + " old=" + r.app + " new=" + proc);
}
- app.waitingToKill = null;
+ proc.clearWaitingToKill();
r.launchCount++;
r.lastLaunchTime = SystemClock.uptimeMillis();
@@ -1449,7 +1449,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
}
try {
- if (app.thread == null) {
+ if (!proc.hasThread()) {
throw new RemoteException();
}
List<ResultInfo> results = null;
@@ -1475,50 +1475,29 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
r.forceNewConfig = false;
mService.getAppWarningsLocked().onStartActivity(r);
r.compat = mService.compatibilityInfoForPackageLocked(r.info.applicationInfo);
- ProfilerInfo profilerInfo = null;
- if (mService.mAm.mProfileApp != null && mService.mAm.mProfileApp.equals(app.processName)) {
- if (mService.mAm.mProfileProc == null || mService.mAm.mProfileProc == app) {
- mService.mAm.mProfileProc = app;
- ProfilerInfo profilerInfoSvc = mService.mAm.mProfilerInfo;
- if (profilerInfoSvc != null && profilerInfoSvc.profileFile != null) {
- if (profilerInfoSvc.profileFd != null) {
- try {
- profilerInfoSvc.profileFd = profilerInfoSvc.profileFd.dup();
- } catch (IOException e) {
- profilerInfoSvc.closeFd();
- }
- }
-
- profilerInfo = new ProfilerInfo(profilerInfoSvc);
- }
- }
- }
+ ProfilerInfo profilerInfo = proc.onStartActivity(mService.mTopProcessState);
- app.hasShownUi = true;
- app.pendingUiClean = 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
// we have to always create a new Configuration here.
final MergedConfiguration mergedConfiguration = new MergedConfiguration(
- app.getWindowProcessController().getConfiguration(),
- r.getMergedOverrideConfiguration());
+ proc.getConfiguration(), r.getMergedOverrideConfiguration());
r.setLastReportedConfiguration(mergedConfiguration);
logIfTransactionTooLarge(r.intent, r.icicle);
// Create activity launch transaction.
- final ClientTransaction clientTransaction = ClientTransaction.obtain(app.thread,
- r.appToken);
+ final ClientTransaction clientTransaction = ClientTransaction.obtain(
+ proc.getThread(), r.appToken);
clientTransaction.addCallback(LaunchActivityItem.obtain(new Intent(r.intent),
System.identityHashCode(r), r.info,
// TODO: Have this take the merged configuration instead of separate global
// and override configs.
mergedConfiguration.getGlobalConfiguration(),
mergedConfiguration.getOverrideConfiguration(), r.compat,
- r.launchedFromPackage, task.voiceInteractor, app.getReportedProcState(),
+ r.launchedFromPackage, task.voiceInteractor, proc.getReportedProcState(),
r.icicle, r.persistentState, results, newIntents,
mService.isNextTransitionForward(), profilerInfo));
@@ -1534,12 +1513,12 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
// Schedule transaction.
mService.getLifecycleManager().scheduleTransaction(clientTransaction);
- if ((app.info.privateFlags & ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) != 0
+ if ((proc.mInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) != 0
&& mService.mHasHeavyWeightFeature) {
// This may be a heavy-weight process! Note that the package manager will ensure
// that only activity can run in the main process of the .apk, which is the only
// thing that will be considered heavy-weight.
- if (app.processName.equals(app.info.packageName)) {
+ if (proc.mName.equals(proc.mInfo.packageName)) {
if (mService.mHeavyWeightProcess != null
&& mService.mHeavyWeightProcess != proc) {
Slog.w(TAG, "Starting new heavy weight process " + proc
@@ -1552,12 +1531,10 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
} catch (RemoteException e) {
if (r.launchFailed) {
- // This is the second time we failed -- finish activity
- // and give up.
+ // This is the second time we failed -- finish activity and give up.
Slog.e(TAG, "Second failure launching "
- + r.intent.getComponent().flattenToShortString()
- + ", giving up", e);
- mService.mAm.appDiedLocked(app);
+ + r.intent.getComponent().flattenToShortString() + ", giving up", e);
+ proc.appDied();
stack.requestFinishActivityLocked(r.appToken, Activity.RESULT_CANCELED, null,
"2nd-crash", false);
return false;
@@ -1666,24 +1643,21 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
}
}
- void startSpecificActivityLocked(ActivityRecord r,
- boolean andResume, boolean checkConfig) {
+ void startSpecificActivityLocked(ActivityRecord r, boolean andResume, boolean checkConfig) {
// Is this activity's application already running?
- ProcessRecord app = mService.mAm.getProcessRecordLocked(r.processName,
- r.info.applicationInfo.uid, true);
+ final WindowProcessController wpc =
+ mService.getProcessController(r.processName, r.info.applicationInfo.uid);
- if (app != null && app.thread != null) {
+ if (wpc != null && wpc.hasThread()) {
try {
- if ((r.info.flags&ActivityInfo.FLAG_MULTIPROCESS) == 0
+ if ((r.info.flags & ActivityInfo.FLAG_MULTIPROCESS) == 0
|| !"android".equals(r.info.packageName)) {
- // Don't add this if it is a platform component that is marked
- // to run in multiple processes, because this is actually
- // part of the framework so doesn't make sense to track as a
- // separate apk in the process.
- app.addPackage(r.info.packageName, r.info.applicationInfo.longVersionCode,
- mService.mAm.mProcessStats);
+ // Don't add this if it is a platform component that is marked to run in
+ // multiple processes, because this is actually part of the framework so doesn't
+ // make sense to track as a separate apk in the process.
+ wpc.addPackage(r.info.packageName, r.info.applicationInfo.longVersionCode);
}
- realStartActivityLocked(r, app, andResume, checkConfig);
+ realStartActivityLocked(r, wpc, andResume, checkConfig);
return;
} catch (RemoteException e) {
Slog.w(TAG, "Exception when starting activity "
@@ -1694,8 +1668,12 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
// restart the application.
}
- mService.mAm.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
- "activity", r.intent.getComponent(), false, false, true);
+ // Post message to start process to avoid possible deadlock of calling into AMS with the
+ // ATMS lock held.
+ final Message msg = PooledLambda.obtainMessage(
+ ActivityManagerInternal::startProcess, mService.mAmInternal, r.processName,
+ r.info.applicationInfo, true, "activity", r.intent.getComponent());
+ mService.mH.sendMessage(msg);
}
void sendPowerHintForLaunchStartIfNeeded(boolean forceSend, ActivityRecord targetActivity) {
@@ -1725,24 +1703,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,
@@ -2265,9 +2244,9 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
* Finish the topmost activities in all stacks that belong to the crashed app.
* @param app The app that crashed.
* @param reason Reason to perform this action.
- * @return The task that was finished in this stack, {@code null} if haven't found any.
+ * @return The task id that was finished in this stack, or INVALID_TASK_ID if none was finished.
*/
- TaskRecord finishTopCrashedActivitiesLocked(WindowProcessController app, String reason) {
+ int finishTopCrashedActivitiesLocked(WindowProcessController app, String reason) {
TaskRecord finishedTask = null;
ActivityStack focusedStack = getTopDisplayFocusedStack();
for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
@@ -2282,7 +2261,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
}
}
}
- return finishedTask;
+ return finishedTask != null ? finishedTask.taskId : INVALID_TASK_ID;
}
void finishVoiceTask(IVoiceInteractionSession session) {
@@ -2322,17 +2301,8 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
mUserLeaving = true;
}
- // TODO(b/111363427): The moving-to-top task may not be on the top display, so it could be
- // different from where the prev activity stays on.
- final ActivityRecord prev = topRunningActivityLocked();
-
- if ((flags & ActivityManager.MOVE_TASK_WITH_HOME) != 0
- || (prev != null && prev.isActivityTypeRecents())) {
- // Caller wants the home activity moved with it or the previous task is recents in which
- // case we always return home from the task we are moving to the front.
- currentStack.getDisplay().moveHomeStackToFront("findTaskToMoveToFront");
- }
-
+ reason = reason + " findTaskToMoveToFront";
+ boolean reparented = false;
if (task.isResizeable() && canUseActivityOptionsLaunchBounds(options)) {
final Rect bounds = options.getLaunchBounds();
task.updateOverrideConfiguration(bounds);
@@ -2340,10 +2310,12 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
ActivityStack stack = getLaunchStack(null, options, task, ON_TOP);
if (stack != currentStack) {
+ moveHomeStackToFrontIfNeeded(flags, stack.getDisplay(), reason);
task.reparent(stack, ON_TOP, REPARENT_KEEP_STACK_AT_FRONT, !ANIMATE, DEFER_RESUME,
- "findTaskToMoveToFront");
+ reason);
currentStack = stack;
- // moveTaskToStackUncheckedLocked() should already placed the task on top,
+ reparented = true;
+ // task.reparent() should already placed the task on top,
// still need moveTaskToFrontLocked() below for any transition settings.
}
if (stack.resizeStackWithLaunchBounds()) {
@@ -2358,6 +2330,10 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
}
}
+ if (!reparented) {
+ moveHomeStackToFrontIfNeeded(flags, currentStack.getDisplay(), reason);
+ }
+
final ActivityRecord r = task.getTopActivity();
currentStack.moveTaskToFrontLocked(task, false /* noAnimation */, options,
r == null ? null : r.appTimeTracker, reason);
@@ -2369,6 +2345,18 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
currentStack, forceNonResizeable);
}
+ private void moveHomeStackToFrontIfNeeded(int flags, ActivityDisplay display, String reason) {
+ final ActivityStack focusedStack = display.getFocusedStack();
+
+ if ((display.getWindowingMode() == WINDOWING_MODE_FULLSCREEN
+ && (flags & ActivityManager.MOVE_TASK_WITH_HOME) != 0)
+ || (focusedStack != null && focusedStack.isActivityTypeRecents())) {
+ // We move home stack to front when we are on a fullscreen display and caller has
+ // requested the home activity to move with it. Or the previous stack is recents.
+ display.moveHomeStackToFront(reason);
+ }
+ }
+
boolean canUseActivityOptionsLaunchBounds(ActivityOptions options) {
// We use the launch bounds in the activity options is the device supports freeform
// window management or is launching into the pinned stack.
@@ -2474,7 +2462,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
}
if (displayId != INVALID_DISPLAY && canLaunchOnDisplay(r, displayId)) {
if (r != null) {
- stack = (T) getValidLaunchStackOnDisplay(displayId, r, options);
+ stack = (T) getValidLaunchStackOnDisplay(displayId, r, candidateTask, options);
if (stack != null) {
return stack;
}
@@ -2539,10 +2527,11 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
* If there is no such stack, new dynamic stack can be created.
* @param displayId Target display.
* @param r Activity that should be launched there.
+ * @param candidateTask The possible task the activity might be put in.
* @return Existing stack if there is a valid one, new dynamic stack if it is valid or null.
*/
ActivityStack getValidLaunchStackOnDisplay(int displayId, @NonNull ActivityRecord r,
- @Nullable ActivityOptions options) {
+ @Nullable TaskRecord candidateTask, @Nullable ActivityOptions options) {
final ActivityDisplay activityDisplay = getActivityDisplayOrCreateLocked(displayId);
if (activityDisplay == null) {
throw new IllegalArgumentException(
@@ -2553,6 +2542,13 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
return null;
}
+ // If {@code r} is already in target display and its task is the same as the candidate task,
+ // the intention should be getting a launch stack for the reusable activity, so we can use
+ // the existing stack.
+ if (r.getDisplayId() == displayId && r.getTask() == candidateTask) {
+ return candidateTask.getStack();
+ }
+
// Return the topmost valid stack on the display.
for (int i = activityDisplay.getChildCount() - 1; i >= 0; --i) {
final ActivityStack stack = activityDisplay.getChildAt(i);
@@ -2573,6 +2569,11 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
return null;
}
+ ActivityStack getValidLaunchStackOnDisplay(int displayId, @NonNull ActivityRecord r,
+ @Nullable ActivityOptions options) {
+ return getValidLaunchStackOnDisplay(displayId, r, null /* candidateTask */, options);
+ }
+
// TODO: Can probably be consolidated into getLaunchStack()...
private boolean isValidLaunchStack(ActivityStack stack, int displayId, ActivityRecord r) {
switch (stack.getActivityType()) {
@@ -3090,7 +3091,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;
@@ -3411,7 +3414,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
return true;
}
- void acquireAppLaunchPerfLock(ActivityRecord r) {
+ void acquireAppLaunchPerfLock(String packageName) {
/* Acquire perf lock during new app launch */
if (mPerfBoost == null) {
mPerfBoost = new BoostFramework();
@@ -3521,7 +3524,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);
}
}
@@ -4529,10 +4532,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 0796f506c580..b1a912bafb85 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -53,25 +53,25 @@ 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.ActivityStack.ActivityState.RESUMED;
import static com.android.server.am.ActivityStackSupervisor.DEFER_RESUME;
import static com.android.server.am.ActivityStackSupervisor.ON_TOP;
import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS;
import static com.android.server.am.ActivityStackSupervisor.TAG_TASKS;
+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.EventLogTags.AM_NEW_INTENT;
import static com.android.server.am.TaskRecord.REPARENT_KEEP_STACK_AT_FRONT;
import static com.android.server.am.TaskRecord.REPARENT_MOVE_STACK_TO_FRONT;
@@ -128,7 +128,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;
@@ -594,12 +594,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: "
@@ -730,14 +730,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()
@@ -837,8 +835,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);
@@ -861,7 +858,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;
}
@@ -878,12 +875,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;
@@ -1089,9 +1085,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: "
@@ -1131,7 +1128,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);
}
}
}
@@ -1284,6 +1281,7 @@ class ActivityStarter {
setInitialState(r, options, inTask, doResume, startFlags, sourceRecord, voiceSession,
voiceInteractor);
+ final int preferredWindowingMode = mLaunchParams.mWindowingMode;
// Do not start home activity if it cannot be launched on preferred display. We are not
// doing this in ActivityStackSupervisor#canPlaceEntityOnDisplay because it might
@@ -1302,25 +1300,6 @@ class ActivityStarter {
ActivityRecord reusedActivity = getReusableIntentActivity();
- int preferredWindowingMode = WINDOWING_MODE_UNDEFINED;
- int preferredLaunchDisplayId = DEFAULT_DISPLAY;
- if (mOptions != null) {
- preferredWindowingMode = mOptions.getLaunchWindowingMode();
- preferredLaunchDisplayId = mOptions.getLaunchDisplayId();
- }
-
- // windowing mode and preferred launch display values from {@link LaunchParams} take
- // priority over those specified in {@link ActivityOptions}.
- if (!mLaunchParams.isEmpty()) {
- if (mLaunchParams.hasPreferredDisplay()) {
- preferredLaunchDisplayId = mLaunchParams.mPreferredDisplayId;
- }
-
- if (mLaunchParams.hasWindowingMode()) {
- preferredWindowingMode = mLaunchParams.mWindowingMode;
- }
- }
-
if (reusedActivity != null) {
// When the flags NEW_TASK and CLEAR_TASK are set, then the task gets reused but
// still needs to be a lock task mode violation since the task gets cleared out and
@@ -1467,7 +1446,7 @@ class ActivityStarter {
// Don't use mStartActivity.task to show the toast. We're not starting a new activity
// but reusing 'top'. Fields in mStartActivity may not be fully initialized.
mSupervisor.handleNonResizableTaskIfNeeded(top.getTask(), preferredWindowingMode,
- preferredLaunchDisplayId, topStack);
+ mPreferredDisplayId, topStack);
return START_DELIVERED_TO_TOP;
}
@@ -1487,7 +1466,7 @@ class ActivityStarter {
mPerf.perfHint(BoostFramework.VENDOR_HINT_FIRST_LAUNCH_BOOST,
packageName, -1, BoostFramework.Launch.BOOST_V1);
}
- result = setTaskFromReuseOrCreateNewTask(taskToAffiliate, topStack);
+ result = setTaskFromReuseOrCreateNewTask(taskToAffiliate);
} else if (mSourceRecord != null) {
result = setTaskFromSourceRecord();
} else if (mInTask != null) {
@@ -1503,8 +1482,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);
@@ -1552,7 +1532,7 @@ class ActivityStarter {
mSupervisor.updateUserStackLocked(mStartActivity.userId, mTargetStack);
mSupervisor.handleNonResizableTaskIfNeeded(mStartActivity.getTask(), preferredWindowingMode,
- preferredLaunchDisplayId, mTargetStack);
+ mPreferredDisplayId, mTargetStack);
return START_SUCCESS;
}
@@ -1616,12 +1596,16 @@ class ActivityStarter {
mVoiceSession = voiceSession;
mVoiceInteractor = voiceInteractor;
- mPreferredDisplayId = getPreferedDisplayId(mSourceRecord, mStartActivity, options);
-
mLaunchParams.reset();
- mSupervisor.getLaunchParamsController().calculate(inTask, null /*layout*/, r, sourceRecord,
- options, mLaunchParams);
+ mSupervisor.getLaunchParamsController().calculate(inTask, r.info.windowLayout, r,
+ sourceRecord, options, mLaunchParams);
+
+ if (mLaunchParams.hasPreferredDisplay()) {
+ mPreferredDisplayId = mLaunchParams.mPreferredDisplayId;
+ } else {
+ mPreferredDisplayId = DEFAULT_DISPLAY;
+ }
mLaunchMode = r.launchMode;
@@ -1893,44 +1877,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.
@@ -2135,8 +2081,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
@@ -2446,17 +2391,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 3c477f263bb3..bef05ea5e81f 100644
--- a/services/core/java/com/android/server/am/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityTaskManagerService.java
@@ -38,8 +38,11 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
+import static android.content.Intent.FLAG_ACTIVITY_TASK_ON_HOME;
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;
@@ -50,6 +53,7 @@ import static android.os.Build.VERSION_CODES.N;
import static android.os.FactoryTest.FACTORY_TEST_HIGH_LEVEL;
import static android.os.FactoryTest.FACTORY_TEST_LOW_LEVEL;
import static android.os.FactoryTest.FACTORY_TEST_OFF;
+import static android.os.Process.FIRST_APPLICATION_UID;
import static android.os.Process.SYSTEM_UID;
import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
import static android.provider.Settings.Global.ALWAYS_FINISH_ACTIVITIES;
@@ -67,29 +71,41 @@ 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.ActivityManagerServiceDumpProcessesProto.CONFIG_WILL_CHANGE;
+import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.CONTROLLER;
+import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.CURRENT_TRACKER;
+import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.Controller.IS_A_MONKEY;
+import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.GLOBAL_CONFIGURATION;
+import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.GOING_TO_SLEEP;
+import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.HEAVY_WEIGHT_PROC;
+import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.HOME_PROC;
+import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.LAUNCHING_ACTIVITY;
+import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.PREVIOUS_PROC;
+import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.PREVIOUS_PROC_VISIBLE_TIME_MS;
+import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.SCREEN_COMPAT_PACKAGES;
+import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.ScreenCompatPackage.MODE;
+import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.ScreenCompatPackage.PACKAGE;
+import static com.android.server.am.ActivityTaskManagerDebugConfig.DEBUG_ALL;
+import static com.android.server.am.ActivityManagerService.ANR_TRACE_DIR;
+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 +116,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 +157,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 +195,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 +206,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;
@@ -220,9 +238,12 @@ import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
import com.android.internal.notification.SystemNotificationChannels;
+import com.android.internal.os.TransferPipe;
import com.android.internal.os.logging.MetricsLoggerWrapper;
import com.android.internal.policy.IKeyguardDismissCallback;
import com.android.internal.policy.KeyguardDismissCallback;
+import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.FastPrintWriter;
import com.android.internal.util.Preconditions;
import com.android.internal.util.function.pooled.PooledLambda;
import com.android.server.AppOpsService;
@@ -231,6 +252,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;
@@ -238,16 +260,23 @@ import com.android.server.wm.ActivityTaskManagerInternal;
import com.android.server.wm.PinnedStackWindowController;
import com.android.server.wm.WindowManagerService;
+import java.io.BufferedReader;
import java.io.File;
+import java.io.FileDescriptor;
import java.io.FileOutputStream;
+import java.io.FileReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.ref.WeakReference;
+import java.text.DateFormat;
import java.util.ArrayList;
+import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
/**
* System service for managing activities and their containers (task, stacks, displays,... ).
@@ -255,7 +284,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;
@@ -265,16 +294,40 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
private static final String TAG_CONFIGURATION = TAG + POSTFIX_CONFIGURATION;
// How long we wait until we timeout on key dispatching.
- private static final int KEY_DISPATCHING_TIMEOUT_MS = 5 * 1000;
+ public static final int KEY_DISPATCHING_TIMEOUT_MS = 5 * 1000;
// How long we wait until we timeout on key dispatching during instrumentation.
- private static final int INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT_MS = 60 * 1000;
+ 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;
+
+ public static final String DUMP_ACTIVITIES_CMD = "activities" ;
+ public static final String DUMP_ACTIVITIES_SHORT_CMD = "a" ;
+ public static final String DUMP_LASTANR_CMD = "lastanr" ;
+ public static final String DUMP_LASTANR_TRACES_CMD = "lastanr-traces" ;
+ public static final String DUMP_STARTER_CMD = "starter" ;
+ public static final String DUMP_CONTAINERS_CMD = "containers" ;
+ public static final String DUMP_RECENTS_CMD = "recents" ;
+ public static final String DUMP_RECENTS_SHORT_CMD = "r" ;
+
+ /** This activity is not being relaunched, or being relaunched for a non-resize reason. */
+ public static final int RELAUNCH_REASON_NONE = 0;
+ /** This activity is being relaunched due to windowing mode change. */
+ public static final int RELAUNCH_REASON_WINDOWING_MODE_RESIZE = 1;
+ /** This activity is being relaunched due to a free-resize operation. */
+ public static final int RELAUNCH_REASON_FREE_RESIZE = 2;
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 +335,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;
@@ -401,6 +459,12 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
String mTopData;
/**
+ * Dump of the activity state at the time of the last ANR. Cleared after
+ * {@link WindowManagerService#LAST_ANR_LIFETIME_DURATION_MSECS}
+ */
+ String mLastANRState;
+
+ /**
* Used to retain an update lock when the foreground activity is in
* immersive mode.
*/
@@ -537,8 +601,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 +618,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 +705,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());
@@ -683,6 +752,11 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
void setWindowManager(WindowManagerService wm) {
mWindowManager = wm;
mLockTaskController.setWindowManager(wm);
+ mStackSupervisor.setWindowManager(wm);
+ }
+
+ void setUsageStatsManager(UsageStatsManagerInternal usageStatsManager) {
+ mUsageStatsInternal = usageStatsManager;
}
UserManagerService getUserManager() {
@@ -764,7 +838,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;
}
@@ -1295,7 +1369,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
Slog.i(TAG, "Removing task failed to finish activity");
}
// Explicitly dismissing the activity so reset its relaunch flag.
- r.mRelaunchReason = ActivityRecord.RELAUNCH_REASON_NONE;
+ r.mRelaunchReason = RELAUNCH_REASON_NONE;
} else {
res = tr.getStack().requestFinishActivityLocked(token, resultCode,
resultData, "app-request", true);
@@ -1707,7 +1781,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 +1802,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();
}
}
@@ -2595,7 +2669,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
pae.intent.setFlags(FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_SINGLE_TOP
| Intent.FLAG_ACTIVITY_CLEAR_TOP);
- mAmInternal.closeSystemDialogs("assist");
+ mInternal.closeSystemDialogs("assist");
try {
mContext.startActivityAsUser(pae.intent, new UserHandle(pae.userHandle));
@@ -2762,8 +2836,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 +2857,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 +2997,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 +3963,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 +3993,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 +4203,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 +4222,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);
}
}
@@ -4263,6 +4332,17 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
}
}
+ public static String relaunchReasonToString(int relaunchReason) {
+ switch (relaunchReason) {
+ case RELAUNCH_REASON_WINDOWING_MODE_RESIZE:
+ return "window_resize";
+ case RELAUNCH_REASON_FREE_RESIZE:
+ return "free_resize";
+ default:
+ return null;
+ }
+ }
+
ActivityStack getTopDisplayFocusedStack() {
return mStackSupervisor.getTopDisplayFocusedStack();
}
@@ -4287,16 +4367,177 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
|| transit == TRANSIT_TASK_TO_FRONT;
}
- void dumpSleepStates(PrintWriter pw, boolean testPssMode) {
+ void dumpLastANRLocked(PrintWriter pw) {
+ pw.println("ACTIVITY MANAGER LAST ANR (dumpsys activity lastanr)");
+ if (mLastANRState == null) {
+ pw.println(" <no ANR has occurred since boot>");
+ } else {
+ pw.println(mLastANRState);
+ }
+ }
+
+ void dumpLastANRTracesLocked(PrintWriter pw) {
+ pw.println("ACTIVITY MANAGER LAST ANR TRACES (dumpsys activity lastanr-traces)");
+
+ final File[] files = new File(ANR_TRACE_DIR).listFiles();
+ if (ArrayUtils.isEmpty(files)) {
+ pw.println(" <no ANR has occurred since boot>");
+ return;
+ }
+ // Find the latest file.
+ File latest = null;
+ for (File f : files) {
+ if ((latest == null) || (latest.lastModified() < f.lastModified())) {
+ latest = f;
+ }
+ }
+ pw.print("File: ");
+ pw.print(latest.getName());
+ pw.println();
+ try (BufferedReader in = new BufferedReader(new FileReader(latest))) {
+ String line;
+ while ((line = in.readLine()) != null) {
+ pw.println(line);
+ }
+ } catch (IOException e) {
+ pw.print("Unable to read: ");
+ pw.print(e);
+ pw.println();
+ }
+ }
+
+ void dumpActivitiesLocked(FileDescriptor fd, PrintWriter pw, String[] args,
+ int opti, boolean dumpAll, boolean dumpClient, String dumpPackage) {
+ dumpActivitiesLocked(fd, pw, args, opti, dumpAll, dumpClient, dumpPackage,
+ "ACTIVITY MANAGER ACTIVITIES (dumpsys activity activities)");
+ }
+
+ void dumpActivitiesLocked(FileDescriptor fd, PrintWriter pw, String[] args,
+ int opti, boolean dumpAll, boolean dumpClient, String dumpPackage, String header) {
+ pw.println(header);
+
+ boolean printedAnything = mStackSupervisor.dumpActivitiesLocked(fd, pw, dumpAll, dumpClient,
+ dumpPackage);
+ boolean needSep = printedAnything;
+
+ boolean printed = ActivityStackSupervisor.printThisActivity(pw,
+ mStackSupervisor.getTopResumedActivity(), dumpPackage, needSep,
+ " ResumedActivity: ");
+ if (printed) {
+ printedAnything = true;
+ needSep = false;
+ }
+
+ if (dumpPackage == null) {
+ if (needSep) {
+ pw.println();
+ }
+ printedAnything = true;
+ mStackSupervisor.dump(pw, " ");
+ }
+
+ if (!printedAnything) {
+ pw.println(" (nothing)");
+ }
+ }
+
+ void dumpActivityContainersLocked(PrintWriter pw) {
+ pw.println("ACTIVITY MANAGER STARTER (dumpsys activity containers)");
+ mStackSupervisor.dumpChildrenNames(pw, " ");
+ pw.println(" ");
+ }
+
+ void dumpActivityStarterLocked(PrintWriter pw, String dumpPackage) {
+ pw.println("ACTIVITY MANAGER STARTER (dumpsys activity starter)");
+ getActivityStartController().dump(pw, "", dumpPackage);
+ }
+
+ /**
+ * There are three things that cmd can be:
+ * - a flattened component name that matches an existing activity
+ * - the cmd arg isn't the flattened component name of an existing activity:
+ * dump all activity whose component contains the cmd as a substring
+ * - A hex number of the ActivityRecord object instance.
+ *
+ * @param dumpVisibleStacksOnly dump activity with {@param name} only if in a visible stack
+ * @param dumpFocusedStackOnly dump activity with {@param name} only if in the focused stack
+ */
+ protected boolean dumpActivity(FileDescriptor fd, PrintWriter pw, String name, String[] args,
+ int opti, boolean dumpAll, boolean dumpVisibleStacksOnly, boolean dumpFocusedStackOnly) {
+ ArrayList<ActivityRecord> activities;
+
synchronized (mGlobalLock) {
- pw.println(" mSleepTokens=" + mStackSupervisor.mSleepTokens);
- if (mRunningVoice != null) {
- pw.println(" mRunningVoice=" + mRunningVoice);
- pw.println(" mVoiceWakeLock" + mVoiceWakeLock);
+ activities = mStackSupervisor.getDumpActivitiesLocked(name, dumpVisibleStacksOnly,
+ dumpFocusedStackOnly);
+ }
+
+ if (activities.size() <= 0) {
+ return false;
+ }
+
+ String[] newArgs = new String[args.length - opti];
+ System.arraycopy(args, opti, newArgs, 0, args.length - opti);
+
+ TaskRecord lastTask = null;
+ boolean needSep = false;
+ for (int i = activities.size() - 1; i >= 0; i--) {
+ ActivityRecord r = activities.get(i);
+ if (needSep) {
+ pw.println();
+ }
+ needSep = true;
+ synchronized (mGlobalLock) {
+ final TaskRecord task = r.getTask();
+ if (lastTask != task) {
+ lastTask = task;
+ pw.print("TASK "); pw.print(lastTask.affinity);
+ pw.print(" id="); pw.print(lastTask.taskId);
+ pw.print(" userId="); pw.println(lastTask.userId);
+ if (dumpAll) {
+ lastTask.dump(pw, " ");
+ }
+ }
+ }
+ dumpActivity(" ", fd, pw, activities.get(i), newArgs, dumpAll);
+ }
+ return true;
+ }
+
+ /**
+ * Invokes IApplicationThread.dumpActivity() on the thread of the specified activity if
+ * there is a thread associated with the activity.
+ */
+ private void dumpActivity(String prefix, FileDescriptor fd, PrintWriter pw,
+ final ActivityRecord r, String[] args, boolean dumpAll) {
+ String innerPrefix = prefix + " ";
+ synchronized (mGlobalLock) {
+ pw.print(prefix); pw.print("ACTIVITY "); pw.print(r.shortComponentName);
+ pw.print(" "); pw.print(Integer.toHexString(System.identityHashCode(r)));
+ pw.print(" pid=");
+ if (r.hasProcess()) pw.println(r.app.getPid());
+ else pw.println("(not running)");
+ if (dumpAll) {
+ r.dump(pw, innerPrefix);
+ }
+ }
+ if (r.attachedToProcess()) {
+ // flush anything that is already in the PrintWriter since the thread is going
+ // to write to the file descriptor directly
+ pw.flush();
+ try {
+ TransferPipe tp = new TransferPipe();
+ try {
+ r.app.getThread().dumpActivity(tp.getWriteFd(),
+ r.appToken, innerPrefix, args);
+ tp.go(fd);
+ } finally {
+ tp.kill();
+ }
+ } catch (IOException e) {
+ pw.println(innerPrefix + "Failure while dumping the activity: " + e);
+ } catch (RemoteException e) {
+ pw.println(innerPrefix + "Got a RemoteException while dumping the activity");
}
- pw.println(" mSleeping=" + mSleeping);
- pw.println(" mShuttingDown=" + mShuttingDown + " mTestPssMode=" + testPssMode);
- pw.println(" mVrController=" + mVrController);
}
}
@@ -4429,14 +4670,6 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
return kept;
}
- /**
- * Returns true if this configuration change is interesting enough to send an
- * {@link Intent#ACTION_SPLIT_CONFIGURATION_CHANGED} broadcast.
- */
- private static boolean isSplitConfigurationChange(int configDiff) {
- return (configDiff & (ActivityInfo.CONFIG_LOCALE | ActivityInfo.CONFIG_DENSITY)) != 0;
- }
-
/** Update default (global) configuration and notify listeners about changes. */
private int updateGlobalConfigurationLocked(@NonNull Configuration values, boolean initLocale,
boolean persistent, int userId, boolean deferResume) {
@@ -4487,8 +4720,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 +4734,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,65 +4748,31 @@ 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);
- }
- }
-
- Intent intent = new Intent(Intent.ACTION_CONFIGURATION_CHANGED);
- intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_REPLACE_PENDING
- | Intent.FLAG_RECEIVER_FOREGROUND
- | Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS);
- mAm.broadcastIntentLocked(null, null, intent, null, null, 0, null, null, null,
- OP_NONE, null, false, false, MY_PID, SYSTEM_UID,
- UserHandle.USER_ALL);
- if ((changes & ActivityInfo.CONFIG_LOCALE) != 0) {
- intent = new Intent(Intent.ACTION_LOCALE_CHANGED);
- intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND
- | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND
- | Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS);
- if (initLocale || !mAm.mProcessesReady) {
- intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
- }
- mAm.broadcastIntentLocked(null, null, intent, null, null, 0, null, null, null,
- OP_NONE, null, false, false, MY_PID, SYSTEM_UID,
- UserHandle.USER_ALL);
+ 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);
}
- // Send a broadcast to PackageInstallers if the configuration change is interesting
- // for the purposes of installing additional splits.
- if (!initLocale && isSplitConfigurationChange(changes)) {
- intent = new Intent(Intent.ACTION_SPLIT_CONFIGURATION_CHANGED);
- intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING
- | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
-
- // Typically only app stores will have this permission.
- String[] permissions = new String[] { android.Manifest.permission.INSTALL_PACKAGES };
- mAm.broadcastIntentLocked(null, null, intent, null, null, 0, null, null, permissions,
- OP_NONE, null, false, false, MY_PID, SYSTEM_UID, UserHandle.USER_ALL);
- }
+ final Message msg = PooledLambda.obtainMessage(
+ ActivityManagerInternal::broadcastGlobalConfigurationChanged,
+ mAmInternal, changes, initLocale);
+ mH.sendMessage(msg);
// Override configuration of the default display duplicates global config, so we need to
// update it also. This will also notify WindowManager about changes.
@@ -4640,8 +4841,12 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
if (isDensityChange && displayId == DEFAULT_DISPLAY) {
mAppWarnings.onDensityChanged();
- mAm.killAllBackgroundProcessesExcept(N,
- ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE);
+ // Post message to start process to avoid possible deadlock of calling into AMS with
+ // the ATMS lock held.
+ final Message msg = PooledLambda.obtainMessage(
+ ActivityManagerInternal::killAllBackgroundProcessesExcept, mAmInternal,
+ N, ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE);
+ mH.sendMessage(msg);
}
}
@@ -4666,6 +4871,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());
@@ -4693,70 +4918,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
}
private static long getInputDispatchingTimeoutLocked(WindowProcessController r) {
- if (r != null && (r.isInstrumenting() || r.isUsingWrapper())) {
- return INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT_MS;
- }
- return KEY_DISPATCHING_TIMEOUT_MS;
- }
-
- long inputDispatchingTimedOut(int pid, final boolean aboveSystem, String reason) {
- if (checkCallingPermission(FILTER_EVENTS) != PackageManager.PERMISSION_GRANTED) {
- throw new SecurityException("Requires permission " + FILTER_EVENTS);
- }
- WindowProcessController proc;
- long timeout;
- synchronized (mGlobalLock) {
- proc = mPidMap.get(pid);
- timeout = getInputDispatchingTimeoutLocked(proc);
- }
-
- if (inputDispatchingTimedOut(proc, null, null, aboveSystem, reason)) {
- return -1;
- }
-
- return timeout;
- }
-
- /**
- * Handle input dispatching timeouts.
- * Returns whether input dispatching should be aborted or not.
- */
- boolean inputDispatchingTimedOut(final WindowProcessController proc,
- final ActivityRecord activity, final ActivityRecord parent,
- final boolean aboveSystem, String reason) {
- if (checkCallingPermission(FILTER_EVENTS) != PackageManager.PERMISSION_GRANTED) {
- throw new SecurityException("Requires permission " + FILTER_EVENTS);
- }
-
- final String annotation;
- if (reason == null) {
- annotation = "Input dispatching timed out";
- } else {
- annotation = "Input dispatching timed out (" + reason + ")";
- }
-
- if (proc != null) {
- synchronized (mGlobalLock) {
- if (proc.isDebugging()) {
- return false;
- }
-
- if (proc.isInstrumenting()) {
- Bundle info = new Bundle();
- info.putString("shortMsg", "keyDispatchingTimedOut");
- info.putString("longMsg", annotation);
- mAm.finishInstrumentationLocked(
- (ProcessRecord) proc.mOwner, Activity.RESULT_CANCELED, info);
- return true;
- }
- }
- mH.post(() -> {
- mAm.mAppErrors.appNotResponding(
- (ProcessRecord) proc.mOwner, activity, parent, aboveSystem, annotation);
- });
- }
-
- return true;
+ return r != null ? r.getInputDispatchingTimeout() : KEY_DISPATCHING_TIMEOUT_MS;
}
/**
@@ -5261,7 +5423,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
return newInfo;
}
- private WindowProcessController getProcessController(String processName, int uid) {
+ WindowProcessController getProcessController(String processName, int uid) {
if (uid == SYSTEM_UID) {
// The system gets to run in any process. If there are multiple processes with the same
// uid, just pick the first (this should never happen).
@@ -5282,6 +5444,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;
@@ -5343,6 +5525,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);
@@ -5563,7 +5747,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();
}
}
@@ -5779,14 +5963,6 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
}
@Override
- public long inputDispatchingTimedOut(int pid, boolean aboveSystem, String reason) {
- synchronized (mGlobalLock) {
- return ActivityTaskManagerService.this.inputDispatchingTimedOut(
- pid, aboveSystem, reason);
- }
- }
-
- @Override
public void onProcessMapped(int pid, WindowProcessController proc) {
synchronized (mGlobalLock) {
mPidMap.put(pid, proc);
@@ -5824,6 +6000,13 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
}
@Override
+ public void onPackageReplaced(ApplicationInfo aInfo) {
+ synchronized (mGlobalLock) {
+ mStackSupervisor.updateActivityApplicationInfoLocked(aInfo);
+ }
+ }
+
+ @Override
public CompatibilityInfo compatibilityInfoForPackage(ApplicationInfo ai) {
synchronized (mGlobalLock) {
return compatibilityInfoForPackageLocked(ai);
@@ -5987,9 +6170,471 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
mUiHandler.post(() -> {
Dialog d = new FactoryErrorDialog(mUiContext, errorMsg);
d.show();
- mAm.ensureBootCompleted();
+ mAmInternal.ensureBootCompleted();
});
}
}
+
+ @Override
+ public void handleAppDied(WindowProcessController wpc, boolean restarting,
+ Runnable finishInstrumentationCallback) {
+ synchronized (mGlobalLock) {
+ // Remove this application's activities from active lists.
+ boolean hasVisibleActivities = mStackSupervisor.handleAppDiedLocked(wpc);
+
+ wpc.clearRecentTasks();
+ wpc.clearActivities();
+
+ if (wpc.isInstrumenting()) {
+ finishInstrumentationCallback.run();
+ }
+
+ mWindowManager.deferSurfaceLayout();
+ try {
+ if (!restarting && hasVisibleActivities
+ && !mStackSupervisor.resumeFocusedStacksTopActivitiesLocked()) {
+ // If there was nothing to resume, and we are not already restarting this
+ // process, but there is a visible activity that is hosted by the process...
+ // then make sure all visible activities are running, taking care of
+ // restarting this process.
+ mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
+ }
+ } finally {
+ mWindowManager.continueSurfaceLayout();
+ }
+ }
+ }
+
+ @Override
+ public void closeSystemDialogs(String reason) {
+ enforceNotIsolatedCaller("closeSystemDialogs");
+
+ final int pid = Binder.getCallingPid();
+ final int uid = Binder.getCallingUid();
+ final long origId = Binder.clearCallingIdentity();
+ try {
+ synchronized (mGlobalLock) {
+ // Only allow this from foreground processes, so that background
+ // applications can't abuse it to prevent system UI from being shown.
+ if (uid >= FIRST_APPLICATION_UID) {
+ final WindowProcessController proc = mPidMap.get(pid);
+ if (!proc.isPerceptible()) {
+ Slog.w(TAG, "Ignoring closeSystemDialogs " + reason
+ + " from background process " + proc);
+ return;
+ }
+ }
+ mWindowManager.closeSystemDialogs(reason);
+
+ mStackSupervisor.closeSystemDialogsLocked();
+ }
+ // Call into AM outside the synchronized block.
+ mAmInternal.broadcastCloseSystemDialogs(reason);
+ } finally {
+ Binder.restoreCallingIdentity(origId);
+ }
+ }
+
+ @Override
+ public void cleanupDisabledPackageComponents(
+ String packageName, Set<String> disabledClasses, int userId, boolean booted) {
+ synchronized (mGlobalLock) {
+ // Clean-up disabled activities.
+ if (mStackSupervisor.finishDisabledPackageActivitiesLocked(
+ packageName, disabledClasses, true, false, userId) && booted) {
+ mStackSupervisor.resumeFocusedStacksTopActivitiesLocked();
+ mStackSupervisor.scheduleIdleLocked();
+ }
+
+ // Clean-up disabled tasks
+ getRecentTasks().cleanupDisabledPackageTasksLocked(
+ packageName, disabledClasses, userId);
+ }
+ }
+
+ @Override
+ public boolean onForceStopPackage(String packageName, boolean doit, boolean evenPersistent,
+ int userId) {
+ synchronized (mGlobalLock) {
+
+ boolean didSomething =
+ getActivityStartController().clearPendingActivityLaunches(packageName);
+ didSomething |= mStackSupervisor.finishDisabledPackageActivitiesLocked(packageName,
+ null, doit, evenPersistent, userId);
+ return didSomething;
+ }
+ }
+
+ @Override
+ public void resumeTopActivities(boolean scheduleIdle) {
+ synchronized (mGlobalLock) {
+ mStackSupervisor.resumeFocusedStacksTopActivitiesLocked();
+ if (scheduleIdle) {
+ mStackSupervisor.scheduleIdleLocked();
+ }
+ }
+ }
+
+ @Override
+ public void preBindApplication(WindowProcessController wpc) {
+ synchronized (mGlobalLock) {
+ mStackSupervisor.getActivityMetricsLogger().notifyBindApplication(wpc.mInfo);
+ }
+ }
+
+ @Override
+ public boolean attachApplication(WindowProcessController wpc) throws RemoteException {
+ synchronized (mGlobalLock) {
+ return mStackSupervisor.attachApplicationLocked(wpc);
+ }
+ }
+
+ @Override
+ public void notifyLockedProfile(@UserIdInt int userId, int currentUserId) {
+ try {
+ if (!AppGlobals.getPackageManager().isUidPrivileged(Binder.getCallingUid())) {
+ throw new SecurityException("Only privileged app can call notifyLockedProfile");
+ }
+ } catch (RemoteException ex) {
+ throw new SecurityException("Fail to check is caller a privileged app", ex);
+ }
+
+ synchronized (mGlobalLock) {
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ if (mAmInternal.shouldConfirmCredentials(userId)) {
+ if (mKeyguardController.isKeyguardLocked()) {
+ // Showing launcher to avoid user entering credential twice.
+ startHomeActivity(currentUserId, "notifyLockedProfile");
+ }
+ mStackSupervisor.lockAllProfileTasks(userId);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+ }
+
+ @Override
+ public void startConfirmDeviceCredentialIntent(Intent intent, Bundle options) {
+ mAmInternal.enforceCallingPermission(
+ MANAGE_ACTIVITY_STACKS, "startConfirmDeviceCredentialIntent");
+
+ synchronized (mGlobalLock) {
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ intent.addFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS |
+ FLAG_ACTIVITY_TASK_ON_HOME);
+ ActivityOptions activityOptions = options != null
+ ? new ActivityOptions(options) : ActivityOptions.makeBasic();
+ activityOptions.setLaunchTaskId(
+ mStackSupervisor.getDefaultDisplayHomeActivity().getTask().taskId);
+ mContext.startActivityAsUser(intent, activityOptions.toBundle(),
+ UserHandle.CURRENT);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+ }
+
+ @Override
+ public void writeActivitiesToProto(ProtoOutputStream proto) {
+ synchronized (mGlobalLock) {
+ // The output proto of "activity --proto activities"
+ // is ActivityManagerServiceDumpActivitiesProto
+ mStackSupervisor.writeToProto(proto,
+ ActivityManagerServiceDumpActivitiesProto.ACTIVITY_STACK_SUPERVISOR);
+ }
+ }
+
+ @Override
+ public void saveANRState(String reason) {
+ synchronized (mGlobalLock) {
+ final StringWriter sw = new StringWriter();
+ final PrintWriter pw = new FastPrintWriter(sw, false, 1024);
+ pw.println(" ANR time: " + DateFormat.getDateTimeInstance().format(new Date()));
+ if (reason != null) {
+ pw.println(" Reason: " + reason);
+ }
+ pw.println();
+ getActivityStartController().dump(pw, " ", null);
+ pw.println();
+ pw.println("-------------------------------------------------------------------------------");
+ dumpActivitiesLocked(null /* fd */, pw, null /* args */, 0 /* opti */,
+ true /* dumpAll */, false /* dumpClient */, null /* dumpPackage */,
+ "" /* header */);
+ pw.println();
+ pw.close();
+
+ mLastANRState = sw.toString();
+ }
+ }
+
+ @Override
+ public void clearSavedANRState() {
+ synchronized (mGlobalLock) {
+ mLastANRState = null;
+ }
+ }
+
+ @Override
+ public void dump(String cmd, FileDescriptor fd, PrintWriter pw, String[] args, int opti,
+ boolean dumpAll, boolean dumpClient, String dumpPackage) {
+ synchronized (mGlobalLock) {
+ if (DUMP_ACTIVITIES_CMD.equals(cmd) || DUMP_ACTIVITIES_SHORT_CMD.equals(cmd)) {
+ dumpActivitiesLocked(fd, pw, args, opti, dumpAll, dumpClient, dumpPackage);
+ } else if (DUMP_LASTANR_CMD.equals(cmd)) {
+ dumpLastANRLocked(pw);
+ } else if (DUMP_LASTANR_TRACES_CMD.equals(cmd)) {
+ dumpLastANRTracesLocked(pw);
+ } else if (DUMP_STARTER_CMD.equals(cmd)) {
+ dumpActivityStarterLocked(pw, dumpPackage);
+ } else if (DUMP_CONTAINERS_CMD.equals(cmd)) {
+ dumpActivityContainersLocked(pw);
+ } else if (DUMP_RECENTS_CMD.equals(cmd) || DUMP_RECENTS_SHORT_CMD.equals(cmd)) {
+ if (getRecentTasks() != null) {
+ getRecentTasks().dump(pw, dumpAll, dumpPackage);
+ }
+ }
+ }
+ }
+
+ @Override
+ public boolean dumpForProcesses(FileDescriptor fd, PrintWriter pw, boolean dumpAll,
+ String dumpPackage, int dumpAppId, boolean needSep, boolean testPssMode,
+ int wakefulness) {
+ synchronized (mGlobalLock) {
+ if (mHomeProcess != null && (dumpPackage == null
+ || mHomeProcess.mPkgList.contains(dumpPackage))) {
+ if (needSep) {
+ pw.println();
+ needSep = false;
+ }
+ pw.println(" mHomeProcess: " + mHomeProcess);
+ }
+ if (mPreviousProcess != null && (dumpPackage == null
+ || mPreviousProcess.mPkgList.contains(dumpPackage))) {
+ if (needSep) {
+ pw.println();
+ needSep = false;
+ }
+ pw.println(" mPreviousProcess: " + mPreviousProcess);
+ }
+ if (dumpAll && (mPreviousProcess == null || dumpPackage == null
+ || mPreviousProcess.mPkgList.contains(dumpPackage))) {
+ StringBuilder sb = new StringBuilder(128);
+ sb.append(" mPreviousProcessVisibleTime: ");
+ TimeUtils.formatDuration(mPreviousProcessVisibleTime, sb);
+ pw.println(sb);
+ }
+ if (mHeavyWeightProcess != null && (dumpPackage == null
+ || mHeavyWeightProcess.mPkgList.contains(dumpPackage))) {
+ if (needSep) {
+ pw.println();
+ needSep = false;
+ }
+ pw.println(" mHeavyWeightProcess: " + mHeavyWeightProcess);
+ }
+ if (dumpPackage == null) {
+ pw.println(" mGlobalConfiguration: " + getGlobalConfiguration());
+ mStackSupervisor.dumpDisplayConfigs(pw, " ");
+ }
+ if (dumpAll) {
+ if (dumpPackage == null) {
+ pw.println(" mConfigWillChange: "
+ + getTopDisplayFocusedStack().mConfigWillChange);
+ }
+ if (mCompatModePackages.getPackages().size() > 0) {
+ boolean printed = false;
+ for (Map.Entry<String, Integer> entry
+ : mCompatModePackages.getPackages().entrySet()) {
+ String pkg = entry.getKey();
+ int mode = entry.getValue();
+ if (dumpPackage != null && !dumpPackage.equals(pkg)) {
+ continue;
+ }
+ if (!printed) {
+ pw.println(" mScreenCompatPackages:");
+ printed = true;
+ }
+ pw.println(" " + pkg + ": " + mode);
+ }
+ }
+ }
+
+ if (dumpPackage == null) {
+ pw.println(" mWakefulness="
+ + PowerManagerInternal.wakefulnessToString(wakefulness));
+ pw.println(" mSleepTokens=" + mStackSupervisor.mSleepTokens);
+ if (mRunningVoice != null) {
+ pw.println(" mRunningVoice=" + mRunningVoice);
+ pw.println(" mVoiceWakeLock" + mVoiceWakeLock);
+ }
+ pw.println(" mSleeping=" + mSleeping);
+ pw.println(" mShuttingDown=" + mShuttingDown + " mTestPssMode=" + testPssMode);
+ pw.println(" mVrController=" + mVrController);
+ }
+ if (mCurAppTimeTracker != null) {
+ mCurAppTimeTracker.dumpWithHeader(pw, " ", true);
+ }
+ if (mAllowAppSwitchUids.size() > 0) {
+ boolean printed = false;
+ for (int i = 0; i < mAllowAppSwitchUids.size(); i++) {
+ ArrayMap<String, Integer> types = mAllowAppSwitchUids.valueAt(i);
+ for (int j = 0; j < types.size(); j++) {
+ if (dumpPackage == null ||
+ UserHandle.getAppId(types.valueAt(j).intValue()) == dumpAppId) {
+ if (needSep) {
+ pw.println();
+ needSep = false;
+ }
+ if (!printed) {
+ pw.println(" mAllowAppSwitchUids:");
+ printed = true;
+ }
+ pw.print(" User ");
+ pw.print(mAllowAppSwitchUids.keyAt(i));
+ pw.print(": Type ");
+ pw.print(types.keyAt(j));
+ pw.print(" = ");
+ UserHandle.formatUid(pw, types.valueAt(j).intValue());
+ pw.println();
+ }
+ }
+ }
+ }
+ if (dumpPackage == null) {
+ if (mController != null) {
+ pw.println(" mController=" + mController
+ + " mControllerIsAMonkey=" + mControllerIsAMonkey);
+ }
+ pw.println(" mGoingToSleep=" + mStackSupervisor.mGoingToSleep);
+ pw.println(" mLaunchingActivity=" + mStackSupervisor.mLaunchingActivity);
+ }
+
+ return needSep;
+ }
+ }
+
+ @Override
+ public void writeProcessesToProto(ProtoOutputStream proto, String dumpPackage) {
+ synchronized (mGlobalLock) {
+ if (dumpPackage == null) {
+ getGlobalConfiguration().writeToProto(proto, GLOBAL_CONFIGURATION);
+ proto.write(CONFIG_WILL_CHANGE, getTopDisplayFocusedStack().mConfigWillChange);
+ writeSleepStateToProto(proto);
+ if (mController != null) {
+ final long token = proto.start(CONTROLLER);
+ proto.write(CONTROLLER, mController.toString());
+ proto.write(IS_A_MONKEY, mControllerIsAMonkey);
+ proto.end(token);
+ }
+ mStackSupervisor.mGoingToSleep.writeToProto(proto, GOING_TO_SLEEP);
+ mStackSupervisor.mLaunchingActivity.writeToProto(proto, LAUNCHING_ACTIVITY);
+ }
+
+ if (mHomeProcess != null && (dumpPackage == null
+ || mHomeProcess.mPkgList.contains(dumpPackage))) {
+ mHomeProcess.writeToProto(proto, HOME_PROC);
+ }
+
+ if (mPreviousProcess != null && (dumpPackage == null
+ || mPreviousProcess.mPkgList.contains(dumpPackage))) {
+ mPreviousProcess.writeToProto(proto, PREVIOUS_PROC);
+ proto.write(PREVIOUS_PROC_VISIBLE_TIME_MS, mPreviousProcessVisibleTime);
+ }
+
+ if (mHeavyWeightProcess != null && (dumpPackage == null
+ || mHeavyWeightProcess.mPkgList.contains(dumpPackage))) {
+ mHeavyWeightProcess.writeToProto(proto, HEAVY_WEIGHT_PROC);
+ }
+
+ for (Map.Entry<String, Integer> entry
+ : mCompatModePackages.getPackages().entrySet()) {
+ String pkg = entry.getKey();
+ int mode = entry.getValue();
+ if (dumpPackage == null || dumpPackage.equals(pkg)) {
+ long compatToken = proto.start(SCREEN_COMPAT_PACKAGES);
+ proto.write(PACKAGE, pkg);
+ proto.write(MODE, mode);
+ proto.end(compatToken);
+ }
+ }
+
+ if (mCurAppTimeTracker != null) {
+ mCurAppTimeTracker.writeToProto(proto, CURRENT_TRACKER, true);
+ }
+
+ }
+ }
+
+ @Override
+ public boolean dumpActivity(FileDescriptor fd, PrintWriter pw, String name,
+ String[] args, int opti, boolean dumpAll, boolean dumpVisibleStacksOnly,
+ boolean dumpFocusedStackOnly) {
+ synchronized (mGlobalLock) {
+ return ActivityTaskManagerService.this.dumpActivity(fd, pw, name, args, opti,
+ dumpAll, dumpVisibleStacksOnly, dumpFocusedStackOnly);
+ }
+ }
+
+ @Override
+ public boolean canGcNow() {
+ synchronized (mGlobalLock) {
+ return isSleeping() || mStackSupervisor.allResumedActivitiesIdle();
+ }
+ }
+
+ @Override
+ public WindowProcessController getTopApp() {
+ synchronized (mGlobalLock) {
+ final ActivityRecord top = mStackSupervisor.getTopResumedActivity();
+ return top != null ? top.app : null;
+ }
+ }
+
+ @Override
+ public void rankTaskLayersIfNeeded() {
+ synchronized (mGlobalLock) {
+ if (mStackSupervisor != null) {
+ mStackSupervisor.rankTaskLayersIfNeeded();
+ }
+ }
+ }
+
+ @Override
+ public void scheduleDestroyAllActivities(String reason) {
+ synchronized (mGlobalLock) {
+ mStackSupervisor.scheduleDestroyAllActivities(null, reason);
+ }
+ }
+
+ @Override
+ public void removeUser(int userId) {
+ synchronized (mGlobalLock) {
+ mStackSupervisor.removeUserLocked(userId);
+ }
+ }
+
+ @Override
+ public boolean switchUser(int userId, UserState userState) {
+ synchronized (mGlobalLock) {
+ return mStackSupervisor.switchUserLocked(userId, userState);
+ }
+ }
+
+ @Override
+ public void onHandleAppCrash(WindowProcessController wpc) {
+ synchronized (mGlobalLock) {
+ mStackSupervisor.handleAppCrashLocked(wpc);
+ }
+ }
+
+ @Override
+ public int finishTopCrashedActivities(WindowProcessController crashedApp, String reason) {
+ synchronized (mGlobalLock) {
+ return mStackSupervisor.finishTopCrashedActivitiesLocked(crashedApp, reason);
+ }
+ }
}
}
diff --git a/services/core/java/com/android/server/am/AppErrorDialog.java b/services/core/java/com/android/server/am/AppErrorDialog.java
index cde633dddb3b..a80a5b5211ea 100644
--- a/services/core/java/com/android/server/am/AppErrorDialog.java
+++ b/services/core/java/com/android/server/am/AppErrorDialog.java
@@ -16,6 +16,8 @@
package com.android.server.am;
+import static android.app.ActivityTaskManager.INVALID_TASK_ID;
+
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -63,7 +65,7 @@ final class AppErrorDialog extends BaseErrorDialog implements View.OnClickListen
mService = service;
mProc = data.proc;
mResult = data.result;
- mIsRestartable = (data.task != null || data.isRestartableForService)
+ mIsRestartable = (data.taskId != INVALID_TASK_ID || data.isRestartableForService)
&& Settings.Global.getInt(context.getContentResolver(),
Settings.Global.SHOW_RESTART_IN_CRASH_DIALOG, 0) != 0;
BidiFormatter bidi = BidiFormatter.getInstance();
@@ -209,7 +211,7 @@ final class AppErrorDialog extends BaseErrorDialog implements View.OnClickListen
static class Data {
AppErrorResult result;
- TaskRecord task;
+ int taskId;
boolean repeating;
ProcessRecord proc;
boolean isRestartableForService;
diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java
index 6a9c8877ce5b..e8ec0574610c 100644
--- a/services/core/java/com/android/server/am/AppErrors.java
+++ b/services/core/java/com/android/server/am/AppErrors.java
@@ -16,12 +16,13 @@
package com.android.server.am;
-import static com.android.server.Watchdog.NATIVE_STACKS_OF_INTEREST;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ANR;
+import static android.app.ActivityTaskManager.INVALID_TASK_ID;
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.MY_PID;
import static com.android.server.am.ActivityManagerService.SYSTEM_DEBUGGABLE;
+import static com.android.server.am.ActivityTaskManagerService.RELAUNCH_REASON_FREE_RESIZE;
+import static com.android.server.am.ActivityTaskManagerService.RELAUNCH_REASON_NONE;
import android.app.ActivityManager;
import android.app.ActivityOptions;
@@ -46,21 +47,17 @@ import android.util.ArraySet;
import android.util.EventLog;
import android.util.Slog;
import android.util.SparseArray;
-import android.util.StatsLog;
import android.util.TimeUtils;
import android.util.proto.ProtoOutputStream;
import com.android.internal.app.ProcessMap;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto;
-import com.android.internal.os.ProcessCpuTracker;
import com.android.server.RescueParty;
import com.android.server.Watchdog;
-import java.io.File;
import java.io.FileDescriptor;
import java.io.PrintWriter;
-import java.util.ArrayList;
import java.util.Collections;
import java.util.Set;
@@ -124,7 +121,7 @@ class AppErrors {
proto.write(AppErrorsProto.ProcessCrashTime.PROCESS_NAME, pname);
for (int i = 0; i < uidCount; i++) {
final int puid = uids.keyAt(i);
- final ProcessRecord r = mService.mProcessNames.get(pname, puid);
+ final ProcessRecord r = mService.getProcessNames().get(pname, puid);
if (dumpPackage != null && (r == null || !r.pkgList.containsKey(dumpPackage))) {
continue;
}
@@ -151,7 +148,7 @@ class AppErrors {
proto.write(AppErrorsProto.BadProcess.PROCESS_NAME, pname);
for (int i = 0; i < uidCount; i++) {
final int puid = uids.keyAt(i);
- final ProcessRecord r = mService.mProcessNames.get(pname, puid);
+ final ProcessRecord r = mService.getProcessNames().get(pname, puid);
if (dumpPackage != null && (r == null
|| !r.pkgList.containsKey(dumpPackage))) {
continue;
@@ -184,7 +181,7 @@ class AppErrors {
final int uidCount = uids.size();
for (int i = 0; i < uidCount; i++) {
final int puid = uids.keyAt(i);
- final ProcessRecord r = mService.mProcessNames.get(pname, puid);
+ final ProcessRecord r = mService.getProcessNames().get(pname, puid);
if (dumpPackage != null && (r == null
|| !r.pkgList.containsKey(dumpPackage))) {
continue;
@@ -214,7 +211,7 @@ class AppErrors {
final int uidCount = uids.size();
for (int i = 0; i < uidCount; i++) {
final int puid = uids.keyAt(i);
- final ProcessRecord r = mService.mProcessNames.get(pname, puid);
+ final ProcessRecord r = mService.getProcessNames().get(pname, puid);
if (dumpPackage != null && (r == null
|| !r.pkgList.containsKey(dumpPackage))) {
continue;
@@ -411,11 +408,10 @@ class AppErrors {
}
final int relaunchReason = r != null
- ? r.getWindowProcessController().computeRelaunchReason()
- : ActivityRecord.RELAUNCH_REASON_NONE;
+ ? r.getWindowProcessController().computeRelaunchReason() : RELAUNCH_REASON_NONE;
AppErrorResult result = new AppErrorResult();
- TaskRecord task;
+ int taskId;
synchronized (mService) {
/**
* If crash is handled by instance of {@link android.app.IActivityController},
@@ -428,7 +424,7 @@ class AppErrors {
// Suppress crash dialog if the process is being relaunched due to a crash during a free
// resize.
- if (relaunchReason == ActivityRecord.RELAUNCH_REASON_FREE_RESIZE) {
+ if (relaunchReason == RELAUNCH_REASON_FREE_RESIZE) {
return;
}
@@ -458,7 +454,7 @@ class AppErrors {
final Message msg = Message.obtain();
msg.what = ActivityManagerService.SHOW_ERROR_UI_MSG;
- task = data.task;
+ taskId = data.taskId;
msg.obj = data;
mService.mUiHandler.sendMessage(msg);
}
@@ -475,25 +471,15 @@ class AppErrors {
stopReportingCrashesLocked(r);
}
if (res == AppErrorDialog.RESTART) {
- mService.removeProcessLocked(r, false, true, "crash");
- if (task != null) {
+ mService.mProcessList.removeProcessLocked(r, false, true, "crash");
+ if (taskId != INVALID_TASK_ID) {
try {
- mService.mActivityTaskManager.startActivityFromRecents(task.taskId,
+ mService.mActivityTaskManager.startActivityFromRecents(taskId,
ActivityOptions.makeBasic().toBundle());
} catch (IllegalArgumentException e) {
- // Hmm, that didn't work, app might have crashed before creating a
- // recents entry. Let's see if we have a safe-to-restart intent.
- final Set<String> cats = task.intent != null
- ? task.intent.getCategories() : null;
- if (cats != null && cats.contains(Intent.CATEGORY_LAUNCHER)) {
- mService.mActivityTaskManager.getActivityStartController().startActivityInPackage(
- task.mCallingUid, callingPid, callingUid, task.mCallingPackage,
- task.intent, null, null, null, 0, 0,
- new SafeActivityOptions(ActivityOptions.makeBasic()),
- task.userId, null,
- "AppErrors", false /*validateIncomingUser*/,
- null /* originatingPendingIntent */);
- }
+ // Hmm...that didn't work. Task should either be in recents or associated
+ // with a stack.
+ Slog.e(TAG, "Could not restart taskId=" + taskId, e);
}
}
}
@@ -501,10 +487,10 @@ class AppErrors {
long orig = Binder.clearCallingIdentity();
try {
// Kill it with fire!
- mService.mStackSupervisor.handleAppCrashLocked(r.getWindowProcessController());
+ mService.mAtmInternal.onHandleAppCrash(r.getWindowProcessController());
if (!r.isPersistent()) {
- mService.removeProcessLocked(r, false, false, "crash");
- mService.mStackSupervisor.resumeFocusedStacksTopActivitiesLocked();
+ mService.mProcessList.removeProcessLocked(r, false, false, "crash");
+ mService.mAtmInternal.resumeTopActivities(false /* scheduleIdle */);
}
} finally {
Binder.restoreCallingIdentity(orig);
@@ -565,7 +551,7 @@ class AppErrors {
} else {
// Huh.
Process.killProcess(pid);
- ActivityManagerService.killProcessGroup(uid, pid);
+ ProcessList.killProcessGroup(uid, pid);
}
}
return true;
@@ -582,27 +568,12 @@ class AppErrors {
app.setCrashing(true);
app.crashingReport = generateProcessError(app,
ActivityManager.ProcessErrorStateInfo.CRASHED, null, shortMsg, longMsg, stackTrace);
- startAppProblemLocked(app);
+ app.startAppProblemLocked();
app.getWindowProcessController().stopFreezingActivities();
return handleAppCrashLocked(app, "force-crash" /*reason*/, shortMsg, longMsg, stackTrace,
data);
}
- void startAppProblemLocked(ProcessRecord app) {
- // If this app is not running under the current user, then we
- // can't give it a report button because that would require
- // launching the report UI under a different user.
- app.errorReportReceiver = null;
-
- for (int userId : mService.mUserController.getCurrentProfileIds()) {
- if (app.userId == userId) {
- app.errorReportReceiver = ApplicationErrorReport.getErrorReportReceiver(
- mContext, app.info.packageName, app.info.flags);
- }
- }
- mService.skipCurrentReceiverLocked(app);
- }
-
/**
* Generate a process error record, suitable for attachment to a ProcessRecord.
*
@@ -616,7 +587,7 @@ class AppErrors {
*
* @return Returns a fully-formed ProcessErrorStateInfo record.
*/
- private ActivityManager.ProcessErrorStateInfo generateProcessError(ProcessRecord app,
+ ActivityManager.ProcessErrorStateInfo generateProcessError(ProcessRecord app,
int condition, String activity, String shortMsg, String longMsg, String stackTrace) {
ActivityManager.ProcessErrorStateInfo report = new ActivityManager.ProcessErrorStateInfo();
@@ -684,7 +655,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;
@@ -723,7 +694,7 @@ class AppErrors {
+ " has crashed too many times: killing!");
EventLog.writeEvent(EventLogTags.AM_PROCESS_CRASHED_TOO_MUCH,
app.userId, app.info.processName, app.uid);
- mService.mStackSupervisor.handleAppCrashLocked(app.getWindowProcessController());
+ mService.mAtmInternal.onHandleAppCrash(app.getWindowProcessController());
if (!app.isPersistent()) {
// We don't want to start this process again until the user
// explicitly does so... but for persistent process, we really
@@ -743,18 +714,18 @@ class AppErrors {
// Don't let services in this process be restarted and potentially
// annoy the user repeatedly. Unless it is persistent, since those
// processes run critical code.
- mService.removeProcessLocked(app, false, tryAgain, "crash");
- mService.mStackSupervisor.resumeFocusedStacksTopActivitiesLocked();
+ mService.mProcessList.removeProcessLocked(app, false, tryAgain, "crash");
+ mService.mAtmInternal.resumeTopActivities(false /* scheduleIdle */);
if (!showBackground) {
return false;
}
}
- mService.mStackSupervisor.resumeFocusedStacksTopActivitiesLocked();
+ mService.mAtmInternal.resumeTopActivities(false /* scheduleIdle */);
} else {
- final TaskRecord affectedTask =
- mService.mStackSupervisor.finishTopCrashedActivitiesLocked(app.getWindowProcessController(), reason);
+ final int affectedTaskId = mService.mAtmInternal.finishTopCrashedActivities(
+ app.getWindowProcessController(), reason);
if (data != null) {
- data.task = affectedTask;
+ data.taskId = affectedTaskId;
}
if (data != null && crashTimePersistent != null
&& now < crashTimePersistent + ProcessList.MIN_CRASH_INTERVAL) {
@@ -854,259 +825,13 @@ class AppErrors {
}
}
- void stopReportingCrashesLocked(ProcessRecord proc) {
+ private void stopReportingCrashesLocked(ProcessRecord proc) {
if (mAppsNotReportingCrashes == null) {
mAppsNotReportingCrashes = new ArraySet<>();
}
mAppsNotReportingCrashes.add(proc.info.packageName);
}
- static boolean isInterestingForBackgroundTraces(ProcessRecord app) {
- // The system_server is always considered interesting.
- if (app.pid == MY_PID) {
- return true;
- }
-
- // A package is considered interesting if any of the following is true :
- //
- // - It's displaying an activity.
- // - It's the SystemUI.
- // - It has an overlay or a top UI visible.
- //
- // NOTE: The check whether a given ProcessRecord belongs to the systemui
- // process is a bit of a kludge, but the same pattern seems repeated at
- // several places in the system server.
- return app.isInterestingToUserLocked() ||
- (app.info != null && "com.android.systemui".equals(app.info.packageName)) ||
- (app.hasTopUi || app.hasOverlayUi);
- }
-
- final void appNotResponding(ProcessRecord app, ActivityRecord activity,
- ActivityRecord parent, boolean aboveSystem, final String annotation) {
- ArrayList<Integer> firstPids = new ArrayList<Integer>(5);
- SparseArray<Boolean> lastPids = new SparseArray<Boolean>(20);
-
- if (mService.mActivityTaskManager.mController != null) {
- try {
- // 0 == continue, -1 = kill process immediately
- int res = mService.mActivityTaskManager.mController.appEarlyNotResponding(
- app.processName, app.pid, annotation);
- if (res < 0 && app.pid != MY_PID) {
- app.kill("anr", true);
- }
- } catch (RemoteException e) {
- mService.mActivityTaskManager.mController = null;
- Watchdog.getInstance().setActivityController(null);
- }
- }
-
- long anrTime = SystemClock.uptimeMillis();
- if (ActivityManagerService.MONITOR_CPU_USAGE) {
- mService.updateCpuStatsNow();
- }
-
- // Unless configured otherwise, swallow ANRs in background processes & kill the process.
- boolean showBackground = Settings.Secure.getInt(mContext.getContentResolver(),
- Settings.Secure.ANR_SHOW_BACKGROUND, 0) != 0;
-
- boolean isSilentANR;
-
- synchronized (mService) {
- // PowerManager.reboot() can block for a long time, so ignore ANRs while shutting down.
- if (mService.mActivityTaskManager.mShuttingDown) {
- Slog.i(TAG, "During shutdown skipping ANR: " + app + " " + annotation);
- return;
- } else if (app.isNotResponding()) {
- Slog.i(TAG, "Skipping duplicate ANR: " + app + " " + annotation);
- return;
- } else if (app.isCrashing()) {
- Slog.i(TAG, "Crashing app skipping ANR: " + app + " " + annotation);
- return;
- } else if (app.killedByAm) {
- Slog.i(TAG, "App already killed by AM skipping ANR: " + app + " " + annotation);
- return;
- } else if (app.killed) {
- Slog.i(TAG, "Skipping died app ANR: " + app + " " + annotation);
- return;
- }
-
- // In case we come through here for the same app before completing
- // this one, mark as anring now so we will bail out.
- app.setNotResponding(true);
-
- // Log the ANR to the event log.
- EventLog.writeEvent(EventLogTags.AM_ANR, app.userId, app.pid,
- app.processName, app.info.flags, annotation);
-
- // Dump thread traces as quickly as we can, starting with "interesting" processes.
- firstPids.add(app.pid);
-
- // Don't dump other PIDs if it's a background ANR
- isSilentANR = !showBackground && !isInterestingForBackgroundTraces(app);
- if (!isSilentANR) {
- int parentPid = app.pid;
- if (parent != null && parent.app != null && parent.app.getPid() > 0) {
- parentPid = parent.app.getPid();
- }
- if (parentPid != app.pid) firstPids.add(parentPid);
-
- if (MY_PID != app.pid && MY_PID != parentPid) firstPids.add(MY_PID);
-
- for (int i = mService.mLruProcesses.size() - 1; i >= 0; i--) {
- ProcessRecord r = mService.mLruProcesses.get(i);
- if (r != null && r.thread != null) {
- int pid = r.pid;
- if (pid > 0 && pid != app.pid && pid != parentPid && pid != MY_PID) {
- if (r.isPersistent()) {
- firstPids.add(pid);
- if (DEBUG_ANR) Slog.i(TAG, "Adding persistent proc: " + r);
- } else if (r.treatLikeActivity) {
- firstPids.add(pid);
- if (DEBUG_ANR) Slog.i(TAG, "Adding likely IME: " + r);
- } else {
- lastPids.put(pid, Boolean.TRUE);
- if (DEBUG_ANR) Slog.i(TAG, "Adding ANR proc: " + r);
- }
- }
- }
- }
- }
- }
-
- // Log the ANR to the main log.
- StringBuilder info = new StringBuilder();
- info.setLength(0);
- info.append("ANR in ").append(app.processName);
- if (activity != null && activity.shortComponentName != null) {
- info.append(" (").append(activity.shortComponentName).append(")");
- }
- info.append("\n");
- info.append("PID: ").append(app.pid).append("\n");
- if (annotation != null) {
- info.append("Reason: ").append(annotation).append("\n");
- }
- if (parent != null && parent != activity) {
- info.append("Parent: ").append(parent.shortComponentName).append("\n");
- }
-
- ProcessCpuTracker processCpuTracker = new ProcessCpuTracker(true);
-
- // don't dump native PIDs for background ANRs unless it is the process of interest
- String[] nativeProcs = null;
- if (isSilentANR) {
- for (int i = 0; i < NATIVE_STACKS_OF_INTEREST.length; i++) {
- if (NATIVE_STACKS_OF_INTEREST[i].equals(app.processName)) {
- nativeProcs = new String[] { app.processName };
- break;
- }
- }
- } else {
- nativeProcs = NATIVE_STACKS_OF_INTEREST;
- }
-
- int[] pids = nativeProcs == null ? null : Process.getPidsForCommands(nativeProcs);
- ArrayList<Integer> nativePids = null;
-
- if (pids != null) {
- nativePids = new ArrayList<Integer>(pids.length);
- for (int i : pids) {
- nativePids.add(i);
- }
- }
-
- // For background ANRs, don't pass the ProcessCpuTracker to
- // avoid spending 1/2 second collecting stats to rank lastPids.
- File tracesFile = ActivityManagerService.dumpStackTraces(
- firstPids,
- (isSilentANR) ? null : processCpuTracker,
- (isSilentANR) ? null : lastPids,
- nativePids);
-
- String cpuInfo = null;
- if (ActivityManagerService.MONITOR_CPU_USAGE) {
- mService.updateCpuStatsNow();
- synchronized (mService.mProcessCpuTracker) {
- cpuInfo = mService.mProcessCpuTracker.printCurrentState(anrTime);
- }
- info.append(processCpuTracker.printCurrentLoad());
- info.append(cpuInfo);
- }
-
- info.append(processCpuTracker.printCurrentState(anrTime));
-
- Slog.e(TAG, info.toString());
- if (tracesFile == null) {
- // There is no trace file, so dump (only) the alleged culprit's threads to the log
- Process.sendSignal(app.pid, Process.SIGNAL_QUIT);
- }
-
- StatsLog.write(StatsLog.ANR_OCCURRED, app.uid, app.processName,
- activity == null ? "unknown": activity.shortComponentName, annotation,
- (app.info != null) ? (app.info.isInstantApp()
- ? StatsLog.ANROCCURRED__IS_INSTANT_APP__TRUE
- : StatsLog.ANROCCURRED__IS_INSTANT_APP__FALSE)
- : StatsLog.ANROCCURRED__IS_INSTANT_APP__UNAVAILABLE,
- app != null ? (app.isInterestingToUserLocked()
- ? StatsLog.ANROCCURRED__FOREGROUND_STATE__FOREGROUND
- : StatsLog.ANROCCURRED__FOREGROUND_STATE__BACKGROUND)
- : StatsLog.ANROCCURRED__FOREGROUND_STATE__UNKNOWN);
- mService.addErrorToDropBox("anr", app, app.processName, activity, parent, annotation,
- cpuInfo, tracesFile, null);
-
- if (mService.mActivityTaskManager.mController != null) {
- try {
- // 0 == show dialog, 1 = keep waiting, -1 = kill process immediately
- int res = mService.mActivityTaskManager.mController.appNotResponding(
- app.processName, app.pid, info.toString());
- if (res != 0) {
- if (res < 0 && app.pid != MY_PID) {
- app.kill("anr", true);
- } else {
- synchronized (mService) {
- mService.mServices.scheduleServiceTimeoutLocked(app);
- }
- }
- return;
- }
- } catch (RemoteException e) {
- mService.mActivityTaskManager.mController = null;
- Watchdog.getInstance().setActivityController(null);
- }
- }
-
- synchronized (mService) {
- mService.mBatteryStatsService.noteProcessAnr(app.processName, app.uid);
-
- if (isSilentANR) {
- app.kill("bg anr", true);
- return;
- }
-
- // Set the app's notResponding state, and look up the errorReportReceiver
- makeAppNotRespondingLocked(app,
- activity != null ? activity.shortComponentName : null,
- annotation != null ? "ANR " + annotation : "ANR",
- info.toString());
-
- // Bring up the infamous App Not Responding dialog
- Message msg = Message.obtain();
- msg.what = ActivityManagerService.SHOW_NOT_RESPONDING_UI_MSG;
- msg.obj = new AppNotRespondingDialog.Data(app, activity, aboveSystem);
-
- mService.mUiHandler.sendMessage(msg);
- }
- }
-
- private void makeAppNotRespondingLocked(ProcessRecord app,
- String activity, String shortMsg, String longMsg) {
- app.setNotResponding(true);
- app.notRespondingReport = generateProcessError(app,
- ActivityManager.ProcessErrorStateInfo.NOT_RESPONDING,
- activity, shortMsg, longMsg, null);
- startAppProblemLocked(app);
- app.getWindowProcessController().stopFreezingActivities();
- }
-
void handleShowAnrUi(Message msg) {
Dialog dialogToShow = null;
synchronized (mService) {
diff --git a/services/core/java/com/android/server/am/AppNotRespondingDialog.java b/services/core/java/com/android/server/am/AppNotRespondingDialog.java
index 7c983ff427ad..cb76e2fafebd 100644
--- a/services/core/java/com/android/server/am/AppNotRespondingDialog.java
+++ b/services/core/java/com/android/server/am/AppNotRespondingDialog.java
@@ -16,6 +16,7 @@
package com.android.server.am;
+import android.content.pm.ApplicationInfo;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto;
@@ -58,8 +59,8 @@ final class AppNotRespondingDialog extends BaseErrorDialog implements View.OnCli
setCancelable(false);
int resid;
- CharSequence name1 = data.activity != null
- ? data.activity.info.loadLabel(context.getPackageManager())
+ CharSequence name1 = data.aInfo != null
+ ? data.aInfo.loadLabel(context.getPackageManager())
: null;
CharSequence name2 = null;
if ((mProc.pkgList.size() == 1) &&
@@ -181,12 +182,12 @@ final class AppNotRespondingDialog extends BaseErrorDialog implements View.OnCli
static class Data {
final ProcessRecord proc;
- final ActivityRecord activity;
+ final ApplicationInfo aInfo;
final boolean aboveSystem;
- Data(ProcessRecord proc, ActivityRecord activity, boolean aboveSystem) {
+ Data(ProcessRecord proc, ApplicationInfo aInfo, boolean aboveSystem) {
this.proc = proc;
- this.activity = activity;
+ this.aInfo = aInfo;
this.aboveSystem = aboveSystem;
}
}
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index e2035f67031a..a0977be0e25d 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -191,7 +191,7 @@ public final class BroadcastQueue {
@Override
public void run() {
- mService.mAppErrors.appNotResponding(mApp, null, null, false, mAnnotation);
+ mApp.appNotResponding(null, null, null, null, false, mAnnotation);
}
}
@@ -286,7 +286,7 @@ public final class BroadcastQueue {
r.curApp = app;
app.curReceivers.add(r);
app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_RECEIVER);
- mService.updateLruProcessLocked(app, false, null);
+ mService.mProcessList.updateLruProcessLocked(app, false, null);
if (!skipOomAdj) {
mService.updateOomAdjLocked();
}
@@ -892,7 +892,7 @@ public final class BroadcastQueue {
isDead = proc == null || proc.isCrashing();
}
} else {
- final ProcessRecord proc = mService.mProcessNames.get(
+ final ProcessRecord proc = mService.mProcessList.mProcessNames.get(
mPendingBroadcast.curApp.processName, mPendingBroadcast.curApp.uid);
isDead = proc == null || !proc.pendingStart;
}
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 09c152ef5135..48e26ed3d863 100644
--- a/services/core/java/com/android/server/am/CoreSettingsObserver.java
+++ b/services/core/java/com/android/server/am/CoreSettingsObserver.java
@@ -56,6 +56,10 @@ final class CoreSettingsObserver extends ContentObserver {
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...
}
@@ -122,6 +126,7 @@ final class CoreSettingsObserver extends ContentObserver {
value = Settings.Global.getString(context.getContentResolver(), setting);
}
if (value == null) {
+ snapshot.remove(setting);
continue;
}
Class<?> type = entry.getValue();
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..68e897fdbd3e 100644
--- a/services/core/java/com/android/server/am/LaunchParamsController.java
+++ b/services/core/java/com/android/server/am/LaunchParamsController.java
@@ -16,6 +16,14 @@
package com.android.server.am;
+import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+import static android.view.Display.DEFAULT_DISPLAY;
+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 +34,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 +59,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));
}
/**
@@ -101,6 +98,15 @@ class LaunchParamsController {
break;
}
}
+
+ if (activity != null && activity.requestedVrComponent != null) {
+ // Check if the Activity is a VR activity. If so, it should be launched in main display.
+ result.mPreferredDisplayId = DEFAULT_DISPLAY;
+ } else if (mService.mVr2dDisplayId != INVALID_DISPLAY) {
+ // Get the virtual display ID from ActivityTaskManagerService. If that's set we
+ // should always use that.
+ result.mPreferredDisplayId = mService.mVr2dDisplayId;
+ }
}
/**
@@ -226,27 +232,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..85ee7e65ffe7 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;
@@ -37,6 +37,38 @@ import java.util.regex.Pattern;
* Static utility methods related to {@link MemoryStat}.
*/
final class MemoryStatUtil {
+ /**
+ * Which native processes to create {@link MemoryStat} for.
+ *
+ * <p>Processes are matched by their cmdline in procfs. Example: cat /proc/pid/cmdline returns
+ * /system/bin/statsd for the stats daemon.
+ */
+ static final String[] MEMORY_STAT_INTERESTING_NATIVE_PROCESSES = new String[]{
+ "/system/bin/statsd", // Stats daemon.
+ "/system/bin/surfaceflinger",
+ "/system/bin/apexd", // APEX daemon.
+ "/system/bin/audioserver",
+ "/system/bin/cameraserver",
+ "/system/bin/drmserver",
+ "/system/bin/healthd",
+ "/system/bin/incidentd",
+ "/system/bin/installd",
+ "/system/bin/lmkd", // Low memory killer daemon.
+ "/system/bin/logd",
+ "media.codec",
+ "media.extractor",
+ "media.metrics",
+ "/system/bin/mediadrmserver",
+ "/system/bin/mediaserver",
+ "/system/bin/performanced",
+ "/system/bin/tombstoned",
+ "/system/bin/traced", // Perfetto.
+ "/system/bin/traced_probes", // Perfetto.
+ "webview_zygote",
+ "zygote",
+ "zygote64",
+ };
+
static final int BYTES_IN_KILOBYTE = 1024;
static final int PAGE_SIZE = 4096;
@@ -57,6 +89,8 @@ final class MemoryStatUtil {
private static final String PROC_STAT_FILE_FMT = "/proc/%d/stat";
/** Path to procfs status file for logging app memory state */
private static final String PROC_STATUS_FILE_FMT = "/proc/%d/status";
+ /** Path to procfs cmdline file. Used with pid: /proc/pid/cmdline. */
+ private static final String PROC_CMDLINE_FILE_FMT = "/proc/%d/cmdline";
private static final Pattern PGFAULT = Pattern.compile("total_pgfault (\\d+)");
private static final Pattern PGMAJFAULT = Pattern.compile("total_pgmajfault (\\d+)");
@@ -119,6 +153,18 @@ final class MemoryStatUtil {
return stat;
}
+ /**
+ * Reads cmdline of a process from procfs.
+ *
+ * Returns content of /proc/pid/cmdline (e.g. /system/bin/statsd) or an empty string
+ * if the file is not available.
+ */
+ static String readCmdlineFromProcfs(int pid) {
+ String path = String.format(Locale.US, PROC_CMDLINE_FILE_FMT, pid);
+ String cmdline = readFileContents(path);
+ return cmdline != null ? cmdline : "";
+ }
+
private static String readFileContents(String path) {
final File file = new File(path);
if (!file.exists()) {
diff --git a/services/core/java/com/android/server/am/PendingIntentRecord.java b/services/core/java/com/android/server/am/PendingIntentRecord.java
index b9c6fa6020c4..2dcddff2f442 100644
--- a/services/core/java/com/android/server/am/PendingIntentRecord.java
+++ b/services/core/java/com/android/server/am/PendingIntentRecord.java
@@ -288,12 +288,19 @@ public final class PendingIntentRecord extends IIntentSender.Stub {
resolvedType = key.requestResolvedType;
}
+ // Apply any launch flags from the ActivityOptions. This is to ensure that the caller
+ // can specify a consistent launch mode even if the PendingIntent is immutable
+ final ActivityOptions opts = ActivityOptions.fromBundle(options);
+ if (opts != null) {
+ finalIntent.addFlags(opts.getPendingIntentLaunchFlags());
+ }
+
// Extract options before clearing calling identity
mergedOptions = key.options;
if (mergedOptions == null) {
- mergedOptions = SafeActivityOptions.fromBundle(options);
+ mergedOptions = new SafeActivityOptions(opts);
} else {
- mergedOptions.setCallerOptions(ActivityOptions.fromBundle(options));
+ mergedOptions.setCallerOptions(opts);
}
if (whitelistDuration != null) {
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 3ac7885eba37..3f172cc11468 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -16,19 +16,79 @@
package com.android.server.am;
+import static android.app.ActivityManager.PROCESS_STATE_CACHED_ACTIVITY;
+import static android.app.ActivityThread.PROC_START_SEQ_IDENT;
+import static android.content.pm.PackageManager.MATCH_DEBUG_TRIAGED_MISSING;
+import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AUTO;
+import static android.os.Process.FIRST_ISOLATED_UID;
+import static android.os.Process.LAST_ISOLATED_UID;
+import static android.os.Process.SYSTEM_UID;
+import static android.os.Process.THREAD_PRIORITY_BACKGROUND;
+import static android.os.Process.getFreeMemory;
+import static android.os.Process.getTotalMemory;
+import static android.os.Process.killProcessQuiet;
+import static android.os.Process.startWebView;
+
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_LRU;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PROCESSES;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PSS;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_UID_OBSERVERS;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
-
+import static com.android.server.am.ActivityManagerService.PERSISTENT_MASK;
+import static com.android.server.am.ActivityManagerService.PROC_START_TIMEOUT;
+import static com.android.server.am.ActivityManagerService.PROC_START_TIMEOUT_MSG;
+import static com.android.server.am.ActivityManagerService.PROC_START_TIMEOUT_WITH_WRAPPER;
+import static com.android.server.am.ActivityManagerService.STOCK_PM_FLAGS;
+import static com.android.server.am.ActivityManagerService.TAG_LRU;
+import static com.android.server.am.ActivityManagerService.TAG_PROCESSES;
+import static com.android.server.am.ActivityManagerService.TAG_PSS;
+import static com.android.server.am.ActivityManagerService.TAG_UID_OBSERVERS;
+
+import dalvik.system.VMRuntime;
+
+import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
import android.app.ActivityManager;
+import android.app.AppGlobals;
import android.app.AppProtoEnums;
+import android.app.IApplicationThread;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.IPackageManager;
+import android.net.Uri;
+import android.os.Binder;
import android.os.Build;
+import android.os.Bundle;
+import android.os.FactoryTest;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.StrictMode;
import android.os.SystemClock;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.app.ProcessMap;
+import com.android.internal.app.procstats.ProcessStats;
+import com.android.internal.os.Zygote;
+import com.android.internal.util.ArrayUtils;
import com.android.internal.util.MemInfoReader;
+import com.android.server.LocalServices;
+import com.android.server.ServiceThread;
+import com.android.server.Watchdog;
+import com.android.server.pm.dex.DexManager;
import com.android.server.wm.WindowManagerService;
import android.content.res.Resources;
@@ -36,7 +96,15 @@ import android.graphics.Point;
import android.os.SystemProperties;
import android.net.LocalSocketAddress;
import android.net.LocalSocket;
+import android.os.Trace;
+import android.os.UserHandle;
+import android.os.storage.StorageManagerInternal;
+import android.text.TextUtils;
+import android.util.EventLog;
+import android.util.LongSparseArray;
import android.util.Slog;
+import android.util.SparseArray;
+import android.util.StatsLog;
import android.view.Display;
/**
@@ -47,7 +115,7 @@ public final class ProcessList {
// The minimum time we allow between crashes, for us to consider this
// application to be bad and stop and its services and reject broadcasts.
- static final int MIN_CRASH_INTERVAL = 60*1000;
+ static final int MIN_CRASH_INTERVAL = 60 * 1000;
// OOM adjustments for processes in various states:
@@ -129,7 +197,7 @@ public final class ProcessList {
static final int NATIVE_ADJ = -1000;
// Memory pages are 4K.
- static final int PAGE_SIZE = 4*1024;
+ static final int PAGE_SIZE = 4 * 1024;
// Activity manager's version of Process.THREAD_GROUP_BG_NONINTERACTIVE
static final int SCHED_GROUP_BACKGROUND = 0;
@@ -148,7 +216,7 @@ public final class ProcessList {
static final int MIN_CACHED_APPS = 2;
// We allow empty processes to stick around for at most 30 minutes.
- static final long MAX_EMPTY_TIME = 30*60*1000;
+ static final long MAX_EMPTY_TIME = 30 * 60 * 1000;
// Threshold of number of cached+empty where we consider memory critical.
static final int TRIM_CRITICAL_THRESHOLD = 3;
@@ -162,9 +230,17 @@ 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;
+
+ ActivityManagerService mService = null;
+
+ // To kill process groups asynchronously
+ static KillHandler sKillHandler = null;
+ static ServiceThread sKillThread = null;
// 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
@@ -197,6 +273,123 @@ public final class ProcessList {
private static LocalSocket sLmkdSocket;
private static OutputStream sLmkdOutputStream;
+ /**
+ * Temporary to avoid allocations. Protected by main lock.
+ */
+ @GuardedBy("mService")
+ final StringBuilder mStringBuilder = new StringBuilder(256);
+
+ /**
+ * A global counter for generating sequence numbers.
+ * This value will be used when incrementing sequence numbers in individual uidRecords.
+ *
+ * Having a global counter ensures that seq numbers are monotonically increasing for a
+ * particular uid even when the uidRecord is re-created.
+ */
+ @GuardedBy("mService")
+ @VisibleForTesting
+ long mProcStateSeqCounter = 0;
+
+ /**
+ * A global counter for generating sequence numbers to uniquely identify pending process starts.
+ */
+ @GuardedBy("mService")
+ private long mProcStartSeqCounter = 0;
+
+ /**
+ * Contains {@link ProcessRecord} objects for pending process starts.
+ *
+ * Mapping: {@link #mProcStartSeqCounter} -> {@link ProcessRecord}
+ */
+ @GuardedBy("mService")
+ final LongSparseArray<ProcessRecord> mPendingStarts = new LongSparseArray<>();
+
+ /**
+ * List of running applications, sorted by recent usage.
+ * The first entry in the list is the least recently used.
+ */
+ final ArrayList<ProcessRecord> mLruProcesses = new ArrayList<ProcessRecord>();
+
+ /**
+ * Where in mLruProcesses that the processes hosting activities start.
+ */
+ int mLruProcessActivityStart = 0;
+
+ /**
+ * Where in mLruProcesses that the processes hosting services start.
+ * This is after (lower index) than mLruProcessesActivityStart.
+ */
+ int mLruProcessServiceStart = 0;
+
+ /**
+ * Current sequence id for process LRU updating.
+ */
+ int mLruSeq = 0;
+
+ /**
+ * The currently running isolated processes.
+ */
+ final SparseArray<ProcessRecord> mIsolatedProcesses = new SparseArray<>();
+
+ /**
+ * Counter for assigning isolated process uids, to avoid frequently reusing the
+ * same ones.
+ */
+ int mNextIsolatedProcessUid = 0;
+
+ /**
+ * Processes that are being forcibly torn down.
+ */
+ final ArrayList<ProcessRecord> mRemovedProcesses = new ArrayList<ProcessRecord>();
+
+ /**
+ * All of the applications we currently have running organized by name.
+ * The keys are strings of the application package name (as
+ * returned by the package manager), and the keys are ApplicationRecord
+ * objects.
+ */
+ final MyProcessMap mProcessNames = new MyProcessMap();
+
+ final class MyProcessMap extends ProcessMap<ProcessRecord> {
+ @Override
+ public ProcessRecord put(String name, int uid, ProcessRecord value) {
+ final ProcessRecord r = super.put(name, uid, value);
+ mService.mAtmInternal.onProcessAdded(r.getWindowProcessController());
+ return r;
+ }
+
+ @Override
+ public ProcessRecord remove(String name, int uid) {
+ final ProcessRecord r = super.remove(name, uid);
+ mService.mAtmInternal.onProcessRemoved(name, uid);
+ return r;
+ }
+ }
+
+ final class KillHandler extends Handler {
+ static final int KILL_PROCESS_GROUP_MSG = 4000;
+
+ public KillHandler(Looper looper) {
+ super(looper, null, true);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case KILL_PROCESS_GROUP_MSG:
+ Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "killProcessGroup");
+ Process.killProcessGroup(msg.arg1 /* uid */, msg.arg2 /* pid */);
+ Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
+ break;
+
+ default:
+ super.handleMessage(msg);
+ }
+ }
+ }
+
+ //////////////////// END FIELDS ////////////////////
+
ProcessList() {
MemInfoReader minfo = new MemInfoReader();
minfo.readMemInfo();
@@ -204,6 +397,16 @@ public final class ProcessList {
updateOomLevels(0, 0, false);
}
+ void init(ActivityManagerService service) {
+ mService = service;
+ if (sKillHandler == null) {
+ sKillThread = new ServiceThread(TAG + ":kill",
+ THREAD_PRIORITY_BACKGROUND, true /* allowIo */);
+ sKillThread.start();
+ sKillHandler = new KillHandler(sKillThread.getLooper());
+ }
+ }
+
void applyDisplaySize(WindowManagerService wm) {
if (!mHaveDisplaySize) {
Point p = new Point();
@@ -219,12 +422,12 @@ public final class ProcessList {
private void updateOomLevels(int displayWidth, int displayHeight, boolean write) {
// Scale buckets from avail memory: at 300MB we use the lowest values to
// 700MB or more for the top values.
- float scaleMem = ((float)(mTotalMemMb-350))/(700-350);
+ float scaleMem = ((float) (mTotalMemMb - 350)) / (700 - 350);
// Scale buckets from screen size.
- int minSize = 480*800; // 384000
- int maxSize = 1280*800; // 1024000 230400 870400 .264
- float scaleDisp = ((float)(displayWidth*displayHeight)-minSize)/(maxSize-minSize);
+ int minSize = 480 * 800; // 384000
+ int maxSize = 1280 * 800; // 1024000 230400 870400 .264
+ float scaleDisp = ((float)(displayWidth * displayHeight) - minSize) / (maxSize - minSize);
if (false) {
Slog.i("XXXXXX", "scaleMem=" + scaleMem);
Slog.i("XXXXXX", "scaleDisp=" + scaleDisp + " dw=" + displayWidth
@@ -244,27 +447,27 @@ public final class ProcessList {
final boolean is64bit = Build.SUPPORTED_64_BIT_ABIS.length > 0;
- for (int i=0; i<mOomAdj.length; i++) {
+ for (int i = 0; i < mOomAdj.length; i++) {
int low = mOomMinFreeLow[i];
int high = mOomMinFreeHigh[i];
if (is64bit) {
// Increase the high min-free levels for cached processes for 64-bit
- if (i == 4) high = (high*3)/2;
- else if (i == 5) high = (high*7)/4;
+ if (i == 4) high = (high * 3) / 2;
+ else if (i == 5) high = (high * 7) / 4;
}
- mOomMinFree[i] = (int)(low + ((high-low)*scale));
+ mOomMinFree[i] = (int)(low + ((high - low) * scale));
}
if (minfree_abs >= 0) {
- for (int i=0; i<mOomAdj.length; i++) {
+ for (int i = 0; i < mOomAdj.length; i++) {
mOomMinFree[i] = (int)((float)minfree_abs * mOomMinFree[i]
/ mOomMinFree[mOomAdj.length - 1]);
}
}
if (minfree_adj != 0) {
- for (int i=0; i<mOomAdj.length; i++) {
- mOomMinFree[i] += (int)((float)minfree_adj * mOomMinFree[i]
+ for (int i = 0; i < mOomAdj.length; i++) {
+ mOomMinFree[i] += (int)((float) minfree_adj * mOomMinFree[i]
/ mOomMinFree[mOomAdj.length - 1]);
if (mOomMinFree[i] < 0) {
mOomMinFree[i] = 0;
@@ -275,13 +478,15 @@ public final class ProcessList {
// The maximum size we will restore a process from cached to background, when under
// memory duress, is 1/3 the size we have reserved for kernel caches and other overhead
// before killing background processes.
- mCachedRestoreLevel = (getMemLevel(ProcessList.CACHED_APP_MAX_ADJ)/1024) / 3;
+ mCachedRestoreLevel = (getMemLevel(ProcessList.CACHED_APP_MAX_ADJ) / 1024) / 3;
// Ask the kernel to try to keep enough memory free to allocate 3 full
// screen 32bpp buffers without entering direct reclaim.
int reserve = displayWidth * displayHeight * 4 * 3 / 1024;
- int reserve_adj = Resources.getSystem().getInteger(com.android.internal.R.integer.config_extraFreeKbytesAdjust);
- int reserve_abs = Resources.getSystem().getInteger(com.android.internal.R.integer.config_extraFreeKbytesAbsolute);
+ int reserve_adj = Resources.getSystem().getInteger(
+ com.android.internal.R.integer.config_extraFreeKbytesAdjust);
+ int reserve_abs = Resources.getSystem().getInteger(
+ com.android.internal.R.integer.config_extraFreeKbytesAbsolute);
if (reserve_abs >= 0) {
reserve = reserve_abs;
@@ -295,10 +500,10 @@ public final class ProcessList {
}
if (write) {
- ByteBuffer buf = ByteBuffer.allocate(4 * (2*mOomAdj.length + 1));
+ ByteBuffer buf = ByteBuffer.allocate(4 * (2 * mOomAdj.length + 1));
buf.putInt(LMK_TARGET);
- for (int i=0; i<mOomAdj.length; i++) {
- buf.putInt((mOomMinFree[i]*1024)/PAGE_SIZE);
+ for (int i = 0; i < mOomAdj.length; i++) {
+ buf.putInt((mOomMinFree[i] * 1024)/PAGE_SIZE);
buf.putInt(mOomAdj[i]);
}
@@ -318,7 +523,7 @@ public final class ProcessList {
if (space == null) return prefix;
return prefix + " ";
}
- return prefix + "+" + Integer.toString(val-base);
+ return prefix + "+" + Integer.toString(val - base);
}
public static String makeOomAdjString(int setAdj) {
@@ -475,7 +680,7 @@ public final class ProcessList {
}
public static void appendRamKb(StringBuilder sb, long ramKb) {
- for (int j=0, fact=10; j<6; j++, fact*=10) {
+ for (int j = 0, fact = 10; j < 6; j++, fact *= 10) {
if (ramKb < fact) {
sb.append(' ');
}
@@ -735,12 +940,12 @@ public final class ProcessList {
}
long getMemLevel(int adjustment) {
- for (int i=0; i<mOomAdj.length; i++) {
+ for (int i = 0; i < mOomAdj.length; i++) {
if (adjustment <= mOomAdj[i]) {
return mOomMinFree[i] * 1024;
}
}
- return mOomMinFree[mOomAdj.length-1] * 1024;
+ return mOomMinFree[mOomAdj.length - 1] * 1024;
}
/**
@@ -813,31 +1018,1557 @@ 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) {
+ if (openLmkdSocket() == false) {
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException ie) {
+ }
+ continue;
+ }
+
+ // 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;
+ }
+ }
+ }
+
+ static void killProcessGroup(int uid, int pid) {
+ /* static; one-time init here */
+ if (sKillHandler != null) {
+ sKillHandler.sendMessage(
+ sKillHandler.obtainMessage(KillHandler.KILL_PROCESS_GROUP_MSG, uid, pid));
+ } else {
+ Slog.w(TAG, "Asked to kill process group before system bringup!");
+ Process.killProcessGroup(uid, pid);
+ }
+ }
+
+ final ProcessRecord getProcessRecordLocked(String processName, int uid, boolean
+ keepIfLarge) {
+ if (uid == SYSTEM_UID) {
+ // The system gets to run in any process. If there are multiple
+ // processes with the same uid, just pick the first (this
+ // should never happen).
+ SparseArray<ProcessRecord> procs = mProcessNames.getMap().get(processName);
+ if (procs == null) return null;
+ final int procCount = procs.size();
+ for (int i = 0; i < procCount; i++) {
+ final int procUid = procs.keyAt(i);
+ if (UserHandle.isApp(procUid) || !UserHandle.isSameUser(procUid, uid)) {
+ // Don't use an app process or different user process for system component.
+ continue;
+ }
+ return procs.valueAt(i);
+ }
+ }
+ ProcessRecord proc = mProcessNames.get(processName, uid);
+ if (false && proc != null && !keepIfLarge
+ && proc.setProcState >= ActivityManager.PROCESS_STATE_CACHED_EMPTY
+ && proc.lastCachedPss >= 4000) {
+ // Turn this condition on to cause killing to happen regularly, for testing.
+ if (proc.baseProcessTracker != null) {
+ proc.baseProcessTracker.reportCachedKill(proc.pkgList.mPkgList, proc.lastCachedPss);
+ for (int ipkg = proc.pkgList.size() - 1; ipkg >= 0; ipkg--) {
+ ProcessStats.ProcessStateHolder holder = proc.pkgList.valueAt(ipkg);
+ StatsLog.write(StatsLog.CACHED_KILL_REPORTED,
+ proc.info.uid,
+ holder.state.getName(),
+ holder.state.getPackage(),
+ proc.lastCachedPss, holder.appVersion);
+ }
+ }
+ proc.kill(Long.toString(proc.lastCachedPss) + "k from cached", true);
+ } else if (proc != null && !keepIfLarge
+ && mService.mLastMemoryLevel > ProcessStats.ADJ_MEM_FACTOR_NORMAL
+ && proc.setProcState >= ActivityManager.PROCESS_STATE_CACHED_EMPTY) {
+ if (DEBUG_PSS) Slog.d(TAG_PSS, "May not keep " + proc + ": pss=" + proc
+ .lastCachedPss);
+ if (proc.lastCachedPss >= getCachedRestoreThresholdKb()) {
+ if (proc.baseProcessTracker != null) {
+ proc.baseProcessTracker.reportCachedKill(proc.pkgList.mPkgList,
+ proc.lastCachedPss);
+ for (int ipkg = proc.pkgList.size() - 1; ipkg >= 0; ipkg--) {
+ ProcessStats.ProcessStateHolder holder = proc.pkgList.valueAt(ipkg);
+ StatsLog.write(StatsLog.CACHED_KILL_REPORTED,
+ proc.info.uid,
+ holder.state.getName(),
+ holder.state.getPackage(),
+ proc.lastCachedPss, holder.appVersion);
+ }
+ }
+ proc.kill(Long.toString(proc.lastCachedPss) + "k from cached", true);
+ }
+ }
+ return proc;
+ }
+
+ void getMemoryInfo(ActivityManager.MemoryInfo outInfo) {
+ final long homeAppMem = getMemLevel(HOME_APP_ADJ);
+ final long cachedAppMem = getMemLevel(CACHED_APP_MIN_ADJ);
+ outInfo.availMem = getFreeMemory();
+ outInfo.totalMem = getTotalMemory();
+ outInfo.threshold = homeAppMem;
+ outInfo.lowMemory = outInfo.availMem < (homeAppMem + ((cachedAppMem-homeAppMem)/2));
+ outInfo.hiddenAppThreshold = cachedAppMem;
+ outInfo.secondaryServerThreshold = getMemLevel(SERVICE_ADJ);
+ outInfo.visibleAppThreshold = getMemLevel(VISIBLE_APP_ADJ);
+ outInfo.foregroundAppThreshold = getMemLevel(FOREGROUND_APP_ADJ);
+ }
+
+ ProcessRecord findAppProcessLocked(IBinder app, String reason) {
+ final int NP = mProcessNames.getMap().size();
+ for (int ip = 0; ip < NP; ip++) {
+ SparseArray<ProcessRecord> apps = mProcessNames.getMap().valueAt(ip);
+ final int NA = apps.size();
+ for (int ia = 0; ia < NA; ia++) {
+ ProcessRecord p = apps.valueAt(ia);
+ if (p.thread != null && p.thread.asBinder() == app) {
+ return p;
+ }
+ }
+ }
+
+ Slog.w(TAG, "Can't find mystery application for " + reason
+ + " from pid=" + Binder.getCallingPid()
+ + " uid=" + Binder.getCallingUid() + ": " + app);
+ return null;
+ }
+
+ private void checkSlow(long startTime, String where) {
+ long now = SystemClock.uptimeMillis();
+ if ((now - startTime) > 50) {
+ // If we are taking more than 50ms, log about it.
+ Slog.w(TAG, "Slow operation: " + (now - startTime) + "ms so far, now at " + where);
+ }
+ }
+
+ /**
+ * @return {@code true} if process start is successful, false otherwise.
+ * @param app
+ * @param hostingType
+ * @param hostingNameStr
+ * @param disableHiddenApiChecks
+ * @param abiOverride
+ */
+ @GuardedBy("mService")
+ boolean startProcessLocked(ProcessRecord app, String hostingType,
+ String hostingNameStr, boolean disableHiddenApiChecks, String abiOverride) {
+ if (app.pendingStart) {
+ return true;
+ }
+ long startTime = SystemClock.elapsedRealtime();
+ if (app.pid > 0 && app.pid != ActivityManagerService.MY_PID) {
+ checkSlow(startTime, "startProcess: removing from pids map");
+ synchronized (mService.mPidsSelfLocked) {
+ mService.mPidsSelfLocked.remove(app.pid);
+ mService.mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
+ }
+ checkSlow(startTime, "startProcess: done removing from pids map");
+ app.setPid(0);
+ }
+
+ if (DEBUG_PROCESSES && mService.mProcessesOnHold.contains(app)) Slog.v(
+ TAG_PROCESSES,
+ "startProcessLocked removing on hold: " + app);
+ mService.mProcessesOnHold.remove(app);
+
+ checkSlow(startTime, "startProcess: starting to update cpu stats");
+ mService.updateCpuStats();
+ checkSlow(startTime, "startProcess: done updating cpu stats");
+
+ try {
+ try {
+ final int userId = UserHandle.getUserId(app.uid);
+ AppGlobals.getPackageManager().checkPackageStartable(app.info.packageName, userId);
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ }
+
+ int uid = app.uid;
+ int[] gids = null;
+ int mountExternal = Zygote.MOUNT_EXTERNAL_NONE;
+ if (!app.isolated) {
+ int[] permGids = null;
+ try {
+ checkSlow(startTime, "startProcess: getting gids from package manager");
+ final IPackageManager pm = AppGlobals.getPackageManager();
+ permGids = pm.getPackageGids(app.info.packageName,
+ MATCH_DIRECT_BOOT_AUTO, app.userId);
+ StorageManagerInternal storageManagerInternal = LocalServices.getService(
+ StorageManagerInternal.class);
+ mountExternal = storageManagerInternal.getExternalStorageMountMode(uid,
+ app.info.packageName);
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ }
+
+ /*
+ * Add shared application and profile GIDs so applications can share some
+ * resources like shared libraries and access user-wide resources
+ */
+ if (ArrayUtils.isEmpty(permGids)) {
+ gids = new int[3];
+ } else {
+ gids = new int[permGids.length + 3];
+ System.arraycopy(permGids, 0, gids, 3, permGids.length);
+ }
+ gids[0] = UserHandle.getSharedAppGid(UserHandle.getAppId(uid));
+ gids[1] = UserHandle.getCacheAppGid(UserHandle.getAppId(uid));
+ gids[2] = UserHandle.getUserGid(UserHandle.getUserId(uid));
+
+ // Replace any invalid GIDs
+ if (gids[0] == UserHandle.ERR_GID) gids[0] = gids[2];
+ if (gids[1] == UserHandle.ERR_GID) gids[1] = gids[2];
+ }
+ checkSlow(startTime, "startProcess: building args");
+ if (mService.mAtmInternal.isFactoryTestProcess(app.getWindowProcessController())) {
+ uid = 0;
+ }
+ int runtimeFlags = 0;
+ if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
+ runtimeFlags |= Zygote.DEBUG_ENABLE_JDWP;
+ runtimeFlags |= Zygote.DEBUG_JAVA_DEBUGGABLE;
+ // Also turn on CheckJNI for debuggable apps. It's quite
+ // awkward to turn on otherwise.
+ runtimeFlags |= Zygote.DEBUG_ENABLE_CHECKJNI;
+ }
+ // Run the app in safe mode if its manifest requests so or the
+ // system is booted in safe mode.
+ if ((app.info.flags & ApplicationInfo.FLAG_VM_SAFE_MODE) != 0 ||
+ mService.mSafeMode == true) {
+ runtimeFlags |= Zygote.DEBUG_ENABLE_SAFEMODE;
+ }
+ if ("1".equals(SystemProperties.get("debug.checkjni"))) {
+ runtimeFlags |= Zygote.DEBUG_ENABLE_CHECKJNI;
+ }
+ String genDebugInfoProperty = SystemProperties.get("debug.generate-debug-info");
+ if ("1".equals(genDebugInfoProperty) || "true".equals(genDebugInfoProperty)) {
+ runtimeFlags |= Zygote.DEBUG_GENERATE_DEBUG_INFO;
+ }
+ String genMiniDebugInfoProperty = SystemProperties.get("dalvik.vm.minidebuginfo");
+ if ("1".equals(genMiniDebugInfoProperty) || "true".equals(genMiniDebugInfoProperty)) {
+ runtimeFlags |= Zygote.DEBUG_GENERATE_MINI_DEBUG_INFO;
+ }
+ if ("1".equals(SystemProperties.get("debug.jni.logging"))) {
+ runtimeFlags |= Zygote.DEBUG_ENABLE_JNI_LOGGING;
+ }
+ if ("1".equals(SystemProperties.get("debug.assert"))) {
+ runtimeFlags |= Zygote.DEBUG_ENABLE_ASSERT;
+ }
+ if (mService.mNativeDebuggingApp != null
+ && mService.mNativeDebuggingApp.equals(app.processName)) {
+ // Enable all debug flags required by the native debugger.
+ runtimeFlags |= Zygote.DEBUG_ALWAYS_JIT; // Don't interpret anything
+ runtimeFlags |= Zygote.DEBUG_GENERATE_DEBUG_INFO; // Generate debug info
+ runtimeFlags |= Zygote.DEBUG_NATIVE_DEBUGGABLE; // Disbale optimizations
+ mService.mNativeDebuggingApp = null;
+ }
+
+ if (app.info.isPrivilegedApp() &&
+ DexManager.isPackageSelectedToRunOob(app.pkgList.mPkgList.keySet())) {
+ runtimeFlags |= Zygote.ONLY_USE_SYSTEM_OAT_FILES;
+ }
+
+ if (!disableHiddenApiChecks && !mService.mHiddenApiBlacklist.isDisabled()) {
+ app.info.maybeUpdateHiddenApiEnforcementPolicy(
+ mService.mHiddenApiBlacklist.getPolicyForPrePApps(),
+ mService.mHiddenApiBlacklist.getPolicyForPApps());
+ @ApplicationInfo.HiddenApiEnforcementPolicy int policy =
+ app.info.getHiddenApiEnforcementPolicy();
+ int policyBits = (policy << Zygote.API_ENFORCEMENT_POLICY_SHIFT);
+ if ((policyBits & Zygote.API_ENFORCEMENT_POLICY_MASK) != policyBits) {
+ throw new IllegalStateException("Invalid API policy: " + policy);
+ }
+ runtimeFlags |= policyBits;
+ }
+
+ String invokeWith = null;
+ if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
+ // Debuggable apps may include a wrapper script with their library directory.
+ String wrapperFileName = app.info.nativeLibraryDir + "/wrap.sh";
+ StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
+ try {
+ if (new File(wrapperFileName).exists()) {
+ invokeWith = "/system/bin/logwrapper " + wrapperFileName;
+ }
+ } finally {
+ StrictMode.setThreadPolicy(oldPolicy);
+ }
+ }
+
+ String requiredAbi = (abiOverride != null) ? abiOverride : app.info.primaryCpuAbi;
+ if (requiredAbi == null) {
+ requiredAbi = Build.SUPPORTED_ABIS[0];
+ }
+
+ String instructionSet = null;
+ if (app.info.primaryCpuAbi != null) {
+ instructionSet = VMRuntime.getInstructionSet(app.info.primaryCpuAbi);
+ }
+
+ app.gids = gids;
+ app.setRequiredAbi(requiredAbi);
+ app.instructionSet = instructionSet;
+
+ // the per-user SELinux context must be set
+ if (TextUtils.isEmpty(app.info.seInfoUser)) {
+ Slog.wtf(ActivityManagerService.TAG, "SELinux tag not defined",
+ new IllegalStateException("SELinux tag not defined for "
+ + app.info.packageName + " (uid " + app.uid + ")"));
+ }
+ final String seInfo = app.info.seInfo
+ + (TextUtils.isEmpty(app.info.seInfoUser) ? "" : app.info.seInfoUser);
+ // Start the process. It will either succeed and return a result containing
+ // the PID of the new process, or else throw a RuntimeException.
+ final String entryPoint = "android.app.ActivityThread";
+
+ return startProcessLocked(hostingType, hostingNameStr, entryPoint, app, uid, gids,
+ runtimeFlags, mountExternal, seInfo, requiredAbi, instructionSet, invokeWith,
+ startTime);
+ } catch (RuntimeException e) {
+ Slog.e(ActivityManagerService.TAG, "Failure starting process " + app.processName, e);
+
+ // Something went very wrong while trying to start this process; one
+ // common case is when the package is frozen due to an active
+ // upgrade. To recover, clean up any active bookkeeping related to
+ // starting this process. (We already invoked this method once when
+ // the package was initially frozen through KILL_APPLICATION_MSG, so
+ // it doesn't hurt to use it again.)
+ mService.forceStopPackageLocked(app.info.packageName, UserHandle.getAppId(app.uid),
+ false, false, true, false, false, app.userId, "start failure");
+ return false;
+ }
+ }
+
+ @GuardedBy("mService")
+ boolean startProcessLocked(String hostingType, String hostingNameStr,
+ String entryPoint,
+ ProcessRecord app, int uid, int[] gids, int runtimeFlags, int mountExternal,
+ String seInfo, String requiredAbi, String instructionSet, String invokeWith,
+ long startTime) {
+ app.pendingStart = true;
+ app.killedByAm = false;
+ app.removed = false;
+ app.killed = false;
+ final long startSeq = app.startSeq = ++mProcStartSeqCounter;
+ app.setStartParams(uid, hostingType, hostingNameStr, seInfo, startTime);
+ if (mService.mConstants.FLAG_PROCESS_START_ASYNC) {
+ if (DEBUG_PROCESSES) Slog.i(TAG_PROCESSES,
+ "Posting procStart msg for " + app.toShortString());
+ mService.mProcStartHandler.post(() -> {
+ try {
+ synchronized (mService) {
+ final String reason = isProcStartValidLocked(app, startSeq);
+ if (reason != null) {
+ Slog.w(TAG_PROCESSES, app + " not valid anymore,"
+ + " don't start process, " + reason);
+ app.pendingStart = false;
+ return;
}
+ app.setUsingWrapper(invokeWith != null
+ || SystemProperties.get("wrap." + app.processName) != null);
+ mPendingStarts.put(startSeq, app);
+ }
+ final Process.ProcessStartResult startResult = startProcess(app.hostingType,
+ entryPoint, app, app.startUid, gids, runtimeFlags, mountExternal,
+ app.seInfo, requiredAbi, instructionSet, invokeWith, app.startTime);
+ synchronized (mService) {
+ handleProcessStartedLocked(app, startResult, startSeq);
+ }
+ } catch (RuntimeException e) {
+ synchronized (mService) {
+ Slog.e(ActivityManagerService.TAG, "Failure starting process "
+ + app.processName, e);
+ mPendingStarts.remove(startSeq);
+ app.pendingStart = false;
+ mService.forceStopPackageLocked(app.info.packageName,
+ UserHandle.getAppId(app.uid),
+ false, false, true, false, false, app.userId, "start failure");
+ }
+ }
+ });
+ return true;
+ } else {
+ try {
+ final Process.ProcessStartResult startResult = startProcess(hostingType,
+ entryPoint, app,
+ uid, gids, runtimeFlags, mountExternal, seInfo, requiredAbi, instructionSet,
+ invokeWith, startTime);
+ handleProcessStartedLocked(app, startResult.pid, startResult.usingWrapper,
+ startSeq, false);
+ } catch (RuntimeException e) {
+ Slog.e(ActivityManagerService.TAG, "Failure starting process "
+ + app.processName, e);
+ app.pendingStart = false;
+ mService.forceStopPackageLocked(app.info.packageName, UserHandle.getAppId(app.uid),
+ false, false, true, false, false, app.userId, "start failure");
+ }
+ return app.pid > 0;
+ }
+ }
+
+ private Process.ProcessStartResult startProcess(String hostingType, String entryPoint,
+ ProcessRecord app, int uid, int[] gids, int runtimeFlags, int mountExternal,
+ String seInfo, String requiredAbi, String instructionSet, String invokeWith,
+ long startTime) {
+ try {
+ final String[] packageNames = mService.mContext.getPackageManager()
+ .getPackagesForUid(uid);
+ final String[] visibleVolIds = LocalServices.getService(StorageManagerInternal.class)
+ .getVisibleVolumesForUser(UserHandle.getUserId(uid));
+ Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Start proc: " +
+ app.processName);
+ checkSlow(startTime, "startProcess: asking zygote to start proc");
+ final Process.ProcessStartResult startResult;
+ if (hostingType.equals("webview_service")) {
+ startResult = startWebView(entryPoint,
+ app.processName, uid, uid, gids, runtimeFlags, mountExternal,
+ app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
+ app.info.dataDir, null, app.info.packageName,
+ packageNames, visibleVolIds,
+ new String[] {PROC_START_SEQ_IDENT + app.startSeq});
+ } else {
+ startResult = Process.start(entryPoint,
+ app.processName, uid, uid, gids, runtimeFlags, mountExternal,
+ app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
+ app.info.dataDir, invokeWith, app.info.packageName,
+ packageNames, visibleVolIds,
+ new String[] {PROC_START_SEQ_IDENT + app.startSeq});
+ }
+ checkSlow(startTime, "startProcess: returned from zygote!");
+ return startResult;
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
+ }
+ }
+
+ @GuardedBy("mService")
+ final void startProcessLocked(ProcessRecord app,
+ String hostingType, String hostingNameStr) {
+ startProcessLocked(app, hostingType, hostingNameStr, null /* abiOverride */);
+ }
+
+ @GuardedBy("mService")
+ final boolean startProcessLocked(ProcessRecord app,
+ String hostingType, String hostingNameStr, String abiOverride) {
+ return startProcessLocked(app, hostingType, hostingNameStr,
+ false /* disableHiddenApiChecks */, abiOverride);
+ }
+
+ @GuardedBy("mService")
+ final ProcessRecord startProcessLocked(String processName, ApplicationInfo info,
+ boolean knownToBeDead, int intentFlags, String hostingType, ComponentName hostingName,
+ boolean allowWhileBooting, boolean isolated, int isolatedUid, boolean keepIfLarge,
+ String abiOverride, String entryPoint, String[] entryPointArgs, Runnable crashHandler) {
+ long startTime = SystemClock.elapsedRealtime();
+ ProcessRecord app;
+ if (!isolated) {
+ app = getProcessRecordLocked(processName, info.uid, keepIfLarge);
+ checkSlow(startTime, "startProcess: after getProcessRecord");
+
+ if ((intentFlags & Intent.FLAG_FROM_BACKGROUND) != 0) {
+ // If we are in the background, then check to see if this process
+ // is bad. If so, we will just silently fail.
+ if (mService.mAppErrors.isBadProcessLocked(info)) {
+ if (DEBUG_PROCESSES) Slog.v(TAG, "Bad process: " + info.uid
+ + "/" + info.processName);
+ return null;
+ }
+ } else {
+ // When the user is explicitly starting a process, then clear its
+ // crash count so that we won't make it bad until they see at
+ // least one crash dialog again, and make the process good again
+ // if it had been bad.
+ if (DEBUG_PROCESSES) Slog.v(TAG, "Clearing bad process: " + info.uid
+ + "/" + info.processName);
+ mService.mAppErrors.resetProcessCrashTimeLocked(info);
+ if (mService.mAppErrors.isBadProcessLocked(info)) {
+ EventLog.writeEvent(EventLogTags.AM_PROC_GOOD,
+ UserHandle.getUserId(info.uid), info.uid,
+ info.processName);
+ mService.mAppErrors.clearBadProcessLocked(info);
+ if (app != null) {
+ app.bad = false;
+ }
+ }
+ }
+ } else {
+ // If this is an isolated process, it can't re-use an existing process.
+ app = null;
+ }
+
+ // We don't have to do anything more if:
+ // (1) There is an existing application record; and
+ // (2) The caller doesn't think it is dead, OR there is no thread
+ // object attached to it so we know it couldn't have crashed; and
+ // (3) There is a pid assigned to it, so it is either starting or
+ // already running.
+ if (DEBUG_PROCESSES) Slog.v(TAG_PROCESSES, "startProcess: name=" + processName
+ + " app=" + app + " knownToBeDead=" + knownToBeDead
+ + " thread=" + (app != null ? app.thread : null)
+ + " pid=" + (app != null ? app.pid : -1));
+ if (app != null && app.pid > 0) {
+ if ((!knownToBeDead && !app.killed) || app.thread == null) {
+ // We already have the app running, or are waiting for it to
+ // come up (we have a pid but not yet its thread), so keep it.
+ if (DEBUG_PROCESSES) Slog.v(TAG_PROCESSES, "App already running: " + app);
+ // If this is a new package in the process, add the package to the list
+ app.addPackage(info.packageName, info.versionCode, mService.mProcessStats);
+ checkSlow(startTime, "startProcess: done, added package to proc");
+ return app;
+ }
+
+ // An application record is attached to a previous process,
+ // clean it up now.
+ if (DEBUG_PROCESSES) Slog.v(TAG_PROCESSES, "App died: " + app);
+ checkSlow(startTime, "startProcess: bad proc running, killing");
+ ProcessList.killProcessGroup(app.uid, app.pid);
+ mService.handleAppDiedLocked(app, true, true);
+ checkSlow(startTime, "startProcess: done killing old proc");
+ }
+
+ String hostingNameStr = hostingName != null
+ ? hostingName.flattenToShortString() : null;
+
+ if (app == null) {
+ checkSlow(startTime, "startProcess: creating new process record");
+ app = newProcessRecordLocked(info, processName, isolated, isolatedUid);
+ if (app == null) {
+ Slog.w(TAG, "Failed making new process record for "
+ + processName + "/" + info.uid + " isolated=" + isolated);
+ return null;
+ }
+ app.crashHandler = crashHandler;
+ app.isolatedEntryPoint = entryPoint;
+ app.isolatedEntryPointArgs = entryPointArgs;
+ checkSlow(startTime, "startProcess: done creating new process record");
+ } else {
+ // If this is a new package in the process, add the package to the list
+ app.addPackage(info.packageName, info.versionCode, mService.mProcessStats);
+ checkSlow(startTime, "startProcess: added package to existing proc");
+ }
+
+ // If the system is not ready yet, then hold off on starting this
+ // process until it is.
+ if (!mService.mProcessesReady
+ && !mService.isAllowedWhileBooting(info)
+ && !allowWhileBooting) {
+ if (!mService.mProcessesOnHold.contains(app)) {
+ mService.mProcessesOnHold.add(app);
+ }
+ if (DEBUG_PROCESSES) Slog.v(TAG_PROCESSES,
+ "System not ready, putting on hold: " + app);
+ checkSlow(startTime, "startProcess: returning with proc on hold");
+ return app;
+ }
+
+ checkSlow(startTime, "startProcess: stepping in to startProcess");
+ final boolean success = startProcessLocked(app, hostingType, hostingNameStr,
+ abiOverride);
+ checkSlow(startTime, "startProcess: done starting proc!");
+ return success ? app : null;
+ }
+
+ @GuardedBy("mService")
+ private String isProcStartValidLocked(ProcessRecord app, long expectedStartSeq) {
+ StringBuilder sb = null;
+ if (app.killedByAm) {
+ if (sb == null) sb = new StringBuilder();
+ sb.append("killedByAm=true;");
+ }
+ if (mProcessNames.get(app.processName, app.uid) != app) {
+ if (sb == null) sb = new StringBuilder();
+ sb.append("No entry in mProcessNames;");
+ }
+ if (!app.pendingStart) {
+ if (sb == null) sb = new StringBuilder();
+ sb.append("pendingStart=false;");
+ }
+ if (app.startSeq > expectedStartSeq) {
+ if (sb == null) sb = new StringBuilder();
+ sb.append("seq=" + app.startSeq + ",expected=" + expectedStartSeq + ";");
+ }
+ return sb == null ? null : sb.toString();
+ }
+
+ @GuardedBy("mService")
+ private boolean handleProcessStartedLocked(ProcessRecord pending,
+ Process.ProcessStartResult startResult, long expectedStartSeq) {
+ // Indicates that this process start has been taken care of.
+ if (mPendingStarts.get(expectedStartSeq) == null) {
+ if (pending.pid == startResult.pid) {
+ pending.setUsingWrapper(startResult.usingWrapper);
+ // TODO: Update already existing clients of usingWrapper
+ }
+ return false;
+ }
+ return handleProcessStartedLocked(pending, startResult.pid, startResult.usingWrapper,
+ expectedStartSeq, false);
+ }
+
+ @GuardedBy("mService")
+ boolean handleProcessStartedLocked(ProcessRecord app, int pid, boolean usingWrapper,
+ long expectedStartSeq, boolean procAttached) {
+ mPendingStarts.remove(expectedStartSeq);
+ final String reason = isProcStartValidLocked(app, expectedStartSeq);
+ if (reason != null) {
+ Slog.w(TAG_PROCESSES, app + " start not valid, killing pid=" +
+ pid
+ + ", " + reason);
+ app.pendingStart = false;
+ killProcessQuiet(pid);
+ Process.killProcessGroup(app.uid, app.pid);
+ return false;
+ }
+ mService.mBatteryStatsService.noteProcessStart(app.processName, app.info.uid);
+ checkSlow(app.startTime, "startProcess: done updating battery stats");
+
+ EventLog.writeEvent(EventLogTags.AM_PROC_START,
+ UserHandle.getUserId(app.startUid), pid, app.startUid,
+ app.processName, app.hostingType,
+ app.hostingNameStr != null ? app.hostingNameStr : "");
+
+ try {
+ AppGlobals.getPackageManager().logAppProcessStartIfNeeded(app.processName, app.uid,
+ app.seInfo, app.info.sourceDir, pid);
+ } catch (RemoteException ex) {
+ // Ignore
+ }
+
+ if (app.isPersistent()) {
+ Watchdog.getInstance().processStarted(app.processName, pid);
+ }
+
+ checkSlow(app.startTime, "startProcess: building log message");
+ StringBuilder buf = mStringBuilder;
+ buf.setLength(0);
+ buf.append("Start proc ");
+ buf.append(pid);
+ buf.append(':');
+ buf.append(app.processName);
+ buf.append('/');
+ UserHandle.formatUid(buf, app.startUid);
+ if (app.isolatedEntryPoint != null) {
+ buf.append(" [");
+ buf.append(app.isolatedEntryPoint);
+ buf.append("]");
+ }
+ buf.append(" for ");
+ buf.append(app.hostingType);
+ if (app.hostingNameStr != null) {
+ buf.append(" ");
+ buf.append(app.hostingNameStr);
+ }
+ mService.reportUidInfoMessageLocked(TAG, buf.toString(), app.startUid);
+ app.setPid(pid);
+ app.setUsingWrapper(usingWrapper);
+ app.pendingStart = false;
+ checkSlow(app.startTime, "startProcess: starting to update pids map");
+ ProcessRecord oldApp;
+ synchronized (mService.mPidsSelfLocked) {
+ oldApp = mService.mPidsSelfLocked.get(pid);
+ }
+ // If there is already an app occupying that pid that hasn't been cleaned up
+ if (oldApp != null && !app.isolated) {
+ // Clean up anything relating to this pid first
+ Slog.w(TAG, "Reusing pid " + pid
+ + " while app is still mapped to it");
+ mService.cleanUpApplicationRecordLocked(oldApp, false, false, -1,
+ true /*replacingPid*/);
+ }
+ synchronized (mService.mPidsSelfLocked) {
+ mService.mPidsSelfLocked.put(pid, app);
+ if (!procAttached) {
+ Message msg = mService.mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
+ msg.obj = app;
+ mService.mHandler.sendMessageDelayed(msg, usingWrapper
+ ? PROC_START_TIMEOUT_WITH_WRAPPER : PROC_START_TIMEOUT);
+ }
+ }
+ checkSlow(app.startTime, "startProcess: done updating pids map");
+ return true;
+ }
+
+ final void removeLruProcessLocked(ProcessRecord app) {
+ int lrui = mLruProcesses.lastIndexOf(app);
+ if (lrui >= 0) {
+ if (!app.killed) {
+ if (app.isPersistent()) {
+ Slog.w(TAG, "Removing persistent process that hasn't been killed: " + app);
+ } else {
+ Slog.wtfStack(TAG, "Removing process that hasn't been killed: " + app);
+ if (app.pid > 0) {
+ killProcessQuiet(app.pid);
+ ProcessList.killProcessGroup(app.uid, app.pid);
+ } else {
+ app.pendingStart = false;
+ }
+ }
+ }
+ if (lrui <= mLruProcessActivityStart) {
+ mLruProcessActivityStart--;
+ }
+ if (lrui <= mLruProcessServiceStart) {
+ mLruProcessServiceStart--;
+ }
+ mLruProcesses.remove(lrui);
+ }
+ }
+
+ void killAllBackgroundProcessesLocked() {
+ final ArrayList<ProcessRecord> procs = new ArrayList<>();
+ final int NP = mProcessNames.getMap().size();
+ for (int ip = 0; ip < NP; ip++) {
+ final SparseArray<ProcessRecord> apps = mProcessNames.getMap().valueAt(ip);
+ final int NA = apps.size();
+ for (int ia = 0; ia < NA; ia++) {
+ final ProcessRecord app = apps.valueAt(ia);
+ if (app.isPersistent()) {
+ // We don't kill persistent processes.
+ continue;
+ }
+ if (app.removed) {
+ procs.add(app);
+ } else if (app.setAdj >= ProcessList.CACHED_APP_MIN_ADJ) {
+ app.removed = true;
+ procs.add(app);
+ }
+ }
+ }
+
+ final int N = procs.size();
+ for (int i = 0; i < N; i++) {
+ removeProcessLocked(procs.get(i), false, true, "kill all background");
+ }
+ }
+
+ @GuardedBy("mService")
+ final boolean killPackageProcessesLocked(String packageName, int appId,
+ int userId, int minOomAdj, boolean callerWillRestart, boolean allowRestart,
+ boolean doit, boolean evenPersistent, String reason) {
+ ArrayList<ProcessRecord> procs = new ArrayList<>();
+
+ // Remove all processes this package may have touched: all with the
+ // same UID (except for the system or root user), and all whose name
+ // matches the package name.
+ final int NP = mProcessNames.getMap().size();
+ for (int ip = 0; ip < NP; ip++) {
+ SparseArray<ProcessRecord> apps = mProcessNames.getMap().valueAt(ip);
+ final int NA = apps.size();
+ for (int ia = 0; ia < NA; ia++) {
+ ProcessRecord app = apps.valueAt(ia);
+ if (app.isPersistent() && !evenPersistent) {
+ // we don't kill persistent processes
+ continue;
+ }
+ if (app.removed) {
+ if (doit) {
+ procs.add(app);
+ }
+ continue;
+ }
+
+ // Skip process if it doesn't meet our oom adj requirement.
+ if (app.setAdj < minOomAdj) {
+ continue;
+ }
+
+ // If no package is specified, we call all processes under the
+ // give user id.
+ if (packageName == null) {
+ if (userId != UserHandle.USER_ALL && app.userId != userId) {
+ continue;
+ }
+ if (appId >= 0 && UserHandle.getAppId(app.uid) != appId) {
continue;
}
+ // Package has been specified, we want to hit all processes
+ // that match it. We need to qualify this by the processes
+ // that are running under the specified app and user ID.
+ } else {
+ final boolean isDep = app.pkgDeps != null
+ && app.pkgDeps.contains(packageName);
+ if (!isDep && UserHandle.getAppId(app.uid) != appId) {
+ continue;
+ }
+ if (userId != UserHandle.USER_ALL && app.userId != userId) {
+ continue;
+ }
+ if (!app.pkgList.containsKey(packageName) && !isDep) {
+ continue;
+ }
+ }
+
+ // Process has passed all conditions, kill it!
+ if (!doit) {
+ return true;
+ }
+ app.removed = true;
+ procs.add(app);
+ }
+ }
+
+ int N = procs.size();
+ for (int i=0; i<N; i++) {
+ removeProcessLocked(procs.get(i), callerWillRestart, allowRestart, reason);
+ }
+ mService.updateOomAdjLocked();
+ return N > 0;
+ }
+ @GuardedBy("mService")
+ boolean removeProcessLocked(ProcessRecord app,
+ boolean callerWillRestart, boolean allowRestart, String reason) {
+ final String name = app.processName;
+ final int uid = app.uid;
+ if (DEBUG_PROCESSES) Slog.d(TAG_PROCESSES,
+ "Force removing proc " + app.toShortString() + " (" + name + "/" + uid + ")");
+
+ ProcessRecord old = mProcessNames.get(name, uid);
+ if (old != app) {
+ // This process is no longer active, so nothing to do.
+ Slog.w(TAG, "Ignoring remove of inactive process: " + app);
+ return false;
+ }
+ removeProcessNameLocked(name, uid);
+ mService.mAtmInternal.clearHeavyWeightProcessIfEquals(app.getWindowProcessController());
+
+ boolean needRestart = false;
+ if ((app.pid > 0 && app.pid != ActivityManagerService.MY_PID) || (app.pid == 0 && app
+ .pendingStart)) {
+ int pid = app.pid;
+ if (pid > 0) {
+ synchronized (mService.mPidsSelfLocked) {
+ mService.mPidsSelfLocked.remove(pid);
+ mService.mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
+ }
+ mService.mBatteryStatsService.noteProcessFinish(app.processName, app.info.uid);
+ if (app.isolated) {
+ mService.mBatteryStatsService.removeIsolatedUid(app.uid, app.info.uid);
+ mService.getPackageManagerInternalLocked().removeIsolatedUid(app.uid);
+ }
+ }
+ boolean willRestart = false;
+ if (app.isPersistent() && !app.isolated) {
+ if (!callerWillRestart) {
+ willRestart = true;
+ } else {
+ needRestart = true;
+ }
+ }
+ app.kill(reason, true);
+ mService.handleAppDiedLocked(app, willRestart, allowRestart);
+ if (willRestart) {
+ removeLruProcessLocked(app);
+ mService.addAppLocked(app.info, null, false, null /* ABI override */);
}
+ } else {
+ mRemovedProcesses.add(app);
+ }
+
+ return needRestart;
+ }
+ @GuardedBy("mService")
+ final void addProcessNameLocked(ProcessRecord proc) {
+ // We shouldn't already have a process under this name, but just in case we
+ // need to clean up whatever may be there now.
+ ProcessRecord old = removeProcessNameLocked(proc.processName, proc.uid);
+ if (old == proc && proc.isPersistent()) {
+ // We are re-adding a persistent process. Whatevs! Just leave it there.
+ Slog.w(TAG, "Re-adding persistent process " + proc);
+ } else if (old != null) {
+ Slog.wtf(TAG, "Already have existing proc " + old + " when adding " + proc);
+ }
+ UidRecord uidRec = mService.mActiveUids.get(proc.uid);
+ if (uidRec == null) {
+ uidRec = new UidRecord(proc.uid);
+ // This is the first appearance of the uid, report it now!
+ if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS,
+ "Creating new process uid: " + uidRec);
+ if (Arrays.binarySearch(mService.mDeviceIdleTempWhitelist,
+ UserHandle.getAppId(proc.uid)) >= 0
+ || mService.mPendingTempWhitelist.indexOfKey(proc.uid) >= 0) {
+ uidRec.setWhitelist = uidRec.curWhitelist = true;
+ }
+ uidRec.updateHasInternetPermission();
+ mService.mActiveUids.put(proc.uid, uidRec);
+ EventLogTags.writeAmUidRunning(uidRec.uid);
+ mService.noteUidProcessState(uidRec.uid, uidRec.curProcState);
+ }
+ proc.uidRecord = uidRec;
+
+ // Reset render thread tid if it was already set, so new process can set it again.
+ proc.renderThreadTid = 0;
+ uidRec.numProcs++;
+ mProcessNames.put(proc.processName, proc.uid, proc);
+ if (proc.isolated) {
+ mIsolatedProcesses.put(proc.uid, proc);
+ }
+ }
+
+ @GuardedBy("mService")
+ final ProcessRecord newProcessRecordLocked(ApplicationInfo info, String customProcess,
+ boolean isolated, int isolatedUid) {
+ String proc = customProcess != null ? customProcess : info.processName;
+ final int userId = UserHandle.getUserId(info.uid);
+ int uid = info.uid;
+ if (isolated) {
+ if (isolatedUid == 0) {
+ int stepsLeft = LAST_ISOLATED_UID - FIRST_ISOLATED_UID + 1;
+ while (true) {
+ if (mNextIsolatedProcessUid < FIRST_ISOLATED_UID
+ || mNextIsolatedProcessUid > LAST_ISOLATED_UID) {
+ mNextIsolatedProcessUid = FIRST_ISOLATED_UID;
+ }
+ uid = UserHandle.getUid(userId, mNextIsolatedProcessUid);
+ mNextIsolatedProcessUid++;
+ if (mIsolatedProcesses.indexOfKey(uid) < 0) {
+ // No process for this uid, use it.
+ break;
+ }
+ stepsLeft--;
+ if (stepsLeft <= 0) {
+ return null;
+ }
+ }
+ } else {
+ // Special case for startIsolatedProcess (internal only), where
+ // the uid of the isolated process is specified by the caller.
+ uid = isolatedUid;
+ }
+ mService.getPackageManagerInternalLocked().addIsolatedUid(uid, info.uid);
+
+ // Register the isolated UID with this application so BatteryStats knows to
+ // attribute resource usage to the application.
+ //
+ // NOTE: This is done here before addProcessNameLocked, which will tell BatteryStats
+ // about the process state of the isolated UID *before* it is registered with the
+ // owning application.
+ mService.mBatteryStatsService.addIsolatedUid(uid, info.uid);
+ StatsLog.write(StatsLog.ISOLATED_UID_CHANGED, info.uid, uid,
+ StatsLog.ISOLATED_UID_CHANGED__EVENT__CREATED);
+ }
+ final ProcessRecord r = new ProcessRecord(mService, info, proc, uid,
+ mService.getGlobalConfiguration());
+
+ if (!mService.mBooted && !mService.mBooting
+ && userId == UserHandle.USER_SYSTEM
+ && (info.flags & PERSISTENT_MASK) == PERSISTENT_MASK) {
+ // The system process is initialized to SCHED_GROUP_DEFAULT in init.rc.
+ r.setCurrentSchedulingGroup(ProcessList.SCHED_GROUP_DEFAULT);
+ r.setSchedGroup = ProcessList.SCHED_GROUP_DEFAULT;
+ r.setPersistent(true);
+ r.maxAdj = ProcessList.PERSISTENT_PROC_ADJ;
+ }
+ if (isolated && isolatedUid != 0) {
+ // Special case for startIsolatedProcess (internal only) - assume the process
+ // is required by the system server to prevent it being killed.
+ r.maxAdj = ProcessList.PERSISTENT_SERVICE_ADJ;
+ }
+ addProcessNameLocked(r);
+ return r;
+ }
+
+ @GuardedBy("mService")
+ final ProcessRecord removeProcessNameLocked(final String name, final int uid) {
+ return removeProcessNameLocked(name, uid, null);
+ }
+
+ @GuardedBy("mService")
+ final ProcessRecord removeProcessNameLocked(final String name, final int uid,
+ final ProcessRecord expecting) {
+ ProcessRecord old = mProcessNames.get(name, uid);
+ // Only actually remove when the currently recorded value matches the
+ // record that we expected; if it doesn't match then we raced with a
+ // newly created process and we don't want to destroy the new one.
+ if ((expecting == null) || (old == expecting)) {
+ mProcessNames.remove(name, uid);
+ }
+ if (old != null && old.uidRecord != null) {
+ old.uidRecord.numProcs--;
+ if (old.uidRecord.numProcs == 0) {
+ // No more processes using this uid, tell clients it is gone.
+ if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS,
+ "No more processes in " + old.uidRecord);
+ mService.enqueueUidChangeLocked(old.uidRecord, -1, UidRecord.CHANGE_GONE);
+ EventLogTags.writeAmUidStopped(uid);
+ mService.mActiveUids.remove(uid);
+ mService.noteUidProcessState(uid, ActivityManager.PROCESS_STATE_NONEXISTENT);
+ }
+ old.uidRecord = null;
+ }
+ mIsolatedProcesses.remove(uid);
+ return old;
+ }
+
+ /** Call setCoreSettings on all LRU processes, with the new settings. */
+ @GuardedBy("mService")
+ void updateCoreSettingsLocked(Bundle settings) {
+ for (int i = mLruProcesses.size() - 1; i >= 0; i--) {
+ ProcessRecord processRecord = mLruProcesses.get(i);
try {
- sLmkdOutputStream.write(buf.array(), 0, buf.position());
- return;
- } catch (IOException ex) {
- Slog.w(TAG, "Error writing to lowmemorykiller socket");
+ if (processRecord.thread != null) {
+ processRecord.thread.setCoreSettings(settings);
+ }
+ } catch (RemoteException re) {
+ /* ignore */
+ }
+ }
+ }
+ /**
+ * Kill all background processes except for ones with targetSdk lower than minTargetSdk and
+ * procstate lower than maxProcState.
+ * @param minTargetSdk
+ * @param maxProcState
+ */
+ @GuardedBy("mService")
+ void killAllBackgroundProcessesExceptLocked(int minTargetSdk, int maxProcState) {
+ final ArrayList<ProcessRecord> procs = new ArrayList<>();
+ final int NP = mProcessNames.getMap().size();
+ for (int ip = 0; ip < NP; ip++) {
+ final SparseArray<ProcessRecord> apps = mProcessNames.getMap().valueAt(ip);
+ final int NA = apps.size();
+ for (int ia = 0; ia < NA; ia++) {
+ final ProcessRecord app = apps.valueAt(ia);
+ if (app.removed) {
+ procs.add(app);
+ } else if ((minTargetSdk < 0 || app.info.targetSdkVersion < minTargetSdk)
+ && (maxProcState < 0 || app.setProcState > maxProcState)) {
+ app.removed = true;
+ procs.add(app);
+ }
+ }
+ }
+
+ final int N = procs.size();
+ for (int i = 0; i < N; i++) {
+ removeProcessLocked(procs.get(i), false, true, "kill all background except");
+ }
+ }
+
+ /**
+ * Call updateTimePrefs on all LRU processes
+ * @param timePref The time pref to pass to each process
+ */
+ @GuardedBy("mService")
+ void updateAllTimePrefsLocked(int timePref) {
+ for (int i = mLruProcesses.size() - 1; i >= 0; i--) {
+ ProcessRecord r = mLruProcesses.get(i);
+ if (r.thread != null) {
try {
- sLmkdSocket.close();
- } catch (IOException ex2) {
+ r.thread.updateTimePrefs(timePref);
+ } catch (RemoteException ex) {
+ Slog.w(TAG, "Failed to update preferences for: "
+ + r.info.processName);
}
+ }
+ }
+ }
- sLmkdSocket = null;
+ @GuardedBy("mService")
+ void setAllHttpProxyLocked(String host, String port, String exclList, Uri pacFileUrl) {
+ for (int i = mLruProcesses.size() - 1; i >= 0; i--) {
+ ProcessRecord r = mLruProcesses.get(i);
+ // Don't dispatch to isolated processes as they can't access
+ // ConnectivityManager and don't have network privileges anyway.
+ if (r.thread != null && !r.isolated) {
+ try {
+ r.thread.setHttpProxy(host, port, exclList, pacFileUrl);
+ } catch (RemoteException ex) {
+ Slog.w(TAG, "Failed to update http proxy for: " +
+ r.info.processName);
+ }
+ }
+ }
+ }
+
+ @GuardedBy("mService")
+ void clearAllDnsCacheLocked() {
+ for (int i = mLruProcesses.size() - 1; i >= 0; i--) {
+ ProcessRecord r = mLruProcesses.get(i);
+ if (r.thread != null) {
+ try {
+ r.thread.clearDnsCache();
+ } catch (RemoteException ex) {
+ Slog.w(TAG, "Failed to clear dns cache for: " + r.info.processName);
+ }
+ }
+ }
+ }
+
+ @GuardedBy("mService")
+ void handleAllTrustStorageUpdateLocked() {
+ for (int i = mLruProcesses.size() - 1; i >= 0; i--) {
+ ProcessRecord r = mLruProcesses.get(i);
+ if (r.thread != null) {
+ try {
+ r.thread.handleTrustStorageUpdate();
+ } catch (RemoteException ex) {
+ Slog.w(TAG, "Failed to handle trust storage update for: " +
+ r.info.processName);
+ }
+ }
+ }
+ }
+
+ @GuardedBy("mService")
+ int updateLruProcessInternalLocked(ProcessRecord app, long now, int index,
+ String what, Object obj, ProcessRecord srcApp) {
+ app.lastActivityTime = now;
+
+ if (app.hasActivitiesOrRecentTasks()) {
+ // Don't want to touch dependent processes that are hosting activities.
+ return index;
+ }
+
+ int lrui = mLruProcesses.lastIndexOf(app);
+ if (lrui < 0) {
+ Slog.wtf(TAG, "Adding dependent process " + app + " not on LRU list: "
+ + what + " " + obj + " from " + srcApp);
+ return index;
+ }
+
+ if (lrui >= index) {
+ // Don't want to cause this to move dependent processes *back* in the
+ // list as if they were less frequently used.
+ return index;
+ }
+
+ if (lrui >= mLruProcessActivityStart) {
+ // Don't want to touch dependent processes that are hosting activities.
+ return index;
+ }
+
+ mLruProcesses.remove(lrui);
+ if (index > 0) {
+ index--;
+ }
+ if (DEBUG_LRU) Slog.d(TAG_LRU, "Moving dep from " + lrui + " to " + index
+ + " in LRU list: " + app);
+ mLruProcesses.add(index, app);
+ return index;
+ }
+
+ final void updateLruProcessLocked(ProcessRecord app, boolean activityChange,
+ ProcessRecord client) {
+ final boolean hasActivity = app.hasActivitiesOrRecentTasks() || app.hasClientActivities()
+ || app.treatLikeActivity;
+ final boolean hasService = false; // not impl yet. app.services.size() > 0;
+ if (!activityChange && hasActivity) {
+ // The process has activities, so we are only allowing activity-based adjustments
+ // to move it. It should be kept in the front of the list with other
+ // processes that have activities, and we don't want those to change their
+ // order except due to activity operations.
+ return;
+ }
+
+ mLruSeq++;
+ final long now = SystemClock.uptimeMillis();
+ app.lastActivityTime = now;
+
+ // First a quick reject: if the app is already at the position we will
+ // put it, then there is nothing to do.
+ if (hasActivity) {
+ final int N = mLruProcesses.size();
+ if (N > 0 && mLruProcesses.get(N - 1) == app) {
+ if (DEBUG_LRU) Slog.d(TAG_LRU, "Not moving, already top activity: " + app);
+ return;
+ }
+ } else {
+ if (mLruProcessServiceStart > 0
+ && mLruProcesses.get(mLruProcessServiceStart-1) == app) {
+ if (DEBUG_LRU) Slog.d(TAG_LRU, "Not moving, already top other: " + app);
+ return;
+ }
+ }
+
+ int lrui = mLruProcesses.lastIndexOf(app);
+
+ if (app.isPersistent() && lrui >= 0) {
+ // We don't care about the position of persistent processes, as long as
+ // they are in the list.
+ if (DEBUG_LRU) Slog.d(TAG_LRU, "Not moving, persistent: " + app);
+ return;
+ }
+
+ /* In progress: compute new position first, so we can avoid doing work
+ if the process is not actually going to move. Not yet working.
+ int addIndex;
+ int nextIndex;
+ boolean inActivity = false, inService = false;
+ if (hasActivity) {
+ // Process has activities, put it at the very tipsy-top.
+ addIndex = mLruProcesses.size();
+ nextIndex = mLruProcessServiceStart;
+ inActivity = true;
+ } else if (hasService) {
+ // Process has services, put it at the top of the service list.
+ addIndex = mLruProcessActivityStart;
+ nextIndex = mLruProcessServiceStart;
+ inActivity = true;
+ inService = true;
+ } else {
+ // Process not otherwise of interest, it goes to the top of the non-service area.
+ addIndex = mLruProcessServiceStart;
+ if (client != null) {
+ int clientIndex = mLruProcesses.lastIndexOf(client);
+ if (clientIndex < 0) Slog.d(TAG, "Unknown client " + client + " when updating "
+ + app);
+ if (clientIndex >= 0 && addIndex > clientIndex) {
+ addIndex = clientIndex;
+ }
+ }
+ nextIndex = addIndex > 0 ? addIndex-1 : addIndex;
+ }
+
+ Slog.d(TAG, "Update LRU at " + lrui + " to " + addIndex + " (act="
+ + mLruProcessActivityStart + "): " + app);
+ */
+
+ if (lrui >= 0) {
+ if (lrui < mLruProcessActivityStart) {
+ mLruProcessActivityStart--;
+ }
+ if (lrui < mLruProcessServiceStart) {
+ mLruProcessServiceStart--;
+ }
+ /*
+ if (addIndex > lrui) {
+ addIndex--;
+ }
+ if (nextIndex > lrui) {
+ nextIndex--;
+ }
+ */
+ mLruProcesses.remove(lrui);
+ }
+
+ /*
+ mLruProcesses.add(addIndex, app);
+ if (inActivity) {
+ mLruProcessActivityStart++;
+ }
+ if (inService) {
+ mLruProcessActivityStart++;
+ }
+ */
+
+ int nextIndex;
+ if (hasActivity) {
+ final int N = mLruProcesses.size();
+ if ((!app.hasActivities() || app.hasRecentTasks())
+ && mLruProcessActivityStart < (N - 1)) {
+ // Process doesn't have activities, but has clients with
+ // activities... move it up, but one below the top (the top
+ // should always have a real activity).
+ if (DEBUG_LRU) Slog.d(TAG_LRU,
+ "Adding to second-top of LRU activity list: " + app);
+ mLruProcesses.add(N - 1, app);
+ // To keep it from spamming the LRU list (by making a bunch of clients),
+ // we will push down any other entries owned by the app.
+ final int uid = app.info.uid;
+ for (int i = N - 2; i > mLruProcessActivityStart; i--) {
+ ProcessRecord subProc = mLruProcesses.get(i);
+ if (subProc.info.uid == uid) {
+ // We want to push this one down the list. If the process after
+ // it is for the same uid, however, don't do so, because we don't
+ // want them internally to be re-ordered.
+ if (mLruProcesses.get(i - 1).info.uid != uid) {
+ if (DEBUG_LRU) Slog.d(TAG_LRU,
+ "Pushing uid " + uid + " swapping at " + i + ": "
+ + mLruProcesses.get(i) + " : "
+ + mLruProcesses.get(i - 1));
+ ProcessRecord tmp = mLruProcesses.get(i);
+ mLruProcesses.set(i, mLruProcesses.get(i - 1));
+ mLruProcesses.set(i - 1, tmp);
+ i--;
+ }
+ } else {
+ // A gap, we can stop here.
+ break;
+ }
+ }
+ } else {
+ // Process has activities, put it at the very tipsy-top.
+ if (DEBUG_LRU) Slog.d(TAG_LRU, "Adding to top of LRU activity list: " + app);
+ mLruProcesses.add(app);
+ }
+ nextIndex = mLruProcessServiceStart;
+ } else if (hasService) {
+ // Process has services, put it at the top of the service list.
+ if (DEBUG_LRU) Slog.d(TAG_LRU, "Adding to top of LRU service list: " + app);
+ mLruProcesses.add(mLruProcessActivityStart, app);
+ nextIndex = mLruProcessServiceStart;
+ mLruProcessActivityStart++;
+ } else {
+ // Process not otherwise of interest, it goes to the top of the non-service area.
+ int index = mLruProcessServiceStart;
+ if (client != null) {
+ // If there is a client, don't allow the process to be moved up higher
+ // in the list than that client.
+ int clientIndex = mLruProcesses.lastIndexOf(client);
+ if (DEBUG_LRU && clientIndex < 0) Slog.d(TAG_LRU, "Unknown client " + client
+ + " when updating " + app);
+ if (clientIndex <= lrui) {
+ // Don't allow the client index restriction to push it down farther in the
+ // list than it already is.
+ clientIndex = lrui;
+ }
+ if (clientIndex >= 0 && index > clientIndex) {
+ index = clientIndex;
+ }
+ }
+ if (DEBUG_LRU) Slog.d(TAG_LRU, "Adding at " + index + " of LRU list: " + app);
+ mLruProcesses.add(index, app);
+ nextIndex = index - 1;
+ mLruProcessActivityStart++;
+ mLruProcessServiceStart++;
+ }
+
+ // If the app is currently using a content provider or service,
+ // bump those processes as well.
+ for (int j = app.connections.size() - 1; j >= 0; j--) {
+ ConnectionRecord cr = app.connections.valueAt(j);
+ if (cr.binding != null && !cr.serviceDead && cr.binding.service != null
+ && cr.binding.service.app != null
+ && cr.binding.service.app.lruSeq != mLruSeq
+ && !cr.binding.service.app.isPersistent()) {
+ nextIndex = updateLruProcessInternalLocked(cr.binding.service.app,
+ now,
+ nextIndex,
+ "service connection", cr, app);
+ }
+ }
+ for (int j = app.conProviders.size() - 1; j >= 0; j--) {
+ ContentProviderRecord cpr = app.conProviders.get(j).provider;
+ if (cpr.proc != null && cpr.proc.lruSeq != mLruSeq && !cpr.proc.isPersistent()) {
+ nextIndex = updateLruProcessInternalLocked(cpr.proc, now, nextIndex,
+ "provider reference", cpr, app);
+ }
+ }
+ }
+
+ final ProcessRecord getLRURecordForAppLocked(IApplicationThread thread) {
+ final IBinder threadBinder = thread.asBinder();
+ // Find the application record.
+ for (int i = mLruProcesses.size() - 1; i >= 0; i--) {
+ final ProcessRecord rec = mLruProcesses.get(i);
+ if (rec.thread != null && rec.thread.asBinder() == threadBinder) {
+ return rec;
+ }
+ }
+ return null;
+ }
+
+ boolean haveBackgroundProcessLocked() {
+ for (int i = mLruProcesses.size() - 1; i >= 0; i--) {
+ final ProcessRecord rec = mLruProcesses.get(i);
+ if (rec.thread != null
+ && rec.setProcState >= PROCESS_STATE_CACHED_ACTIVITY) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private static int procStateToImportance(int procState, int memAdj,
+ ActivityManager.RunningAppProcessInfo currApp,
+ int clientTargetSdk) {
+ int imp = ActivityManager.RunningAppProcessInfo.procStateToImportanceForTargetSdk(
+ procState, clientTargetSdk);
+ if (imp == ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND) {
+ currApp.lru = memAdj;
+ } else {
+ currApp.lru = 0;
+ }
+ return imp;
+ }
+
+ @GuardedBy("mService")
+ void fillInProcMemInfoLocked(ProcessRecord app,
+ ActivityManager.RunningAppProcessInfo outInfo,
+ int clientTargetSdk) {
+ outInfo.pid = app.pid;
+ outInfo.uid = app.info.uid;
+ if (mService.mAtmInternal.isHeavyWeightProcess(app.getWindowProcessController())) {
+ outInfo.flags |= ActivityManager.RunningAppProcessInfo.FLAG_CANT_SAVE_STATE;
+ }
+ if (app.isPersistent()) {
+ outInfo.flags |= ActivityManager.RunningAppProcessInfo.FLAG_PERSISTENT;
+ }
+ if (app.hasActivities()) {
+ outInfo.flags |= ActivityManager.RunningAppProcessInfo.FLAG_HAS_ACTIVITIES;
+ }
+ outInfo.lastTrimLevel = app.trimMemoryLevel;
+ int adj = app.curAdj;
+ int procState = app.getCurProcState();
+ outInfo.importance = procStateToImportance(procState, adj, outInfo,
+ clientTargetSdk);
+ outInfo.importanceReasonCode = app.adjTypeCode;
+ outInfo.processState = app.getCurProcState();
+ outInfo.isFocused = (app == mService.getTopAppLocked());
+ outInfo.lastActivityTime = app.lastActivityTime;
+ }
+
+ @GuardedBy("mService")
+ List<ActivityManager.RunningAppProcessInfo> getRunningAppProcessesLocked(boolean allUsers,
+ int userId, boolean allUids, int callingUid, int clientTargetSdk) {
+ // Lazy instantiation of list
+ List<ActivityManager.RunningAppProcessInfo> runList = null;
+
+ for (int i = mLruProcesses.size() - 1; i >= 0; i--) {
+ ProcessRecord app = mLruProcesses.get(i);
+ if ((!allUsers && app.userId != userId)
+ || (!allUids && app.uid != callingUid)) {
+ continue;
+ }
+ if ((app.thread != null) && (!app.isCrashing() && !app.isNotResponding())) {
+ // Generate process state info for running application
+ ActivityManager.RunningAppProcessInfo currApp =
+ new ActivityManager.RunningAppProcessInfo(app.processName,
+ app.pid, app.getPackageList());
+ fillInProcMemInfoLocked(app, currApp, clientTargetSdk);
+ if (app.adjSource instanceof ProcessRecord) {
+ currApp.importanceReasonPid = ((ProcessRecord)app.adjSource).pid;
+ currApp.importanceReasonImportance =
+ ActivityManager.RunningAppProcessInfo.procStateToImportance(
+ app.adjSourceProcState);
+ } else if (app.adjSource instanceof ActivityRecord) {
+ ActivityRecord r = (ActivityRecord)app.adjSource;
+ if (r.app != null) currApp.importanceReasonPid = r.app.getPid();
+ }
+ if (app.adjTarget instanceof ComponentName) {
+ currApp.importanceReasonComponent = (ComponentName)app.adjTarget;
+ }
+ //Slog.v(TAG, "Proc " + app.processName + ": imp=" + currApp.importance
+ // + " lru=" + currApp.lru);
+ if (runList == null) {
+ runList = new ArrayList<>();
+ }
+ runList.add(currApp);
+ }
+ }
+ return runList;
+ }
+
+ @GuardedBy("mService")
+ int getLruSizeLocked() {
+ return mLruProcesses.size();
+ }
+
+ @GuardedBy("mService")
+ void dumpLruListHeaderLocked(PrintWriter pw) {
+ pw.print(" Process LRU list (sorted by oom_adj, "); pw.print(mLruProcesses.size());
+ pw.print(" total, non-act at ");
+ pw.print(mLruProcesses.size() - mLruProcessActivityStart);
+ pw.print(", non-svc at ");
+ pw.print(mLruProcesses.size() - mLruProcessServiceStart);
+ pw.println("):");
+ }
+
+ @GuardedBy("mService")
+ ArrayList<ProcessRecord> collectProcessesLocked(int start, boolean allPkgs, String[] args) {
+ ArrayList<ProcessRecord> procs;
+ if (args != null && args.length > start
+ && args[start].charAt(0) != '-') {
+ procs = new ArrayList<ProcessRecord>();
+ int pid = -1;
+ try {
+ pid = Integer.parseInt(args[start]);
+ } catch (NumberFormatException e) {
+ }
+ for (int i = mLruProcesses.size() - 1; i >= 0; i--) {
+ ProcessRecord proc = mLruProcesses.get(i);
+ if (proc.pid > 0 && proc.pid == pid) {
+ procs.add(proc);
+ } else if (allPkgs && proc.pkgList != null
+ && proc.pkgList.containsKey(args[start])) {
+ procs.add(proc);
+ } else if (proc.processName.equals(args[start])) {
+ procs.add(proc);
+ }
+ }
+ if (procs.size() <= 0) {
+ return null;
+ }
+ } else {
+ procs = new ArrayList<ProcessRecord>(mLruProcesses);
+ }
+ return procs;
+ }
+
+ @GuardedBy("mService")
+ void updateApplicationInfoLocked(List<String> packagesToUpdate, int userId,
+ boolean updateFrameworkRes) {
+ for (int i = mLruProcesses.size() - 1; i >= 0; i--) {
+ final ProcessRecord app = mLruProcesses.get(i);
+ if (app.thread == null) {
+ continue;
+ }
+
+ if (userId != UserHandle.USER_ALL && app.userId != userId) {
+ continue;
+ }
+
+ final int packageCount = app.pkgList.size();
+ for (int j = 0; j < packageCount; j++) {
+ final String packageName = app.pkgList.keyAt(j);
+ if (updateFrameworkRes || packagesToUpdate.contains(packageName)) {
+ try {
+ final ApplicationInfo ai = AppGlobals.getPackageManager()
+ .getApplicationInfo(packageName, STOCK_PM_FLAGS, app.userId);
+ if (ai != null) {
+ app.thread.scheduleApplicationInfoChanged(ai);
+ }
+ } catch (RemoteException e) {
+ Slog.w(TAG, String.format("Failed to update %s ApplicationInfo for %s",
+ packageName, app));
+ }
+ }
+ }
+ }
+ }
+
+ @GuardedBy("mService")
+ void sendPackageBroadcastLocked(int cmd, String[] packages, int userId) {
+ for (int i = mLruProcesses.size() - 1; i >= 0; i--) {
+ ProcessRecord r = mLruProcesses.get(i);
+ if (r.thread != null && (userId == UserHandle.USER_ALL || r.userId == userId)) {
+ try {
+ r.thread.dispatchPackageBroadcast(cmd, packages);
+ } catch (RemoteException ex) {
+ }
}
}
}
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index 83cd7eb62397..307c72a9726f 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -18,12 +18,17 @@ package com.android.server.am;
import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT;
+import static com.android.server.Watchdog.NATIVE_STACKS_OF_INTEREST;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ANR;
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.MY_PID;
import android.app.ActivityManager;
+import android.app.ApplicationErrorReport;
import android.app.Dialog;
import android.app.IApplicationThread;
+import android.app.ProfilerInfo;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.ApplicationInfo;
@@ -32,16 +37,19 @@ import android.content.res.Configuration;
import android.os.Binder;
import android.os.Debug;
import android.os.IBinder;
+import android.os.Message;
import android.os.Process;
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.Trace;
import android.os.UserHandle;
+import android.provider.Settings;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.DebugUtils;
import android.util.EventLog;
import android.util.Slog;
+import android.util.SparseArray;
import android.util.StatsLog;
import android.util.TimeUtils;
import android.util.proto.ProtoOutputStream;
@@ -50,7 +58,11 @@ import android.util.BoostFramework;
import com.android.internal.app.procstats.ProcessState;
import com.android.internal.app.procstats.ProcessStats;
import com.android.internal.os.BatteryStatsImpl;
+import com.android.internal.os.ProcessCpuTracker;
+import com.android.server.Watchdog;
+import java.io.File;
+import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
@@ -129,7 +141,7 @@ final class ProcessRecord implements WindowProcessListener {
long lastCachedPss; // Last computed pss when in cached state.
long lastCachedSwapPss; // Last computed SwapPss when in cached state.
int maxAdj; // Maximum OOM adjustment for this process
- int curRawAdj; // Current OOM unlimited adjustment for this process
+ private int mCurRawAdj; // Current OOM unlimited adjustment for this process
int setRawAdj; // Last set OOM unlimited adjustment for this process
int curAdj; // Current OOM adjustment for this process
int setAdj; // Last set OOM adjustment for this process
@@ -137,7 +149,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
@@ -147,19 +159,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
@@ -172,7 +184,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
@@ -181,8 +193,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
@@ -195,7 +207,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
@@ -363,7 +375,7 @@ final class ProcessRecord implements WindowProcessListener {
pw.print(" initialIdlePss="); pw.println(initialIdlePss);
}
pw.print(prefix); pw.print("oom: max="); pw.print(maxAdj);
- pw.print(" curRaw="); pw.print(curRawAdj);
+ pw.print(" curRaw="); pw.print(mCurRawAdj);
pw.print(" setRaw="); pw.print(setRawAdj);
pw.print(" cur="); pw.print(curAdj);
pw.print(" set="); pw.println(setAdj);
@@ -371,38 +383,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();
}
@@ -410,9 +422,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) {
@@ -439,7 +451,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=");
@@ -532,7 +544,7 @@ final class ProcessRecord implements WindowProcessListener {
userId = UserHandle.getUserId(_uid);
processName = _processName;
maxAdj = ProcessList.UNKNOWN_ADJ;
- curRawAdj = setRawAdj = ProcessList.INVALID_ADJ;
+ mCurRawAdj = setRawAdj = ProcessList.INVALID_ADJ;
curAdj = setAdj = verifiedAdj = ProcessList.INVALID_ADJ;
mPersistent = false;
removed = false;
@@ -555,11 +567,11 @@ final class ProcessRecord implements WindowProcessListener {
+ ",app_pid=" + pid + ",oom_adj=" + curAdj
+ ",setAdj=" + setAdj + ",hasShownUi=" + (hasShownUi ? 1 : 0)
+ ",cached=" + (cached ? 1 : 0)
- + ",fA=" + (foregroundActivities ? 1 : 0)
+ + ",fA=" + (mHasForegroundActivities ? 1 : 0)
+ ",fS=" + (mHasForegroundServices ? 1 : 0)
+ ",systemNoUi=" + (systemNoUi ? 1 : 0)
+ ",curSchedGroup=" + mCurSchedGroup
- + ",curProcState=" + curProcState + ",setProcState=" + setProcState
+ + ",curProcState=" + getCurProcState() + ",setProcState=" + setProcState
+ ",killed=" + (killed ? 1 : 0) + ",killedByAm=" + (killedByAm ? 1 : 0)
+ ",isDebugging=" + (isDebugging() ? 1 : 0);
android.util.SeempLog.record_str(386, seempStr);
@@ -600,11 +612,11 @@ final class ProcessRecord implements WindowProcessListener {
+ ",app_pid=" + pid + ",oom_adj=" + curAdj
+ ",setAdj=" + setAdj + ",hasShownUi=" + (hasShownUi ? 1 : 0)
+ ",cached=" + (cached ? 1 : 0)
- + ",fA=" + (foregroundActivities ? 1 : 0)
+ + ",fA=" + (mHasForegroundActivities ? 1 : 0)
+ ",fS=" + (mHasForegroundServices ? 1 : 0)
+ ",systemNoUi=" + (systemNoUi ? 1 : 0)
+ ",curSchedGroup=" + mCurSchedGroup
- + ",curProcState=" + curProcState + ",setProcState=" + setProcState
+ + ",curProcState=" + getCurProcState() + ",setProcState=" + setProcState
+ ",killed=" + (killed ? 1 : 0) + ",killedByAm=" + (killedByAm ? 1 : 0)
+ ",isDebugging=" + (isDebugging() ? 1 : 0);
android.util.SeempLog.record_str(387, seempStr);
@@ -749,7 +761,7 @@ final class ProcessRecord implements WindowProcessListener {
if (pid > 0) {
EventLog.writeEvent(EventLogTags.AM_KILL, userId, pid, processName, setAdj, reason);
Process.killProcessQuiet(pid);
- ActivityManagerService.killProcessGroup(uid, pid);
+ ProcessList.killProcessGroup(uid, pid);
} else {
pendingStart = false;
}
@@ -764,6 +776,7 @@ final class ProcessRecord implements WindowProcessListener {
}
}
+ @Override
public void writeToProto(ProtoOutputStream proto, long fieldId) {
long token = proto.start(fieldId);
proto.write(ProcessRecordProto.PID, pid);
@@ -854,6 +867,13 @@ final class ProcessRecord implements WindowProcessListener {
return null;
}
+ @Override
+ public void addPackage(String pkg, long versionCode) {
+ synchronized (mService) {
+ addPackage(pkg, versionCode, mService.mProcessStats);
+ }
+ }
+
/*
* Return true if package has been added false if not
*/
@@ -886,7 +906,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),
@@ -960,6 +981,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--) {
@@ -1020,6 +1050,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);
@@ -1047,6 +1140,15 @@ final class ProcessRecord implements WindowProcessListener {
return mInstr;
}
+ void setCurRawAdj(int curRawAdj) {
+ mCurRawAdj = curRawAdj;
+ mWindowProcessController.setPerceptible(curRawAdj <= ProcessList.PERCEPTIBLE_APP_ADJ);
+ }
+
+ int getCurRawAdj() {
+ return mCurRawAdj;
+ }
+
@Override
public void clearProfilerIfNeeded() {
synchronized (mService) {
@@ -1068,14 +1170,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);
}
}
@@ -1088,7 +1195,7 @@ final class ProcessRecord implements WindowProcessListener {
mService.mServices.updateServiceConnectionActivitiesLocked(this);
}
if (updateLru) {
- mService.updateLruProcessLocked(this, activityChange, null);
+ mService.mProcessList.updateLruProcessLocked(this, activityChange, null);
}
if (updateOomAdj) {
mService.updateOomAdjLocked();
@@ -1107,7 +1214,315 @@ final class ProcessRecord implements WindowProcessListener {
* Returns the total time (in milliseconds) spent executing in both user and system code.
* Safe to call without lock held.
*/
+ @Override
public long getCpuTime() {
return mService.mProcessCpuTracker.getCpuTimeForPid(pid);
}
+
+ @Override
+ public void clearWaitingToKill() {
+ synchronized (mService) {
+ waitingToKill = null;
+ }
+ }
+
+ @Override
+ public ProfilerInfo onStartActivity(int topProcessState) {
+ synchronized (mService) {
+ ProfilerInfo profilerInfo = null;
+ if (mService.mProfileApp != null && mService.mProfileApp.equals(processName)) {
+ if (mService.mProfileProc == null || mService.mProfileProc == this) {
+ mService.mProfileProc = this;
+ final ProfilerInfo profilerInfoSvc = mService.mProfilerInfo;
+ if (profilerInfoSvc != null && profilerInfoSvc.profileFile != null) {
+ if (profilerInfoSvc.profileFd != null) {
+ try {
+ profilerInfoSvc.profileFd = profilerInfoSvc.profileFd.dup();
+ } catch (IOException e) {
+ profilerInfoSvc.closeFd();
+ }
+ }
+
+ profilerInfo = new ProfilerInfo(profilerInfoSvc);
+ }
+ }
+ }
+
+ hasShownUi = true;
+ setPendingUiClean(true);
+ forceProcessStateUpTo(topProcessState);
+
+ return profilerInfo;
+ }
+ }
+
+ @Override
+ public void appDied() {
+ synchronized (mService) {
+ mService.appDiedLocked(this);
+ }
+ }
+
+ public long getInputDispatchingTimeout() {
+ return mWindowProcessController.getInputDispatchingTimeout();
+ }
+
+ void appNotResponding(String activityShortComponentName, ApplicationInfo aInfo,
+ String parentShortComponentName, WindowProcessController parentProcess,
+ boolean aboveSystem, String annotation) {
+ ArrayList<Integer> firstPids = new ArrayList<>(5);
+ SparseArray<Boolean> lastPids = new SparseArray<>(20);
+
+ if (mService.mActivityTaskManager.mController != null) {
+ try {
+ // 0 == continue, -1 = kill process immediately
+ int res = mService.mActivityTaskManager.mController.appEarlyNotResponding(
+ processName, pid, annotation);
+ if (res < 0 && pid != MY_PID) {
+ kill("anr", true);
+ }
+ } catch (RemoteException e) {
+ mService.mActivityTaskManager.mController = null;
+ Watchdog.getInstance().setActivityController(null);
+ }
+ }
+
+ long anrTime = SystemClock.uptimeMillis();
+ if (ActivityManagerService.MONITOR_CPU_USAGE) {
+ mService.updateCpuStatsNow();
+ }
+
+ // Unless configured otherwise, swallow ANRs in background processes & kill the process.
+ boolean showBackground = Settings.Secure.getInt(mService.mContext.getContentResolver(),
+ Settings.Secure.ANR_SHOW_BACKGROUND, 0) != 0;
+
+ boolean isSilentANR;
+
+ synchronized (mService) {
+ // PowerManager.reboot() can block for a long time, so ignore ANRs while shutting down.
+ if (mService.mActivityTaskManager.mShuttingDown) {
+ Slog.i(TAG, "During shutdown skipping ANR: " + this + " " + annotation);
+ return;
+ } else if (isNotResponding()) {
+ Slog.i(TAG, "Skipping duplicate ANR: " + this + " " + annotation);
+ return;
+ } else if (isCrashing()) {
+ Slog.i(TAG, "Crashing app skipping ANR: " + this + " " + annotation);
+ return;
+ } else if (killedByAm) {
+ Slog.i(TAG, "App already killed by AM skipping ANR: " + this + " " + annotation);
+ return;
+ } else if (killed) {
+ Slog.i(TAG, "Skipping died app ANR: " + this + " " + annotation);
+ return;
+ }
+
+ // In case we come through here for the same app before completing
+ // this one, mark as anring now so we will bail out.
+ setNotResponding(true);
+
+ // Log the ANR to the event log.
+ EventLog.writeEvent(EventLogTags.AM_ANR, userId, pid, processName, info.flags,
+ annotation);
+
+ // Dump thread traces as quickly as we can, starting with "interesting" processes.
+ firstPids.add(pid);
+
+ // Don't dump other PIDs if it's a background ANR
+ isSilentANR = !showBackground && !isInterestingForBackgroundTraces();
+ if (!isSilentANR) {
+ int parentPid = pid;
+ if (parentProcess != null && parentProcess.getPid() > 0) {
+ parentPid = parentProcess.getPid();
+ }
+ if (parentPid != pid) firstPids.add(parentPid);
+
+ if (MY_PID != pid && MY_PID != parentPid) firstPids.add(MY_PID);
+
+ for (int i = mService.mProcessList.mLruProcesses.size() - 1; i >= 0; i--) {
+ ProcessRecord r = mService.mProcessList.mLruProcesses.get(i);
+ if (r != null && r.thread != null) {
+ int myPid = r.pid;
+ if (myPid > 0 && myPid != pid && myPid != parentPid && myPid != MY_PID) {
+ if (r.isPersistent()) {
+ firstPids.add(myPid);
+ if (DEBUG_ANR) Slog.i(TAG, "Adding persistent proc: " + r);
+ } else if (r.treatLikeActivity) {
+ firstPids.add(myPid);
+ if (DEBUG_ANR) Slog.i(TAG, "Adding likely IME: " + r);
+ } else {
+ lastPids.put(myPid, Boolean.TRUE);
+ if (DEBUG_ANR) Slog.i(TAG, "Adding ANR proc: " + r);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // Log the ANR to the main log.
+ StringBuilder info = new StringBuilder();
+ info.setLength(0);
+ info.append("ANR in ").append(processName);
+ if (activityShortComponentName != null) {
+ info.append(" (").append(activityShortComponentName).append(")");
+ }
+ info.append("\n");
+ info.append("PID: ").append(pid).append("\n");
+ if (annotation != null) {
+ info.append("Reason: ").append(annotation).append("\n");
+ }
+ if (parentShortComponentName != null
+ && parentShortComponentName.equals(activityShortComponentName)) {
+ info.append("Parent: ").append(parentShortComponentName).append("\n");
+ }
+
+ ProcessCpuTracker processCpuTracker = new ProcessCpuTracker(true);
+
+ // don't dump native PIDs for background ANRs unless it is the process of interest
+ String[] nativeProcs = null;
+ if (isSilentANR) {
+ for (int i = 0; i < NATIVE_STACKS_OF_INTEREST.length; i++) {
+ if (NATIVE_STACKS_OF_INTEREST[i].equals(processName)) {
+ nativeProcs = new String[] { processName };
+ break;
+ }
+ }
+ } else {
+ nativeProcs = NATIVE_STACKS_OF_INTEREST;
+ }
+
+ int[] pids = nativeProcs == null ? null : Process.getPidsForCommands(nativeProcs);
+ ArrayList<Integer> nativePids = null;
+
+ if (pids != null) {
+ nativePids = new ArrayList<>(pids.length);
+ for (int i : pids) {
+ nativePids.add(i);
+ }
+ }
+
+ // For background ANRs, don't pass the ProcessCpuTracker to
+ // avoid spending 1/2 second collecting stats to rank lastPids.
+ File tracesFile = ActivityManagerService.dumpStackTraces(firstPids,
+ (isSilentANR) ? null : processCpuTracker, (isSilentANR) ? null : lastPids,
+ nativePids);
+
+ String cpuInfo = null;
+ if (ActivityManagerService.MONITOR_CPU_USAGE) {
+ mService.updateCpuStatsNow();
+ synchronized (mService.mProcessCpuTracker) {
+ cpuInfo = mService.mProcessCpuTracker.printCurrentState(anrTime);
+ }
+ info.append(processCpuTracker.printCurrentLoad());
+ info.append(cpuInfo);
+ }
+
+ info.append(processCpuTracker.printCurrentState(anrTime));
+
+ Slog.e(TAG, info.toString());
+ if (tracesFile == null) {
+ // There is no trace file, so dump (only) the alleged culprit's threads to the log
+ Process.sendSignal(pid, Process.SIGNAL_QUIT);
+ }
+
+ StatsLog.write(StatsLog.ANR_OCCURRED, uid, processName,
+ activityShortComponentName == null ? "unknown": activityShortComponentName,
+ annotation,
+ (this.info != null) ? (this.info.isInstantApp()
+ ? StatsLog.ANROCCURRED__IS_INSTANT_APP__TRUE
+ : StatsLog.ANROCCURRED__IS_INSTANT_APP__FALSE)
+ : StatsLog.ANROCCURRED__IS_INSTANT_APP__UNAVAILABLE,
+ isInterestingToUserLocked()
+ ? StatsLog.ANROCCURRED__FOREGROUND_STATE__FOREGROUND
+ : StatsLog.ANROCCURRED__FOREGROUND_STATE__BACKGROUND);
+ final ProcessRecord parentPr = parentProcess != null
+ ? (ProcessRecord) parentProcess.mOwner : null;
+ mService.addErrorToDropBox("anr", this, processName, activityShortComponentName,
+ parentShortComponentName, parentPr, annotation, cpuInfo, tracesFile, null);
+
+ if (mService.mActivityTaskManager.mController != null) {
+ try {
+ // 0 == show dialog, 1 = keep waiting, -1 = kill process immediately
+ int res = mService.mActivityTaskManager.mController.appNotResponding(
+ processName, pid, info.toString());
+ if (res != 0) {
+ if (res < 0 && pid != MY_PID) {
+ kill("anr", true);
+ } else {
+ synchronized (mService) {
+ mService.mServices.scheduleServiceTimeoutLocked(this);
+ }
+ }
+ return;
+ }
+ } catch (RemoteException e) {
+ mService.mActivityTaskManager.mController = null;
+ Watchdog.getInstance().setActivityController(null);
+ }
+ }
+
+ synchronized (mService) {
+ mService.mBatteryStatsService.noteProcessAnr(processName, uid);
+
+ if (isSilentANR) {
+ kill("bg anr", true);
+ return;
+ }
+
+ // Set the app's notResponding state, and look up the errorReportReceiver
+ makeAppNotRespondingLocked(activityShortComponentName,
+ annotation != null ? "ANR " + annotation : "ANR", info.toString());
+
+ // Bring up the infamous App Not Responding dialog
+ Message msg = Message.obtain();
+ msg.what = ActivityManagerService.SHOW_NOT_RESPONDING_UI_MSG;
+ msg.obj = new AppNotRespondingDialog.Data(this, aInfo, aboveSystem);
+
+ mService.mUiHandler.sendMessage(msg);
+ }
+ }
+
+ private void makeAppNotRespondingLocked(String activity, String shortMsg, String longMsg) {
+ setNotResponding(true);
+ notRespondingReport = mService.mAppErrors.generateProcessError(this,
+ ActivityManager.ProcessErrorStateInfo.NOT_RESPONDING,
+ activity, shortMsg, longMsg, null);
+ startAppProblemLocked();
+ getWindowProcessController().stopFreezingActivities();
+ }
+
+ void startAppProblemLocked() {
+ // If this app is not running under the current user, then we can't give it a report button
+ // because that would require launching the report UI under a different user.
+ errorReportReceiver = null;
+
+ for (int userId : mService.mUserController.getCurrentProfileIds()) {
+ if (this.userId == userId) {
+ errorReportReceiver = ApplicationErrorReport.getErrorReportReceiver(
+ mService.mContext, info.packageName, info.flags);
+ }
+ }
+ mService.skipCurrentReceiverLocked(this);
+ }
+
+ private boolean isInterestingForBackgroundTraces() {
+ // The system_server is always considered interesting.
+ if (pid == MY_PID) {
+ return true;
+ }
+
+ // A package is considered interesting if any of the following is true :
+ //
+ // - It's displaying an activity.
+ // - It's the SystemUI.
+ // - It has an overlay or a top UI visible.
+ //
+ // NOTE: The check whether a given ProcessRecord belongs to the systemui
+ // process is a bit of a kludge, but the same pattern seems repeated at
+ // several places in the system server.
+ return isInterestingToUserLocked() ||
+ (info != null && "com.android.systemui".equals(info.packageName))
+ || (hasTopUi() || hasOverlayUi());
+ }
}
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..111adecb933f 100644
--- a/services/core/java/com/android/server/am/TaskLaunchParamsModifier.java
+++ b/services/core/java/com/android/server/am/TaskLaunchParamsModifier.java
@@ -16,304 +16,788 @@
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()) {
+ initLogBuilder(task, activity);
+ final int result = calculate(task, layout, activity, source, options, currentParams,
+ outParams);
+ outputLog();
+ return result;
+ }
+
+ private int calculate(TaskRecord task, ActivityInfo.WindowLayout layout,
+ ActivityRecord activity, ActivityRecord source, ActivityOptions options,
+ LaunchParams currentParams, LaunchParams outParams) {
+ final ActivityRecord root;
+ if (task != null) {
+ root = task.getRootActivity() == null ? activity : task.getRootActivity();
+ } else {
+ root = activity;
+ }
+
+ // TODO: Investigate whether we can safely ignore all cases where we don't have root
+ // activity available. Note we can't know if the bounds are valid if we're not sure of the
+ // requested orientation of the root activity. Therefore if we found such a case we may need
+ // to pass the activity into this modifier in that case.
+ if (root == null) {
+ // There is a case that can lead us here. The caller is moving the top activity that is
+ // in a task that has multiple activities to PIP mode. For that the caller is creating a
+ // new task to host the activity so that we only move the top activity to PIP mode and
+ // keep other activities in the previous task. There is no point to apply the launch
+ // logic in this case.
return RESULT_SKIP;
}
- final ArrayList<TaskRecord> tasks = task.getStack().getAllTasks();
+ // 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());
+ // 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 treats 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, launchMode);
+ if (mSupervisor.canUseActivityOptionsLaunchBounds(options)
+ && (canApplyFreeformPolicy || canApplyPipWindowPolicy(launchMode))) {
+ 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, int launchMode) {
+ return mSupervisor.mService.mSupportsFreeformWindowManagement
+ && (display.inFreeformWindowingMode() || launchMode == WINDOWING_MODE_FREEFORM);
}
- @VisibleForTesting
- static int getFreeformStartTop(Rect bounds) {
- return bounds.top + bounds.height() / MARGIN_SIZE_DENOMINATOR;
+ private boolean canApplyPipWindowPolicy(int launchMode) {
+ return mSupervisor.mService.mSupportsPictureInPicture
+ && launchMode == WINDOWING_MODE_PINNED;
}
- @VisibleForTesting
- static int getFreeformWidth(Rect bounds) {
- return bounds.width() / WINDOW_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 getFreeformHeight(Rect bounds) {
- return bounds.height() / 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 getHorizontalStep(Rect bounds) {
- return Math.max(bounds.width() / STEP_DENOMINATOR, MINIMAL_STEP);
+ private boolean isNOrGreater(@NonNull ActivityRecord root) {
+ return root.appInfo.targetSdkVersion >= Build.VERSION_CODES.N;
}
- @VisibleForTesting
- static int getVerticalStep(Rect bounds) {
- return Math.max(bounds.height() / STEP_DENOMINATOR, MINIMAL_STEP);
+ /**
+ * 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;
}
+ private boolean isPreNResizeable(ActivityRecord root) {
+ return root.appInfo.targetSdkVersion < Build.VERSION_CODES.N && root.isResizeable();
+ }
+ private void cascadeBounds(@NonNull Rect srcBounds, @NonNull ActivityDisplay display,
+ @NonNull Rect outBounds) {
+ outBounds.set(srcBounds);
+ float density = (float) display.getConfiguration().densityDpi / DENSITY_DEFAULT;
+ final int defaultOffset = (int) (CASCADING_OFFSET_DP * density + 0.5f);
- private int getFinalWidth(ActivityInfo.WindowLayout windowLayout, Rect availableRect) {
- int width = getFreeformWidth(availableRect);
- if (windowLayout.width > 0) {
- width = windowLayout.width;
+ 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 (windowLayout.widthFraction > 0) {
- width = (int) (availableRect.width() * windowLayout.widthFraction);
+
+ 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;
}
- return width;
- }
- private int getFinalHeight(ActivityInfo.WindowLayout windowLayout, Rect availableRect) {
- int height = getFreeformHeight(availableRect);
- if (windowLayout.height > 0) {
- height = windowLayout.height;
+ 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.heightFraction > 0) {
- height = (int) (availableRect.height() * windowLayout.heightFraction);
+
+ // 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 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);
+ // Lastly we adjust bounds to avoid conflicts with other tasks as much as possible.
+ adjustBoundsToAvoidConflict(display, inOutBounds);
}
- 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 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 (orientation == SCREEN_ORIENTATION_UNSPECIFIED) {
+ orientation = bounds.isEmpty() ? SCREEN_ORIENTATION_PORTRAIT
+ : orientationFromBounds(bounds);
+ if (DEBUG) {
+ appendLog(bounds.isEmpty() ? "default-portrait"
+ : "orientation-from-bounds=" + bounds);
+ }
+ }
+
+ return orientation;
}
- 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);
+ 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 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);
+ /**
+ * 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 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);
+ 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;
+ }
+
+ 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/UserController.java b/services/core/java/com/android/server/am/UserController.java
index 3a897c4d525c..d2dd3db70118 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -2242,21 +2242,15 @@ class UserController implements Handler.Callback {
}
void stackSupervisorRemoveUser(int userId) {
- synchronized (mService) {
- mService.mStackSupervisor.removeUserLocked(userId);
- }
+ mService.mAtmInternal.removeUser(userId);
}
protected boolean stackSupervisorSwitchUser(int userId, UserState uss) {
- synchronized (mService) {
- return mService.mStackSupervisor.switchUserLocked(userId, uss);
- }
+ return mService.mAtmInternal.switchUser(userId, uss);
}
protected void stackSupervisorResumeFocusedStackTopActivity() {
- synchronized (mService) {
- mService.mStackSupervisor.resumeFocusedStacksTopActivitiesLocked();
- }
+ mService.mAtmInternal.resumeTopActivities(false /* scheduleIdle */);
}
protected void clearAllLockedTasks(String reason) {
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..1743ddeedd91 100644
--- a/services/core/java/com/android/server/am/WindowProcessController.java
+++ b/services/core/java/com/android/server/am/WindowProcessController.java
@@ -18,22 +18,26 @@ 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;
import static com.android.server.am.ActivityStack.ActivityState.PAUSING;
import static com.android.server.am.ActivityStack.ActivityState.RESUMED;
import static com.android.server.am.ActivityStack.ActivityState.STOPPING;
+import static com.android.server.am.ActivityTaskManagerService.INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT_MS;
+import static com.android.server.am.ActivityTaskManagerService.KEY_DISPATCHING_TIMEOUT_MS;
+import static com.android.server.am.ActivityTaskManagerService.RELAUNCH_REASON_NONE;
import android.app.Activity;
import android.app.ActivityThread;
import android.app.IApplicationThread;
+import android.app.ProfilerInfo;
import android.app.servertransaction.ConfigurationChangeItem;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
@@ -44,6 +48,7 @@ import android.util.ArraySet;
import android.util.Log;
import android.util.Slog;
+import android.util.proto.ProtoOutputStream;
import com.android.internal.app.HeavyWeightSwitcherActivity;
import com.android.internal.util.function.pooled.PooledLambda;
import com.android.server.wm.ConfigurationContainer;
@@ -63,7 +68,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 +92,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,10 +106,34 @@ 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?
private volatile boolean mInstrumenting;
+ // This process it perceptible by the user.
+ private volatile boolean mPerceptible;
// Set to true when process was launched with a wrapper attached
private volatile boolean mUsingWrapper;
@@ -161,6 +192,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 +240,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;
}
@@ -233,6 +344,14 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
return mInstrumenting;
}
+ public void setPerceptible(boolean perceptible) {
+ mPerceptible = perceptible;
+ }
+
+ boolean isPerceptible() {
+ return mPerceptible;
+ }
+
@Override
protected int getChildCount() {
return 0;
@@ -500,12 +619,19 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
final int activitiesSize = mActivities.size();
for (int i = activitiesSize - 1; i >= 0; i--) {
final ActivityRecord r = mActivities.get(i);
- if (r.mRelaunchReason != ActivityRecord.RELAUNCH_REASON_NONE) {
+ if (r.mRelaunchReason != RELAUNCH_REASON_NONE) {
return r.mRelaunchReason;
}
}
}
- return ActivityRecord.RELAUNCH_REASON_NONE;
+ return RELAUNCH_REASON_NONE;
+ }
+
+ public long getInputDispatchingTimeout() {
+ synchronized (mAtm.mGlobalLock) {
+ return isInstrumenting() || isUsingWrapper()
+ ? INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT_MS : KEY_DISPATCHING_TIMEOUT_MS;
+ }
}
void clearProfilerIfNeeded() {
@@ -532,31 +658,52 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
WindowProcessListener::updateServiceConnectionActivities, mListener));
}
- void setPendingUiClean(boolean pendingUiClean) {
+ void setPendingUiCleanAndForceProcessStateUpTo(int newState) {
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);
+ WindowProcessListener::setPendingUiCleanAndForceProcessStateUpTo,
+ mListener, newState);
mAtm.mH.sendMessage(m);
}
- void setPendingUiCleanAndForceProcessStateUpTo(int newState) {
+ void setRemoved(boolean removed) {
if (mListener == null) return;
// Posting on handler so WM lock isn't held when we call into AM.
final Message m = PooledLambda.obtainMessage(
- WindowProcessListener::setPendingUiCleanAndForceProcessStateUpTo,
- mListener, newState);
+ WindowProcessListener::setRemoved, mListener, removed);
mAtm.mH.sendMessage(m);
}
- void setRemoved(boolean removed) {
+ void clearWaitingToKill() {
if (mListener == null) return;
// Posting on handler so WM lock isn't held when we call into AM.
final Message m = PooledLambda.obtainMessage(
- WindowProcessListener::setRemoved, mListener, removed);
+ WindowProcessListener::clearWaitingToKill, mListener);
mAtm.mH.sendMessage(m);
}
+ void addPackage(String pkg, long versionCode) {
+ // TODO(b/80414790): Calling directly into AM for now which can lead to deadlock once we are
+ // using WM lock. Need to figure-out if it is okay to do this asynchronously.
+ if (mListener == null) return;
+ mListener.addPackage(pkg, versionCode);
+ }
+
+ ProfilerInfo onStartActivity(int topProcessState) {
+ // TODO(b/80414790): Calling directly into AM for now which can lead to deadlock once we are
+ // using WM lock. Need to figure-out if it is okay to do this asynchronously.
+ if (mListener == null) return null;
+ return mListener.onStartActivity(topProcessState);
+ }
+
+ public void appDied() {
+ // TODO(b/80414790): Calling directly into AM for now which can lead to deadlock once we are
+ // using WM lock. Need to figure-out if it is okay to do this asynchronously.
+ if (mListener == null) return;
+ mListener.appDied();
+ }
+
@Override
public void onConfigurationChanged(Configuration newGlobalConfig) {
super.onConfigurationChanged(newGlobalConfig);
@@ -654,4 +801,9 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
pw.println(prefix + " mLastReportedConfiguration=" + mLastReportedConfiguration);
}
+ void writeToProto(ProtoOutputStream proto, long fieldId) {
+ if (mListener != null) {
+ mListener.writeToProto(proto, fieldId);
+ }
+ }
}
diff --git a/services/core/java/com/android/server/am/WindowProcessListener.java b/services/core/java/com/android/server/am/WindowProcessListener.java
index 2de3e3763028..4a7e6e8a38fe 100644
--- a/services/core/java/com/android/server/am/WindowProcessListener.java
+++ b/services/core/java/com/android/server/am/WindowProcessListener.java
@@ -16,6 +16,10 @@
package com.android.server.am;
+import android.app.ProfilerInfo;
+import android.content.pm.ApplicationInfo;
+import android.util.proto.ProtoOutputStream;
+
/**
* Interface used by the owner/creator of a process that owns windows to listen to changes from the
* WM side.
@@ -47,4 +51,17 @@ public interface WindowProcessListener {
/** Returns the total time (in milliseconds) spent executing in both user and system code. */
long getCpuTime();
+
+ /** Clears the waiting to kill reason for this process. */
+ void clearWaitingToKill();
+
+ /** Adds the package to the process. */
+ void addPackage(String pkg, long versionCode);
+
+ /** Called when we are in the process on starting an activity. */
+ ProfilerInfo onStartActivity(int topProcessState);
+
+ /** App died :(...oh well */
+ void appDied();
+ void writeToProto(ProtoOutputStream proto, long fieldId);
}
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index e9a105e3bf85..d841a9f434b9 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -4836,22 +4836,15 @@ public class AudioService extends IAudioService.Stub
}
}
- @Override
- public void setHearingAidDeviceConnectionState(BluetoothDevice device, int state)
- {
- mDeviceLogger.log((new AudioEventLogger.StringEvent(
- "setHearingAidDeviceConnectionState state=" + state
- + " addr=" + device.getAddress())).printLog(TAG));
-
- setBluetoothHearingAidDeviceConnectionState(
- device, state, false /* suppressNoisyIntent */, AudioSystem.DEVICE_NONE);
- }
-
public int setBluetoothHearingAidDeviceConnectionState(
BluetoothDevice device, int state, boolean suppressNoisyIntent,
int musicDevice)
{
int delay;
+ mDeviceLogger.log((new AudioEventLogger.StringEvent(
+ "setHearingAidDeviceConnectionState state=" + state
+ + " addr=" + device.getAddress()
+ + " supprNoisy=" + suppressNoisyIntent)).printLog(TAG));
synchronized (mConnectedDevices) {
if (!suppressNoisyIntent) {
int intState = (state == BluetoothHearingAid.STATE_CONNECTED) ? 1 : 0;
@@ -6042,6 +6035,7 @@ public class AudioService extends IAudioService.Stub
address));
sendMsg(mAudioHandler, MSG_ACCESSORY_PLUG_MEDIA_UNMUTE, SENDMSG_QUEUE,
AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0, null, 0);
+ setCurrentAudioRouteNameIfPossible(name);
}
private void onSendBecomingNoisyIntent() {
@@ -6063,7 +6057,7 @@ public class AudioService extends IAudioService.Stub
mConnectedDevices.remove(
makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address));
// Remove A2DP routes as well
- setCurrentAudioRouteName(null);
+ setCurrentAudioRouteNameIfPossible(null);
if (mDockAddress == address) {
mDockAddress = null;
}
@@ -6130,6 +6124,10 @@ public class AudioService extends IAudioService.Stub
address));
sendMsg(mAudioHandler, MSG_ACCESSORY_PLUG_MEDIA_UNMUTE, SENDMSG_QUEUE,
AudioSystem.DEVICE_OUT_HEARING_AID, 0, null, 0);
+ sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
+ AudioSystem.DEVICE_OUT_HEARING_AID, 0,
+ mStreamStates[AudioSystem.STREAM_MUSIC], 0);
+ setCurrentAudioRouteNameIfPossible(name);
}
// must be called synchronized on mConnectedDevices
@@ -6139,7 +6137,7 @@ public class AudioService extends IAudioService.Stub
mConnectedDevices.remove(
makeDeviceListKey(AudioSystem.DEVICE_OUT_HEARING_AID, address));
// Remove Hearing Aid routes as well
- setCurrentAudioRouteName(null);
+ setCurrentAudioRouteNameIfPossible(null);
}
// must be called synchronized on mConnectedDevices
@@ -6184,7 +6182,6 @@ public class AudioService extends IAudioService.Stub
} else {
makeA2dpDeviceUnavailableNow(address);
}
- setCurrentAudioRouteName(null);
} else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) {
if (btDevice.isBluetoothDock()) {
// this could be a reconnection after a transient disconnection
@@ -6208,7 +6205,6 @@ public class AudioService extends IAudioService.Stub
}
makeA2dpDeviceAvailable(address, btDevice.getName(),
"onSetA2dpSinkConnectionState");
- setCurrentAudioRouteName(btDevice.getAliasName());
}
}
}
@@ -6260,25 +6256,35 @@ public class AudioService extends IAudioService.Stub
if (isConnected && state != BluetoothProfile.STATE_CONNECTED) {
makeHearingAidDeviceUnavailable(address);
- setCurrentAudioRouteName(null);
} else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) {
makeHearingAidDeviceAvailable(address, btDevice.getName(),
"onSetHearingAidConnectionState");
- setCurrentAudioRouteName(btDevice.getAliasName());
}
}
}
- private void setCurrentAudioRouteName(String name){
+ private void setCurrentAudioRouteNameIfPossible(String name) {
synchronized (mCurAudioRoutes) {
if (!TextUtils.equals(mCurAudioRoutes.bluetoothName, name)) {
- mCurAudioRoutes.bluetoothName = name;
- sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
- SENDMSG_NOOP, 0, 0, null, 0);
+ if (name != null || !isCurrentDeviceConnected()) {
+ mCurAudioRoutes.bluetoothName = name;
+ sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
+ SENDMSG_NOOP, 0, 0, null, 0);
+ }
}
}
}
+ private boolean isCurrentDeviceConnected() {
+ for (int i = 0; i < mConnectedDevices.size(); i++) {
+ DeviceListSpec deviceSpec = mConnectedDevices.valueAt(i);
+ if (TextUtils.equals(deviceSpec.mDeviceName, mCurAudioRoutes.bluetoothName)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
private void onBluetoothA2dpDeviceConfigChange(BluetoothDevice btDevice)
{
if (DEBUG_DEVICES) {
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/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index c16d3cd5b4a5..b148a2f3fff5 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -307,19 +307,19 @@ public class HdmiControlService extends SystemService {
private final class CecMessageBuffer {
private List<HdmiCecMessage> mBuffer = new ArrayList<>();
- public void bufferMessage(HdmiCecMessage message) {
+ public boolean bufferMessage(HdmiCecMessage message) {
switch (message.getOpcode()) {
case Constants.MESSAGE_ACTIVE_SOURCE:
bufferActiveSource(message);
- break;
+ return true;
case Constants.MESSAGE_IMAGE_VIEW_ON:
case Constants.MESSAGE_TEXT_VIEW_ON:
bufferImageOrTextViewOn(message);
- break;
+ return true;
// Add here if new message that needs to buffer
default:
// Do not need to buffer messages other than above
- break;
+ return false;
}
}
@@ -906,10 +906,6 @@ public class HdmiControlService extends SystemService {
@ServiceThreadOnly
boolean handleCecCommand(HdmiCecMessage message) {
assertRunOnServiceThread();
- if (!mAddressAllocated) {
- mCecMessageBuffer.bufferMessage(message);
- return true;
- }
int errorCode = mMessageValidator.isValid(message);
if (errorCode != HdmiCecMessageValidator.OK) {
// We'll not response on the messages with the invalid source or destination
@@ -919,7 +915,12 @@ public class HdmiControlService extends SystemService {
}
return true;
}
- return dispatchMessageToLocalDevice(message);
+
+ if (dispatchMessageToLocalDevice(message)) {
+ return true;
+ }
+
+ return (!mAddressAllocated) ? mCecMessageBuffer.bufferMessage(message) : false;
}
void enableAudioReturnChannel(int portId, boolean enabled) {
diff --git a/services/core/java/com/android/server/hdmi/SystemAudioAutoInitiationAction.java b/services/core/java/com/android/server/hdmi/SystemAudioAutoInitiationAction.java
index d347a9188dee..f7e871d0b645 100644
--- a/services/core/java/com/android/server/hdmi/SystemAudioAutoInitiationAction.java
+++ b/services/core/java/com/android/server/hdmi/SystemAudioAutoInitiationAction.java
@@ -50,8 +50,7 @@ final class SystemAudioAutoInitiationAction extends HdmiCecFeatureAction {
@Override
public void onSendCompleted(int error) {
if (error != SendMessageResult.SUCCESS) {
- tv().setSystemAudioMode(false);
- finish();
+ handleSystemAudioModeStatusTimeout();
}
}
});
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index 4913e8bda6ad..c20079e8a685 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -197,7 +197,7 @@ public class InputManagerService extends IInputManager.Stub
private static native boolean nativeHasKeys(long ptr,
int deviceId, int sourceMask, int[] keyCodes, boolean[] keyExists);
private static native void nativeRegisterInputChannel(long ptr, InputChannel inputChannel,
- InputWindowHandle inputWindowHandle, boolean monitor);
+ InputWindowHandle inputWindowHandle, int displayId);
private static native void nativeUnregisterInputChannel(long ptr, InputChannel inputChannel);
private static native void nativeSetInputFilterEnabled(long ptr, boolean enable);
private static native int nativeInjectInputEvent(long ptr, InputEvent event,
@@ -473,15 +473,21 @@ public class InputManagerService extends IInputManager.Stub
/**
* Creates an input channel that will receive all input from the input dispatcher.
* @param inputChannelName The input channel name.
+ * @param displayId Target display id.
* @return The input channel.
*/
- public InputChannel monitorInput(String inputChannelName) {
+ public InputChannel monitorInput(String inputChannelName, int displayId) {
if (inputChannelName == null) {
throw new IllegalArgumentException("inputChannelName must not be null.");
}
+ if (displayId < Display.DEFAULT_DISPLAY) {
+ throw new IllegalArgumentException("displayId must >= 0.");
+ }
+
InputChannel[] inputChannels = InputChannel.openInputChannelPair(inputChannelName);
- nativeRegisterInputChannel(mPtr, inputChannels[0], null, true);
+ // Register channel for monitor.
+ nativeRegisterInputChannel(mPtr, inputChannels[0], null, displayId);
inputChannels[0].dispose(); // don't need to retain the Java object reference
return inputChannels[1];
}
@@ -498,7 +504,8 @@ public class InputManagerService extends IInputManager.Stub
throw new IllegalArgumentException("inputChannel must not be null.");
}
- nativeRegisterInputChannel(mPtr, inputChannel, inputWindowHandle, false);
+ // Register channel for normal.
+ nativeRegisterInputChannel(mPtr, inputChannel, inputWindowHandle, Display.INVALID_DISPLAY);
}
/**
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 71c419f50790..fc76b46f5dcf 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -15,7 +15,6 @@
package com.android.server.inputmethod;
-import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.INVALID_DISPLAY;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
@@ -1508,11 +1507,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
resetDefaultImeLocked(mContext);
}
updateFromSettingsLocked(true);
- try {
- startInputInnerLocked();
- } catch (RuntimeException e) {
- Slog.w(TAG, "Unexpected exception", e);
- }
}
if (initialUserSwitch) {
@@ -1588,12 +1582,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
InputMethodUtils.setNonSelectedSystemImesDisabledUntilUsed(mIPackageManager,
mSettings.getEnabledInputMethodListLocked(), currentUserId,
mContext.getBasePackageName());
-
- try {
- startInputInnerLocked();
- } catch (RuntimeException e) {
- Slog.w(TAG, "Unexpected exception", e);
- }
}
}
}
@@ -1788,10 +1776,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());
@@ -1910,6 +1894,14 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
return InputBindResult.NO_IME;
}
+ if (!mSystemReady) {
+ // If the system is not yet ready, we shouldn't be running third
+ // party code.
+ return new InputBindResult(
+ InputBindResult.ResultCode.ERROR_SYSTEM_NOT_READY,
+ null, null, mCurMethodId, mCurSeq);
+ }
+
if (!InputMethodUtils.checkIfPackageBelongsToUid(mAppOpsManager, cs.uid,
attribute.packageName)) {
Slog.e(TAG, "Rejecting this client as it reported an invalid package name."
@@ -1917,6 +1909,13 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
return InputBindResult.INVALID_PACKAGE_NAME;
}
+ if (!mWindowManagerInternal.isUidAllowedOnDisplay(cs.selfReportedDisplayId, cs.uid)) {
+ // Wait, the client no longer has access to the display.
+ return InputBindResult.INVALID_DISPLAY_ID;
+ }
+ // Now that the display ID is validated, we trust cs.selfReportedDisplayId for this session.
+ final int displayIdToShowIme = cs.selfReportedDisplayId;
+
if (mCurClient != cs) {
// Was the keyguard locked when switching over to the new client?
mCurClientInKeyguard = isKeyguardLocked();
@@ -1943,8 +1942,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
// Check if the input method is changing.
// We expect the caller has already verified that the client is allowed to access this
// display ID.
- final int displayId = mCurFocusedWindowClient.selfReportedDisplayId;
- if (mCurId != null && mCurId.equals(mCurMethodId) && displayId == mCurTokenDisplayId) {
+ if (mCurId != null && mCurId.equals(mCurMethodId)
+ && displayIdToShowIme == mCurTokenDisplayId) {
if (cs.curSession != null) {
// Fast case: if we are already connected to the input method,
// then just return it.
@@ -1978,23 +1977,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
}
}
- return startInputInnerLocked();
- }
-
- @GuardedBy("mMethodMap")
- InputBindResult startInputInnerLocked() {
- if (mCurMethodId == null) {
- return InputBindResult.NO_IME;
- }
-
- if (!mSystemReady) {
- // If the system is not yet ready, we shouldn't be running third
- // party code.
- return new InputBindResult(
- InputBindResult.ResultCode.ERROR_SYSTEM_NOT_READY,
- null, null, mCurMethodId, mCurSeq);
- }
-
InputMethodInfo info = mMethodMap.get(mCurMethodId);
if (info == null) {
throw new IllegalArgumentException("Unknown id: " + mCurMethodId);
@@ -2008,18 +1990,13 @@ 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;
- }
- final int displayId = mCurFocusedWindowClient.selfReportedDisplayId;
- mCurTokenDisplayId = (displayId != INVALID_DISPLAY) ? displayId : DEFAULT_DISPLAY;
if (bindCurrentInputMethodServiceLocked(mCurIntent, this, IME_CONNECTION_BIND_FLAGS)) {
mLastBindTime = SystemClock.uptimeMillis();
mHaveConnection = true;
mCurId = info.getId();
mCurToken = new Binder();
+ mCurTokenDisplayId = displayIdToShowIme;
try {
if (DEBUG) {
Slog.v(TAG, "Adding window token: " + mCurToken + " for display: "
@@ -2038,10 +2015,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
}
@Override
- public void finishInput(IInputMethodClient client) {
- }
-
- @Override
public void onServiceConnected(ComponentName name, IBinder service) {
synchronized (mMethodMap) {
if (mCurIntent != null && name.equals(mCurIntent.getComponent())) {
diff --git a/services/core/java/com/android/server/location/ContextHubClientBroker.java b/services/core/java/com/android/server/location/ContextHubClientBroker.java
index 9640e042fe6a..99a04d7b144f 100644
--- a/services/core/java/com/android/server/location/ContextHubClientBroker.java
+++ b/services/core/java/com/android/server/location/ContextHubClientBroker.java
@@ -20,6 +20,7 @@ import android.content.Context;
import android.hardware.contexthub.V1_0.ContextHubMsg;
import android.hardware.contexthub.V1_0.IContexthub;
import android.hardware.contexthub.V1_0.Result;
+import android.hardware.location.ContextHubInfo;
import android.hardware.location.ContextHubTransaction;
import android.hardware.location.IContextHubClient;
import android.hardware.location.IContextHubClientCallback;
@@ -57,9 +58,9 @@ public class ContextHubClientBroker extends IContextHubClient.Stub
private final ContextHubClientManager mClientManager;
/*
- * The ID of the hub that this client is attached to.
+ * The object describing the hub that this client is attached to.
*/
- private final int mAttachedContextHubId;
+ private final ContextHubInfo mAttachedContextHubInfo;
/*
* The host end point ID of this client.
@@ -76,13 +77,21 @@ 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) {
+ ContextHubInfo contextHubInfo, short hostEndPointId,
+ IContextHubClientCallback callback) {
mContext = context;
mContextHubProxy = contextHubProxy;
mClientManager = clientManager;
- mAttachedContextHubId = contextHubId;
+ mAttachedContextHubInfo = contextHubInfo;
mHostEndPointId = hostEndPointId;
mCallbackInterface = callback;
}
@@ -112,11 +121,12 @@ public class ContextHubClientBroker extends IContextHubClient.Stub
ContextHubMsg messageToNanoApp = ContextHubServiceUtil.createHidlContextHubMessage(
mHostEndPointId, message);
+ int contextHubId = mAttachedContextHubInfo.getId();
try {
- result = mContextHubProxy.sendMessageToHub(mAttachedContextHubId, messageToNanoApp);
+ result = mContextHubProxy.sendMessageToHub(contextHubId, messageToNanoApp);
} catch (RemoteException e) {
Log.e(TAG, "RemoteException in sendMessageToNanoApp (target hub ID = "
- + mAttachedContextHubId + ")", e);
+ + contextHubId + ")", e);
result = Result.UNKNOWN_FAILURE;
}
} else {
@@ -140,19 +150,16 @@ 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();
}
/**
* @return the ID of the context hub this client is attached to
*/
/* package */ int getAttachedContextHubId() {
- return mAttachedContextHubId;
+ return mAttachedContextHubInfo.getId();
}
/**
@@ -168,14 +175,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 +184,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 +193,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 +210,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/ContextHubClientManager.java b/services/core/java/com/android/server/location/ContextHubClientManager.java
index 4243f02a15b2..eda8c6f8b418 100644
--- a/services/core/java/com/android/server/location/ContextHubClientManager.java
+++ b/services/core/java/com/android/server/location/ContextHubClientManager.java
@@ -19,13 +19,13 @@ package com.android.server.location;
import android.content.Context;
import android.hardware.contexthub.V1_0.ContextHubMsg;
import android.hardware.contexthub.V1_0.IContexthub;
+import android.hardware.location.ContextHubInfo;
import android.hardware.location.IContextHubClient;
import android.hardware.location.IContextHubClientCallback;
import android.hardware.location.NanoAppMessage;
import android.os.RemoteException;
import android.util.Log;
-import java.util.NoSuchElementException;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Consumer;
@@ -80,15 +80,15 @@ import java.util.function.Consumer;
* Registers a new client with the service.
*
* @param clientCallback the callback interface of the client to register
- * @param contextHubId the ID of the hub this client is attached to
+ * @param contextHubInfo the object describing the hub this client is attached to
*
* @return the client interface
*
* @throws IllegalStateException if max number of clients have already registered
*/
/* package */ IContextHubClient registerClient(
- IContextHubClientCallback clientCallback, int contextHubId) {
- ContextHubClientBroker broker = createNewClientBroker(clientCallback, contextHubId);
+ IContextHubClientCallback clientCallback, ContextHubInfo contextHubInfo) {
+ ContextHubClientBroker broker = createNewClientBroker(clientCallback, contextHubInfo);
try {
broker.attachDeathRecipient();
@@ -183,14 +183,14 @@ import java.util.function.Consumer;
* manager.
*
* @param clientCallback the callback interface of the client to register
- * @param contextHubId the ID of the hub this client is attached to
+ * @param contextHubInfo the object describing the hub this client is attached to
*
* @return the ContextHubClientBroker object
*
* @throws IllegalStateException if max number of clients have already registered
*/
private synchronized ContextHubClientBroker createNewClientBroker(
- IContextHubClientCallback clientCallback, int contextHubId) {
+ IContextHubClientCallback clientCallback, ContextHubInfo contextHubInfo) {
if (mHostEndPointIdToClientMap.size() == MAX_CLIENT_ID + 1) {
throw new IllegalStateException("Could not register client - max limit exceeded");
}
@@ -198,10 +198,11 @@ import java.util.function.Consumer;
ContextHubClientBroker broker = null;
int id = mNextHostEndpointId;
for (int i = 0; i <= MAX_CLIENT_ID; i++) {
- if (!mHostEndPointIdToClientMap.containsKey((short)id)) {
+ if (!mHostEndPointIdToClientMap.containsKey((short) id)) {
broker = new ContextHubClientBroker(
- mContext, mContextHubProxy, this, contextHubId, (short)id, clientCallback);
- mHostEndPointIdToClientMap.put((short)id, broker);
+ mContext, mContextHubProxy, this, contextHubInfo, (short) id,
+ clientCallback);
+ mHostEndPointIdToClientMap.put((short) id, broker);
mNextHostEndpointId = (id == MAX_CLIENT_ID) ? 0 : id + 1;
break;
}
diff --git a/services/core/java/com/android/server/location/ContextHubService.java b/services/core/java/com/android/server/location/ContextHubService.java
index 27509deb958f..96e9337a7932 100644
--- a/services/core/java/com/android/server/location/ContextHubService.java
+++ b/services/core/java/com/android/server/location/ContextHubService.java
@@ -170,8 +170,9 @@ public class ContextHubService extends IContextHubService.Stub {
HashMap<Integer, IContextHubClient> defaultClientMap = new HashMap<>();
for (int contextHubId : mContextHubIdToInfoMap.keySet()) {
+ ContextHubInfo contextHubInfo = mContextHubIdToInfoMap.get(contextHubId);
IContextHubClient client = mClientManager.registerClient(
- createDefaultClientCallback(contextHubId), contextHubId);
+ createDefaultClientCallback(contextHubId), contextHubInfo);
defaultClientMap.put(contextHubId, client);
try {
@@ -623,7 +624,8 @@ public class ContextHubService extends IContextHubService.Stub {
throw new NullPointerException("Cannot register client with null callback");
}
- return mClientManager.registerClient(clientCallback, contextHubId);
+ ContextHubInfo contextHubInfo = mContextHubIdToInfoMap.get(contextHubId);
+ return mClientManager.registerClient(clientCallback, contextHubInfo);
}
/**
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/net/NetworkPolicyLogger.java b/services/core/java/com/android/server/net/NetworkPolicyLogger.java
index 452b699667b7..4f4b6bfdb358 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyLogger.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyLogger.java
@@ -72,6 +72,7 @@ public class NetworkPolicyLogger {
static final int NTWK_ALLOWED_TMP_WHITELIST = 4;
static final int NTWK_BLOCKED_BG_RESTRICT = 5;
static final int NTWK_ALLOWED_DEFAULT = 6;
+ static final int NTWK_ALLOWED_SYSTEM = 7;
private final LogBuffer mNetworkBlockedBuffer = new LogBuffer(MAX_NETWORK_BLOCKED_LOG_SIZE);
private final LogBuffer mUidStateChangeBuffer = new LogBuffer(MAX_LOG_SIZE);
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerInternal.java b/services/core/java/com/android/server/net/NetworkPolicyManagerInternal.java
index 61d67b74da18..099671d81a3e 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerInternal.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerInternal.java
@@ -16,6 +16,8 @@
package com.android.server.net;
+import static com.android.server.net.NetworkPolicyManagerService.isUidNetworkingBlockedInternal;
+
import android.net.Network;
import android.net.NetworkTemplate;
import android.telephony.SubscriptionPlan;
@@ -46,6 +48,28 @@ public abstract class NetworkPolicyManagerInternal {
public abstract boolean isUidNetworkingBlocked(int uid, String ifname);
/**
+ * Figure out if networking is blocked for a given set of conditions.
+ *
+ * This is used by ConnectivityService via passing stale copies of conditions, so it must not
+ * take any locks.
+ *
+ * @param uid The target uid.
+ * @param uidRules The uid rules which are obtained from NetworkPolicyManagerService.
+ * @param isNetworkMetered True if the network is metered.
+ * @param isBackgroundRestricted True if data saver is enabled.
+ *
+ * @return true if networking is blocked for the UID under the specified conditions.
+ */
+ public static boolean isUidNetworkingBlocked(int uid, int uidRules, boolean isNetworkMetered,
+ boolean isBackgroundRestricted) {
+ // Log of invoking internal function is disabled because it will be called very
+ // frequently. And metrics are unlikely needed on this method because the callers are
+ // external and this method doesn't take any locks or perform expensive operations.
+ return isUidNetworkingBlockedInternal(uid, uidRules, isNetworkMetered,
+ isBackgroundRestricted, null);
+ }
+
+ /**
* Informs that an appId has been added or removed from the temp-powersave-whitelist so that
* that network rules for that appId can be updated.
*
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 48e09d744ff4..d7996422870c 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -99,6 +99,7 @@ import static com.android.internal.util.XmlUtils.writeStringAttribute;
import static com.android.server.NetworkManagementService.LIMIT_GLOBAL_ALERT;
import static com.android.server.net.NetworkPolicyLogger.NTWK_ALLOWED_DEFAULT;
import static com.android.server.net.NetworkPolicyLogger.NTWK_ALLOWED_NON_METERED;
+import static com.android.server.net.NetworkPolicyLogger.NTWK_ALLOWED_SYSTEM;
import static com.android.server.net.NetworkPolicyLogger.NTWK_ALLOWED_TMP_WHITELIST;
import static com.android.server.net.NetworkPolicyLogger.NTWK_ALLOWED_WHITELIST;
import static com.android.server.net.NetworkPolicyLogger.NTWK_BLOCKED_BG_RESTRICT;
@@ -4837,46 +4838,75 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
final long startTime = mStatLogger.getTime();
mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
- final boolean ret = isUidNetworkingBlockedInternal(uid, isNetworkMetered);
+ final int uidRules;
+ final boolean isBackgroundRestricted;
+ synchronized (mUidRulesFirstLock) {
+ uidRules = mUidRules.get(uid, RULE_NONE);
+ isBackgroundRestricted = mRestrictBackground;
+ }
+ final boolean ret = isUidNetworkingBlockedInternal(uid, uidRules, isNetworkMetered,
+ isBackgroundRestricted, mLogger);
mStatLogger.logDurationStat(Stats.IS_UID_NETWORKING_BLOCKED, startTime);
return ret;
}
- private boolean isUidNetworkingBlockedInternal(int uid, boolean isNetworkMetered) {
- final int uidRules;
- final boolean isBackgroundRestricted;
- synchronized (mUidRulesFirstLock) {
- uidRules = mUidRules.get(uid, RULE_NONE);
- isBackgroundRestricted = mRestrictBackground;
+ private static boolean isSystem(int uid) {
+ return uid < Process.FIRST_APPLICATION_UID;
+ }
+
+ static boolean isUidNetworkingBlockedInternal(int uid, int uidRules, boolean isNetworkMetered,
+ boolean isBackgroundRestricted, @Nullable NetworkPolicyLogger logger) {
+ final int reason;
+ // Networks are never blocked for system components
+ if (isSystem(uid)) {
+ reason = NTWK_ALLOWED_SYSTEM;
}
- if (hasRule(uidRules, RULE_REJECT_ALL)) {
- mLogger.networkBlocked(uid, NTWK_BLOCKED_POWER);
- return true;
+ else if (hasRule(uidRules, RULE_REJECT_ALL)) {
+ reason = NTWK_BLOCKED_POWER;
}
- if (!isNetworkMetered) {
- mLogger.networkBlocked(uid, NTWK_ALLOWED_NON_METERED);
- return false;
+ else if (!isNetworkMetered) {
+ reason = NTWK_ALLOWED_NON_METERED;
}
- if (hasRule(uidRules, RULE_REJECT_METERED)) {
- mLogger.networkBlocked(uid, NTWK_BLOCKED_BLACKLIST);
- return true;
+ else if (hasRule(uidRules, RULE_REJECT_METERED)) {
+ reason = NTWK_BLOCKED_BLACKLIST;
}
- if (hasRule(uidRules, RULE_ALLOW_METERED)) {
- mLogger.networkBlocked(uid, NTWK_ALLOWED_WHITELIST);
- return false;
+ else if (hasRule(uidRules, RULE_ALLOW_METERED)) {
+ reason = NTWK_ALLOWED_WHITELIST;
}
- if (hasRule(uidRules, RULE_TEMPORARY_ALLOW_METERED)) {
- mLogger.networkBlocked(uid, NTWK_ALLOWED_TMP_WHITELIST);
- return false;
+ else if (hasRule(uidRules, RULE_TEMPORARY_ALLOW_METERED)) {
+ reason = NTWK_ALLOWED_TMP_WHITELIST;
}
- if (isBackgroundRestricted) {
- mLogger.networkBlocked(uid, NTWK_BLOCKED_BG_RESTRICT);
- return true;
+ else if (isBackgroundRestricted) {
+ reason = NTWK_BLOCKED_BG_RESTRICT;
}
- mLogger.networkBlocked(uid, NTWK_ALLOWED_DEFAULT);
- return false;
+ else {
+ reason = NTWK_ALLOWED_DEFAULT;
+ }
+
+ final boolean blocked;
+ switch(reason) {
+ case NTWK_ALLOWED_DEFAULT:
+ case NTWK_ALLOWED_NON_METERED:
+ case NTWK_ALLOWED_TMP_WHITELIST:
+ case NTWK_ALLOWED_WHITELIST:
+ case NTWK_ALLOWED_SYSTEM:
+ blocked = false;
+ break;
+ case NTWK_BLOCKED_POWER:
+ case NTWK_BLOCKED_BLACKLIST:
+ case NTWK_BLOCKED_BG_RESTRICT:
+ blocked = true;
+ break;
+ default:
+ throw new IllegalArgumentException();
+ }
+ if (logger != null) {
+ logger.networkBlocked(uid, reason);
+ }
+
+ return blocked;
}
private class NetworkPolicyManagerInternalImpl extends NetworkPolicyManagerInternal {
@@ -4918,11 +4948,18 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
public boolean isUidNetworkingBlocked(int uid, String ifname) {
final long startTime = mStatLogger.getTime();
+ final int uidRules;
+ final boolean isBackgroundRestricted;
+ synchronized (mUidRulesFirstLock) {
+ uidRules = mUidRules.get(uid, RULE_NONE);
+ isBackgroundRestricted = mRestrictBackground;
+ }
final boolean isNetworkMetered;
synchronized (mNetworkPoliciesSecondLock) {
isNetworkMetered = mMeteredIfaces.contains(ifname);
}
- final boolean ret = isUidNetworkingBlockedInternal(uid, isNetworkMetered);
+ final boolean ret = isUidNetworkingBlockedInternal(uid, uidRules, isNetworkMetered,
+ isBackgroundRestricted, mLogger);
mStatLogger.logDurationStat(Stats.IS_UID_NETWORKING_BLOCKED, startTime);
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/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index 93230401eb20..404f152bb8d1 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
@@ -586,15 +659,6 @@ public class LauncherAppsService extends SystemService {
try {
final PackageManagerInternal pmInt =
LocalServices.getService(PackageManagerInternal.class);
- ActivityInfo info = pmInt.getActivityInfo(component,
- PackageManager.MATCH_DIRECT_BOOT_AWARE
- | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
- callingUid, user.getIdentifier());
- if (!info.exported) {
- throw new SecurityException("Cannot launch non-exported components "
- + component);
- }
-
// Check that the component actually has Intent.CATEGORY_LAUCNCHER
// as calling startActivityAsUser ignores the category and just
// resolves based on the component if present.
@@ -607,6 +671,11 @@ public class LauncherAppsService extends SystemService {
ActivityInfo activityInfo = apps.get(i).activityInfo;
if (activityInfo.packageName.equals(component.getPackageName()) &&
activityInfo.name.equals(component.getClassName())) {
+ if (!activityInfo.exported) {
+ throw new SecurityException("Cannot launch non-exported components "
+ + component);
+ }
+
// Found an activity with category launcher that matches
// this component so ok to launch.
launchIntent.setPackage(null);
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 2b76111449f4..552715142ac7 100755
--- 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;
@@ -2946,7 +2948,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;
@@ -2968,11 +2970,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;
}
@@ -7924,10 +7926,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;
@@ -7992,7 +8000,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
- return new ParceledListSlice<>(list);
+ return list;
}
}
@@ -12212,7 +12220,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);
@@ -12232,7 +12242,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);
@@ -12767,8 +12779,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");
@@ -12813,7 +12825,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));
@@ -17909,7 +17921,7 @@ public class PackageManagerService extends IPackageManager.Stub
false /*hidden*/,
false /*suspended*/,
null /*suspendingPackage*/,
- null /*dialogMessage*/,
+ null /*dialogInfo*/,
null /*suspendedAppExtras*/,
null /*suspendedLauncherExtras*/,
false /*instantApp*/,
@@ -19492,6 +19504,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
@@ -22387,6 +22409,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) {
@@ -22660,10 +22690,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/UserRestrictionsUtils.java b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
index 13155027a387..dd04652a29b3 100644
--- a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
+++ b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
@@ -127,7 +127,8 @@ public class UserRestrictionsUtils {
UserManager.DISALLOW_SHARE_INTO_MANAGED_PROFILE,
UserManager.DISALLOW_AMBIENT_DISPLAY,
UserManager.DISALLOW_CONFIG_SCREEN_TIMEOUT,
- UserManager.DISALLOW_PRINTING
+ UserManager.DISALLOW_PRINTING,
+ UserManager.DISALLOW_CONFIG_PRIVATE_DNS
});
/**
@@ -163,7 +164,8 @@ public class UserRestrictionsUtils {
* User restrictions that cannot be set by profile owners. Applied to all users.
*/
private static final Set<String> DEVICE_OWNER_ONLY_RESTRICTIONS = Sets.newArraySet(
- UserManager.DISALLOW_USER_SWITCH
+ UserManager.DISALLOW_USER_SWITCH,
+ UserManager.DISALLOW_CONFIG_PRIVATE_DNS
);
/**
@@ -741,6 +743,10 @@ public class UserRestrictionsUtils {
restriction = UserManager.DISALLOW_CONFIG_SCREEN_TIMEOUT;
break;
+ case android.provider.Settings.Global.PRIVATE_DNS_MODE:
+ case android.provider.Settings.Global.PRIVATE_DNS_SPECIFIER:
+ restriction = UserManager.DISALLOW_CONFIG_PRIVATE_DNS;
+ break;
default:
if (setting.startsWith(Settings.Global.DATA_ROAMING)) {
if ("0".equals(value)) {
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..e6a018a9f39d 100644
--- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
@@ -31,9 +31,11 @@ import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.PackageManagerInternal;
import android.content.pm.PackageManagerInternal.PackagesProvider;
import android.content.pm.PackageManagerInternal.SyncAdapterPackagesProvider;
+import android.content.pm.PermissionInfo;
import android.content.pm.ProviderInfo;
import android.content.pm.ResolveInfo;
import android.media.RingtoneManager;
@@ -1033,8 +1035,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());
}
}
@@ -1182,12 +1184,16 @@ public final class DefaultPermissionGrantPolicy {
final int permissionGrantCount = permissionGrants.size();
for (int j = 0; j < permissionGrantCount; j++) {
DefaultPermissionGrant permissionGrant = permissionGrants.get(j);
+ if (!isPermissionDangerous(permissionGrant.name)) {
+ Log.w(TAG, "Ignoring permission " + permissionGrant.name
+ + " which isn't dangerous");
+ continue;
+ }
if (permissions == null) {
permissions = new ArraySet<>();
} else {
permissions.clear();
}
- permissions.add(permissionGrant.name);
grantRuntimePermissions(pkg, permissions, permissionGrant.fixed, userId);
}
}
@@ -1350,6 +1356,16 @@ public final class DefaultPermissionGrantPolicy {
&& pkg.applicationInfo.targetSdkVersion > Build.VERSION_CODES.LOLLIPOP_MR1;
}
+ private boolean isPermissionDangerous(String name) {
+ try {
+ final PermissionInfo pi = mContext.getPackageManager().getPermissionInfo(name, 0);
+ return (pi.getProtectionFlags() & PermissionInfo.PROTECTION_DANGEROUS) != 0;
+ } catch (NameNotFoundException e) {
+ // When unknown assume it's dangerous to be on the safe side
+ return true;
+ }
+ }
+
private static final class DefaultPermissionGrant {
final String name;
final boolean fixed;
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 1589246a932c..326233898561 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -2160,7 +2160,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
});
mImmersiveModeConfirmation = new ImmersiveModeConfirmation(mContext);
- mWindowManagerFuncs.registerPointerEventListener(mSystemGestures);
+ //TODO (b/111365687) : make system context per display.
+ mWindowManagerFuncs.registerPointerEventListener(mSystemGestures, DEFAULT_DISPLAY);
mVibrator = (Vibrator)context.getSystemService(Context.VIBRATOR_SERVICE);
@@ -2362,13 +2363,16 @@ public class PhoneWindowManager implements WindowManagerPolicy {
WindowManager wm = (WindowManager) mContext.getSystemService(WINDOW_SERVICE);
lp.inputFeatures |= WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL;
wm.addView(mPointerLocationView, lp);
- mWindowManagerFuncs.registerPointerEventListener(mPointerLocationView);
+ //TODO (b/111365687) : make system context per display.
+ mWindowManagerFuncs.registerPointerEventListener(mPointerLocationView, DEFAULT_DISPLAY);
}
}
private void disablePointerLocation() {
if (mPointerLocationView != null) {
- mWindowManagerFuncs.unregisterPointerEventListener(mPointerLocationView);
+ //TODO (b/111365687) : make system context per display.
+ mWindowManagerFuncs.unregisterPointerEventListener(mPointerLocationView,
+ DEFAULT_DISPLAY);
WindowManager wm = (WindowManager) mContext.getSystemService(WINDOW_SERVICE);
wm.removeView(mPointerLocationView);
mPointerLocationView = null;
@@ -6150,6 +6154,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/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
index 27ab3efb3fb1..2a8e523f04c2 100644
--- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java
+++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
@@ -559,10 +559,10 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants {
public Object getWindowManagerLock();
/** Register a system listener for touch events */
- void registerPointerEventListener(PointerEventListener listener);
+ void registerPointerEventListener(PointerEventListener listener, int displayId);
/** Unregister a system listener for touch events */
- void unregisterPointerEventListener(PointerEventListener listener);
+ void unregisterPointerEventListener(PointerEventListener listener, int displayId);
/**
* @return The content insets of the docked divider window.
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..6db7e4f1a800 100644
--- a/services/core/java/com/android/server/stats/StatsCompanionService.java
+++ b/services/core/java/com/android/server/stats/StatsCompanionService.java
@@ -43,12 +43,15 @@ import android.os.Binder;
import android.os.Bundle;
import android.os.Environment;
import android.os.FileUtils;
+import android.os.Handler;
+import android.os.HandlerThread;
import android.os.IBinder;
import android.os.IStatsCompanionService;
import android.os.IStatsManager;
import android.os.IStoraged;
import android.os.IThermalEventListener;
import android.os.IThermalService;
+import android.os.Looper;
import android.os.ParcelFileDescriptor;
import android.os.Parcelable;
import android.os.Process;
@@ -85,6 +88,7 @@ import com.android.internal.os.KernelWakelockReader;
import com.android.internal.os.KernelWakelockStats;
import com.android.internal.os.LooperStats;
import com.android.internal.os.PowerProfile;
+import com.android.internal.os.ProcessCpuTracker;
import com.android.internal.os.StoragedUidIoStatsReader;
import com.android.internal.util.DumpUtils;
import com.android.server.BinderCallsStatsService;
@@ -148,6 +152,13 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
public static final String EXTRA_LAST_REPORT_TIME = "android.app.extra.LAST_REPORT_TIME";
public static final int DEATH_THRESHOLD = 10;
+
+ static final class CompanionHandler extends Handler {
+ CompanionHandler(Looper looper) {
+ super(looper);
+ }
+ }
+
private final Context mContext;
private final AlarmManager mAlarmManager;
@GuardedBy("sStatsdLock")
@@ -164,15 +175,11 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
private final KernelWakelockStats mTmpWakelockStats = new KernelWakelockStats();
private IWifiManager mWifiManager = null;
private TelephonyManager mTelephony = null;
- private final StatFs mStatFsData = new StatFs(Environment.getDataDirectory().getAbsolutePath());
- private final StatFs mStatFsSystem =
- new StatFs(Environment.getRootDirectory().getAbsolutePath());
- private final StatFs mStatFsTemp =
- new StatFs(Environment.getDownloadCacheDirectory().getAbsolutePath());
@GuardedBy("sStatsdLock")
private final HashSet<Long> mDeathTimeMillis = new HashSet<>();
@GuardedBy("sStatsdLock")
private final HashMap<Long, String> mDeletedFiles = new HashMap<>();
+ private final CompanionHandler mHandler;
private KernelUidCpuTimeReader mKernelUidCpuTimeReader = new KernelUidCpuTimeReader();
private KernelCpuSpeedReader[] mKernelCpuSpeedReaders;
@@ -188,6 +195,8 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
private static IThermalService sThermalService;
private File mBaseDir =
new File(SystemServiceManager.ensureSystemDir(), "stats_companion");
+ @GuardedBy("this")
+ ProcessCpuTracker mProcessCpuTracker = null;
public StatsCompanionService(Context context) {
super();
@@ -251,6 +260,11 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
} else {
Slog.e(TAG, "cannot find thermalservice, no throttling push notifications");
}
+
+ HandlerThread handlerThread = new HandlerThread(TAG);
+ handlerThread.start();
+ mHandler = new CompanionHandler(handlerThread.getLooper());
+
}
@Override
@@ -498,7 +512,7 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
// only fire when it awakens.
// AlarmManager will automatically cancel any previous mAnomalyAlarmListener alarm.
mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME, timestampMs, TAG + ".anomaly",
- mAnomalyAlarmListener, null);
+ mAnomalyAlarmListener, mHandler);
} finally {
Binder.restoreCallingIdentity(callingToken);
}
@@ -529,7 +543,7 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
// using ELAPSED_REALTIME, not ELAPSED_REALTIME_WAKEUP, so if device is asleep, will
// only fire when it awakens.
mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME, timestampMs, TAG + ".periodic",
- mPeriodicAlarmListener, null);
+ mPeriodicAlarmListener, mHandler);
} finally {
Binder.restoreCallingIdentity(callingToken);
}
@@ -561,7 +575,7 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
// using ELAPSED_REALTIME, not ELAPSED_REALTIME_WAKEUP, so if device is asleep, will
// only fire when it awakens.
mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME, nextPullTimeMs, TAG + ".pull",
- mPullingAlarmListener, null);
+ mPullingAlarmListener, mHandler);
} finally {
Binder.restoreCallingIdentity(callingToken);
}
@@ -756,7 +770,7 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
private void pullBluetoothBytesTransfer(
int tagId, long elapsedNanos, long wallClockNanos,
List<StatsLogEventWrapper> pulledData) {
- BluetoothActivityEnergyInfo info = pullBluetoothData();
+ BluetoothActivityEnergyInfo info = fetchBluetoothData();
if (info.getUidTraffic() != null) {
for (UidTraffic traffic : info.getUidTraffic()) {
StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos,
@@ -868,9 +882,12 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
int tagId, long elapsedNanos, long wallClockNanos,
List<StatsLogEventWrapper> pulledData) {
long token = Binder.clearCallingIdentity();
- if (mWifiManager == null) {
- mWifiManager =
- IWifiManager.Stub.asInterface(ServiceManager.getService(Context.WIFI_SERVICE));
+ synchronized (this) {
+ if (mWifiManager == null) {
+ mWifiManager =
+ IWifiManager.Stub.asInterface(
+ ServiceManager.getService(Context.WIFI_SERVICE));
+ }
}
if (mWifiManager != null) {
try {
@@ -900,8 +917,10 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
int tagId, long elapsedNanos, long wallClockNanos,
List<StatsLogEventWrapper> pulledData) {
long token = Binder.clearCallingIdentity();
- if (mTelephony == null) {
- mTelephony = TelephonyManager.from(mContext);
+ synchronized (this) {
+ if (mTelephony == null) {
+ mTelephony = TelephonyManager.from(mContext);
+ }
}
if (mTelephony != null) {
SynchronousResultReceiver modemReceiver = new SynchronousResultReceiver("telephony");
@@ -925,7 +944,7 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
private void pullBluetoothActivityInfo(
int tagId, long elapsedNanos, long wallClockNanos,
List<StatsLogEventWrapper> pulledData) {
- BluetoothActivityEnergyInfo info = pullBluetoothData();
+ BluetoothActivityEnergyInfo info = fetchBluetoothData();
StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos);
e.writeLong(info.getTimeStamp());
e.writeInt(info.getBluetoothStackState());
@@ -936,7 +955,7 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
pulledData.add(e);
}
- private synchronized BluetoothActivityEnergyInfo pullBluetoothData() {
+ private synchronized BluetoothActivityEnergyInfo fetchBluetoothData() {
final BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
if (adapter != null) {
SynchronousResultReceiver bluetoothReceiver = new SynchronousResultReceiver(
@@ -985,6 +1004,23 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
}
}
+ private void pullNativeProcessMemoryState(
+ int tagId, long elapsedNanos, long wallClockNanos,
+ List<StatsLogEventWrapper> pulledData) {
+ List<ProcessMemoryState> processMemoryStates = LocalServices.getService(
+ ActivityManagerInternal.class).getMemoryStateForNativeProcesses();
+ for (ProcessMemoryState processMemoryState : processMemoryStates) {
+ StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos);
+ e.writeInt(processMemoryState.uid);
+ e.writeString(processMemoryState.processName);
+ e.writeLong(processMemoryState.pgfault);
+ e.writeLong(processMemoryState.pgmajfault);
+ e.writeLong(processMemoryState.rssInBytes);
+ e.writeLong(processMemoryState.rssHighWatermarkInBytes);
+ pulledData.add(e);
+ }
+ }
+
private void pullBinderCallsStats(
int tagId, long elapsedNanos, long wallClockNanos,
List<StatsLogEventWrapper> pulledData) {
@@ -1056,6 +1092,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);
}
}
@@ -1285,30 +1326,35 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
private void pullProcessStats(int section, int tagId, long elapsedNanos, long wallClockNanos,
List<StatsLogEventWrapper> pulledData) {
- try {
- long lastHighWaterMark = readProcStatsHighWaterMark(section);
- List<ParcelFileDescriptor> statsFiles = new ArrayList<>();
- long highWaterMark = mProcessStats.getCommittedStats(
- lastHighWaterMark, section, true, statsFiles);
- if (statsFiles.size() != 1) {
- return;
+ synchronized (this) {
+ try {
+ long lastHighWaterMark = readProcStatsHighWaterMark(section);
+ List<ParcelFileDescriptor> statsFiles = new ArrayList<>();
+ long highWaterMark = mProcessStats.getCommittedStats(
+ lastHighWaterMark, section, true, statsFiles);
+ if (statsFiles.size() != 1) {
+ return;
+ }
+ InputStream stream = new ParcelFileDescriptor.AutoCloseInputStream(
+ statsFiles.get(0));
+ int[] len = new int[1];
+ byte[] stats = readFully(stream, len);
+ StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos,
+ wallClockNanos);
+ e.writeStorage(Arrays.copyOf(stats, len[0]));
+ pulledData.add(e);
+ new File(mBaseDir.getAbsolutePath() + "/" + section + "_"
+ + lastHighWaterMark).delete();
+ new File(
+ mBaseDir.getAbsolutePath() + "/" + section + "_"
+ + highWaterMark).createNewFile();
+ } catch (IOException e) {
+ Log.e(TAG, "Getting procstats failed: ", e);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Getting procstats failed: ", e);
+ } catch (SecurityException e) {
+ Log.e(TAG, "Getting procstats failed: ", e);
}
- InputStream stream = new ParcelFileDescriptor.AutoCloseInputStream(statsFiles.get(0));
- int[] len = new int[1];
- byte[] stats = readFully(stream, len);
- StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos);
- e.writeStorage(Arrays.copyOf(stats, len[0]));
- pulledData.add(e);
- new File(mBaseDir.getAbsolutePath() + "/" + section + "_" + lastHighWaterMark).delete();
- new File(
- mBaseDir.getAbsolutePath() + "/" + section + "_"
- + highWaterMark).createNewFile();
- } catch (IOException e) {
- Log.e(TAG, "Getting procstats failed: ", e);
- } catch (RemoteException e) {
- Log.e(TAG, "Getting procstats failed: ", e);
- } catch (SecurityException e) {
- Log.e(TAG, "Getting procstats failed: ", e);
}
}
@@ -1377,12 +1423,34 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
});
}
+ private void pullProcessCpuTime(int tagId, long elapsedNanos, final long wallClockNanos,
+ List<StatsLogEventWrapper> pulledData) {
+ synchronized (this) {
+ if (mProcessCpuTracker == null) {
+ mProcessCpuTracker = new ProcessCpuTracker(false);
+ mProcessCpuTracker.init();
+ }
+ mProcessCpuTracker.update();
+ for (int i = 0; i < mProcessCpuTracker.countStats(); i++) {
+ ProcessCpuTracker.Stats st = mProcessCpuTracker.getStats(i);
+ StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos,
+ wallClockNanos);
+ e.writeInt(st.uid);
+ e.writeString(st.name);
+ e.writeLong(st.base_utime);
+ e.writeLong(st.base_stime);
+ pulledData.add(e);
+ }
+ }
+ }
+
/**
* Pulls various data.
*/
@Override // Binder call
public StatsLogEventWrapper[] pullData(int tagId) {
enforceCallingPermission();
+
if (DEBUG) {
Slog.d(TAG, "Pulling " + tagId);
}
@@ -1458,6 +1526,10 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
pullProcessMemoryState(tagId, elapsedNanos, wallClockNanos, ret);
break;
}
+ case StatsLog.NATIVE_PROCESS_MEMORY_STATE: {
+ pullNativeProcessMemoryState(tagId, elapsedNanos, wallClockNanos, ret);
+ break;
+ }
case StatsLog.BINDER_CALLS: {
pullBinderCallsStats(tagId, elapsedNanos, wallClockNanos, ret);
break;
@@ -1491,7 +1563,8 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
break;
}
case StatsLog.PROC_STATS: {
- pullProcessStats(ProcessStats.REPORT_ALL, tagId, elapsedNanos, wallClockNanos, ret);
+ pullProcessStats(ProcessStats.REPORT_ALL, tagId, elapsedNanos, wallClockNanos,
+ ret);
break;
}
case StatsLog.PROC_STATS_PKG_PROC: {
@@ -1507,6 +1580,10 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
pullPowerProfile(tagId, elapsedNanos, wallClockNanos, ret);
break;
}
+ case StatsLog.PROCESS_CPU_TIME: {
+ pullProcessCpuTime(tagId, elapsedNanos, wallClockNanos, ret);
+ break;
+ }
default:
Slog.w(TAG, "No such tagId data as " + tagId);
return null;
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/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
index e5347cfee5a2..7f9ee8405dfc 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
@@ -18,6 +18,7 @@ package com.android.server.wm;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.UserIdInt;
import android.app.AppProtoEnums;
import android.app.IActivityManager;
import android.app.IApplicationThread;
@@ -28,19 +29,26 @@ import android.content.pm.ApplicationInfo;
import android.content.res.CompatibilityInfo;
import android.os.Bundle;
import android.os.IBinder;
+import android.os.RemoteException;
import android.os.SystemClock;
import android.service.voice.IVoiceInteractionSession;
import android.util.SparseIntArray;
+import android.util.proto.ProtoOutputStream;
import com.android.internal.app.IVoiceInteractor;
import com.android.server.am.ActivityServiceConnectionsHolder;
import com.android.server.am.PendingIntentRecord;
import com.android.server.am.SafeActivityOptions;
import com.android.server.am.TaskRecord;
+import com.android.server.am.UserState;
import com.android.server.am.WindowProcessController;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
import java.lang.ref.WeakReference;
import java.util.List;
+import java.util.Set;
+import java.util.function.Predicate;
/**
* Activity Task manager local system service interface.
@@ -306,13 +314,13 @@ public abstract class ActivityTaskManagerInternal {
public abstract boolean showStrictModeViolationDialog();
public abstract void showSystemReadyErrorDialogsIfNeeded();
- public abstract long inputDispatchingTimedOut(int pid, boolean aboveSystem, String reason);
public abstract void onProcessMapped(int pid, WindowProcessController proc);
public abstract void onProcessUnMapped(int pid);
public abstract void onPackageDataCleared(String name);
public abstract void onPackageUninstalled(String name);
public abstract void onPackageAdded(String name, boolean replacing);
+ public abstract void onPackageReplaced(ApplicationInfo aInfo);
public abstract CompatibilityInfo compatibilityInfoForPackage(ApplicationInfo ai);
@@ -343,4 +351,92 @@ public abstract class ActivityTaskManagerInternal {
/** @return true if the given process is the factory test process. */
public abstract boolean isFactoryTestProcess(WindowProcessController wpc);
public abstract void updateTopComponentForFactoryTest();
+ public abstract void handleAppDied(WindowProcessController wpc, boolean restarting,
+ Runnable finishInstrumentationCallback);
+ public abstract void closeSystemDialogs(String reason);
+
+ /** Removes all components (e.g. activities, recents, ...) belonging to a disabled package. */
+ public abstract void cleanupDisabledPackageComponents(
+ String packageName, Set<String> disabledClasses, int userId, boolean booted);
+
+ /** Called whenever AM force stops a package. */
+ public abstract boolean onForceStopPackage(String packageName, boolean doit,
+ boolean evenPersistent, int userId);
+ /**
+ * Resumes all top activities in the system if they aren't resumed already.
+ * @param scheduleIdle If the idle message should be schedule after the top activities are
+ * resumed.
+ */
+ public abstract void resumeTopActivities(boolean scheduleIdle);
+
+ /** Called by AM just before it binds to an application process. */
+ public abstract void preBindApplication(WindowProcessController wpc);
+
+ /** Called by AM when an application process attaches. */
+ public abstract boolean attachApplication(WindowProcessController wpc) throws RemoteException;
+
+ /** @see IActivityManager#notifyLockedProfile(int) */
+ public abstract void notifyLockedProfile(@UserIdInt int userId, int currentUserId);
+
+ /** @see IActivityManager#startConfirmDeviceCredentialIntent(Intent, Bundle) */
+ public abstract void startConfirmDeviceCredentialIntent(Intent intent, Bundle options);
+
+ /** Writes current activity states to the proto stream. */
+ public abstract void writeActivitiesToProto(ProtoOutputStream proto);
+
+ /**
+ * Saves the current activity manager state and includes the saved state in the next dump of
+ * activity manager.
+ */
+ public abstract void saveANRState(String reason);
+
+ /** Clears the previously saved activity manager ANR state. */
+ public abstract void clearSavedANRState();
+
+ /** Dump the current state based on the command. */
+ public abstract void dump(String cmd, FileDescriptor fd, PrintWriter pw, String[] args,
+ int opti, boolean dumpAll, boolean dumpClient, String dumpPackage);
+
+ /** Dump the current state for inclusion in process dump. */
+ public abstract boolean dumpForProcesses(FileDescriptor fd, PrintWriter pw, boolean dumpAll,
+ String dumpPackage, int dumpAppId, boolean needSep, boolean testPssMode,
+ int wakefulness);
+
+ /** Writes the current window process states to the proto stream. */
+ public abstract void writeProcessesToProto(ProtoOutputStream proto, String dumpPackage);
+
+ /** Dump the current activities state. */
+ public abstract boolean dumpActivity(FileDescriptor fd, PrintWriter pw, String name,
+ String[] args, int opti, boolean dumpAll, boolean dumpVisibleStacksOnly,
+ boolean dumpFocusedStackOnly);
+
+ /** @return true if it the activity management system is okay with GC running now. */
+ public abstract boolean canGcNow();
+
+ /** @return the process for the top-most resumed activity in the system. */
+ public abstract WindowProcessController getTopApp();
+
+ /** Generate oom-score-adjustment rank for all tasks in the system based on z-order. */
+ public abstract void rankTaskLayersIfNeeded();
+
+ /** Destroy all activities. */
+ public abstract void scheduleDestroyAllActivities(String reason);
+
+ /** Remove user association with activities. */
+ public abstract void removeUser(int userId);
+
+ /** Switch current focused user for activities. */
+ public abstract boolean switchUser(int userId, UserState userState);
+
+ /** Called whenever an app crashes. */
+ public abstract void onHandleAppCrash(WindowProcessController wpc);
+
+ /**
+ * Finish the topmost activities in all stacks that belong to the crashed app.
+ * @param crashedApp The app that crashed.
+ * @param reason Reason to perform this action.
+ * @return The task id that was finished in this stack, or INVALID_TASK_ID if none was finished.
+ */
+ public abstract int finishTopCrashedActivities(
+ WindowProcessController crashedApp, String reason);
}
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 33f8d6e7412a..e4f6e6f5d6da 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;
@@ -147,12 +145,14 @@ import android.view.Display;
import android.view.DisplayCutout;
import android.view.DisplayInfo;
import android.view.Gravity;
+import android.view.InputChannel;
import android.view.InputDevice;
import android.view.MagnificationSpec;
import android.view.Surface;
import android.view.SurfaceControl;
import android.view.SurfaceControl.Transaction;
import android.view.SurfaceSession;
+import android.view.WindowManagerPolicyConstants.PointerEventListener;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ToBooleanFunction;
@@ -456,6 +456,8 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
*/
WindowState mInputMethodWindow;
+ private final PointerEventDispatcher mPointerEventDispatcher;
+
private final Consumer<WindowState> mUpdateWindowsForAnimator = w -> {
WindowStateAnimator winAnimator = w.mWinAnimator;
final AppWindowToken atoken = w.mAppToken;
@@ -835,6 +837,15 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
mDisplayReady = true;
mInputMonitor = new InputMonitor(service, mDisplayId);
+
+ if (mService.mInputManager != null) {
+ final InputChannel inputChannel = mService.mInputManager.monitorInput("Display "
+ + mDisplayId, mDisplayId);
+ mPointerEventDispatcher = inputChannel != null
+ ? new PointerEventDispatcher(inputChannel) : null;
+ } else {
+ mPointerEventDispatcher = null;
+ }
}
boolean isReady() {
@@ -1288,6 +1299,19 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
mDisplayFrames.onDisplayInfoUpdated(mDisplayInfo,
calculateDisplayCutoutForRotation(mDisplayInfo.rotation));
+
+ // Tap Listeners are supported for:
+ // 1. All physical displays (multi-display).
+ // 2. VirtualDisplays on VR, AA (and everything else).
+ if (mPointerEventDispatcher != null && mTapDetector == null) {
+ if (DEBUG_DISPLAY) {
+ Slog.d(TAG,
+ "Registering PointerEventListener for DisplayId: " + mDisplayId);
+ }
+ mTapDetector = new TaskTapPointerEventListener(mService, this);
+ registerPointerEventListener(mTapDetector);
+ registerPointerEventListener(mService.mMousePositionTracker);
+ }
}
/**
@@ -2065,9 +2089,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() && !stack.inMultiWindowMode()) {
+ // We skip not only home stack, but also everything behind home because user can't
+ // see them when home stack is isn't in multi-window mode.
+ break;
+ }
final int taskId = stack.taskIdFromPoint(x, y);
if (taskId != -1) {
return taskId;
@@ -2172,13 +2212,10 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
try {
super.removeImmediately();
if (DEBUG_DISPLAY) Slog.v(TAG_WM, "Removing display=" + this);
- if (mService.canDispatchPointerEvents()) {
- if (mTapDetector != null) {
- mService.unregisterPointerEventListener(mTapDetector);
- }
- if (mDisplayId == DEFAULT_DISPLAY && mService.mMousePositionTracker != null) {
- mService.unregisterPointerEventListener(mService.mMousePositionTracker);
- }
+ if (mPointerEventDispatcher != null && mTapDetector != null) {
+ unregisterPointerEventListener(mTapDetector);
+ unregisterPointerEventListener(mService.mMousePositionTracker);
+ mTapDetector = null;
}
mService.mAnimator.removeDisplayLocked(mDisplayId);
mWindowingLayer.release();
@@ -4400,4 +4437,16 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
boolean getLastHasContent() {
return mLastHasContent;
}
+
+ void registerPointerEventListener(@NonNull PointerEventListener listener) {
+ if (mPointerEventDispatcher != null) {
+ mPointerEventDispatcher.registerInputEventListener(listener);
+ }
+ }
+
+ void unregisterPointerEventListener(@NonNull PointerEventListener listener) {
+ if (mPointerEventDispatcher != null) {
+ mPointerEventDispatcher.unregisterInputEventListener(listener);
+ }
+ }
}
diff --git a/services/core/java/com/android/server/wm/InputManagerCallback.java b/services/core/java/com/android/server/wm/InputManagerCallback.java
index b5e2f01d8fbb..10d77e59b0b3 100644
--- a/services/core/java/com/android/server/wm/InputManagerCallback.java
+++ b/services/core/java/com/android/server/wm/InputManagerCallback.java
@@ -108,7 +108,7 @@ final class InputManagerCallback implements InputManagerService.WindowManagerCal
}
// All the calls below need to happen without the WM lock held since they call into AM.
- mService.mAmInternal.saveANRState(reason);
+ mService.mAtmInternal.saveANRState(reason);
if (appWindowToken != null && appWindowToken.appToken != null) {
// Notify the activity manager about the timeout and let it decide whether
@@ -125,7 +125,7 @@ final class InputManagerCallback implements InputManagerService.WindowManagerCal
} else if (windowState != null) {
// Notify the activity manager about the timeout and let it decide whether
// to abort dispatching or keep waiting.
- long timeout = mService.mAtmInternal.inputDispatchingTimedOut(
+ long timeout = mService.mAmInternal.inputDispatchingTimedOut(
windowState.mSession.mPid, aboveSystem, reason);
if (timeout >= 0) {
// The activity manager declined to abort dispatching.
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index 15f693872158..ed3e6c6ad810 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -435,14 +435,14 @@ final class InputMonitor {
final RecentsAnimationController recentsAnimationController =
mService.getRecentsAnimationController();
if (recentsAnimationController != null
- && recentsAnimationController.hasInputConsumerForApp(w.mAppToken)) {
+ && recentsAnimationController.shouldApplyInputConsumer(w.mAppToken)) {
if (recentsAnimationController.updateInputConsumerForApp(
recentsAnimationInputConsumer.mWindowHandle, hasFocus)) {
addInputWindowHandle(recentsAnimationInputConsumer.mWindowHandle);
mAddRecentsAnimationInputConsumerHandle = false;
}
- // Skip adding the window below regardless of whether there is an input consumer
- // to handle it
+ // If the target app window does not yet exist, then we don't add the input
+ // consumer window, but also don't add the app window below.
return;
}
}
diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index 6fef16304d42..5c80759c6998 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -458,10 +458,9 @@ public class RecentsAnimationController implements DeathRecipient {
mRunner = null;
mCanceled = true;
- // Clear associated input consumers
+ // Update the input windows after the animation is complete
final InputMonitor inputMonitor =
mService.mRoot.getDisplayContent(mDisplayId).getInputMonitor();
- inputMonitor.destroyInputConsumer(INPUT_CONSUMER_RECENTS_ANIMATION);
inputMonitor.updateInputWindowsLw(true /*force*/);
// We have deferred all notifications to the target app as a part of the recents animation,
@@ -494,6 +493,11 @@ public class RecentsAnimationController implements DeathRecipient {
@Override
public void binderDied() {
cancelAnimation(REORDER_MOVE_TO_ORIGINAL_POSITION, "binderDied");
+
+ // Clear associated input consumers on runner death
+ final InputMonitor inputMonitor =
+ mService.mRoot.getDisplayContent(mDisplayId).getInputMonitor();
+ inputMonitor.destroyInputConsumer(INPUT_CONSUMER_RECENTS_ANIMATION);
}
void checkAnimationReady(WallpaperController wallpaperController) {
@@ -516,8 +520,14 @@ public class RecentsAnimationController implements DeathRecipient {
&& isTargetOverWallpaper();
}
- boolean hasInputConsumerForApp(AppWindowToken appToken) {
- return mInputConsumerEnabled && isAnimatingApp(appToken);
+ /**
+ * @return Whether to use the input consumer to override app input to route home/recents.
+ */
+ boolean shouldApplyInputConsumer(AppWindowToken appToken) {
+ // Only apply the input consumer if it is enabled, it is not the target (home/recents)
+ // being revealed with the transition, and we are actively animating the app as a part of
+ // the animation
+ return mInputConsumerEnabled && mTargetAppToken != appToken && isAnimatingApp(appToken);
}
boolean updateInputConsumerForApp(InputWindowHandle inputWindowHandle,
@@ -675,6 +685,7 @@ public class RecentsAnimationController implements DeathRecipient {
final String innerPrefix = prefix + " ";
pw.print(prefix); pw.println(RecentsAnimationController.class.getSimpleName() + ":");
pw.print(innerPrefix); pw.println("mPendingStart=" + mPendingStart);
+ pw.print(innerPrefix); pw.println("mPendingAnimations=" + mPendingAnimations.size());
pw.print(innerPrefix); pw.println("mCanceled=" + mCanceled);
pw.print(innerPrefix); pw.println("mInputConsumerEnabled=" + mInputConsumerEnabled);
pw.print(innerPrefix); pw.println("mSplitScreenMinimized=" + mSplitScreenMinimized);
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 3fef87dce460..c8977bede325 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -228,21 +228,6 @@ class RootWindowContainer extends WindowContainer<DisplayContent> {
mService.mDisplayManagerInternal.setDisplayInfoOverrideFromWindowManager(
displayId, dc.getDisplayInfo());
dc.configureDisplayPolicy();
-
- // Tap Listeners are supported for:
- // 1. All physical displays (multi-display).
- // 2. VirtualDisplays on VR, AA (and everything else).
- if (mService.canDispatchPointerEvents()) {
- if (DEBUG_DISPLAY) {
- Slog.d(TAG,
- "Registering PointerEventListener for DisplayId: " + displayId);
- }
- dc.mTapDetector = new TaskTapPointerEventListener(mService, dc);
- mService.registerPointerEventListener(dc.mTapDetector);
- if (displayId == DEFAULT_DISPLAY) {
- mService.registerPointerEventListener(mService.mMousePositionTracker);
- }
- }
}
return dc;
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/TaskSnapshotPersister.java b/services/core/java/com/android/server/wm/TaskSnapshotPersister.java
index 21e807eee1e8..6fd179550f00 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotPersister.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotPersister.java
@@ -17,6 +17,7 @@
package com.android.server.wm;
import static android.graphics.Bitmap.CompressFormat.*;
+
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
@@ -361,6 +362,7 @@ class TaskSnapshotPersister {
// For snapshots with reduced resolution, do not create or save full sized bitmaps
if (mSnapshot.isReducedResolution()) {
+ swBitmap.recycle();
return true;
}
@@ -373,6 +375,8 @@ class TaskSnapshotPersister {
Slog.e(TAG, "Unable to open " + file + " for persisting.", e);
return false;
}
+ reduced.recycle();
+ swBitmap.recycle();
return true;
}
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index e4e7194e380a..eff2ae001674 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;
@@ -763,8 +763,6 @@ public class WindowManagerService extends IWindowManager.Stub
final ArrayMap<AnimationAdapter, SurfaceAnimator> mAnimationTransferMap = new ArrayMap<>();
final BoundsAnimationController mBoundsAnimationController;
- private final PointerEventDispatcher mPointerEventDispatcher;
-
private WindowContentFrameStats mTempWindowRenderStats;
private final LatencyTracker mLatencyTracker;
@@ -955,14 +953,6 @@ public class WindowManagerService extends IWindowManager.Stub
LocalServices.addService(WindowManagerPolicy.class, mPolicy);
- if(mInputManager != null) {
- final InputChannel inputChannel = mInputManager.monitorInput(TAG_WM);
- mPointerEventDispatcher = inputChannel != null
- ? new PointerEventDispatcher(inputChannel) : null;
- } else {
- mPointerEventDispatcher = null;
- }
-
mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
mKeyguardDisableHandler = new KeyguardDisableHandler(mContext, mPolicy);
@@ -1940,7 +1930,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());
}
@@ -2697,8 +2687,9 @@ public class WindowManagerService extends IWindowManager.Stub
public void cleanupRecentsAnimation(@RecentsAnimationController.ReorderMode int reorderMode) {
synchronized (mWindowMap) {
if (mRecentsAnimationController != null) {
- mRecentsAnimationController.cleanupAnimation(reorderMode);
+ final RecentsAnimationController controller = mRecentsAnimationController;
mRecentsAnimationController = null;
+ controller.cleanupAnimation(reorderMode);
mAppTransition.updateBooster();
}
}
@@ -3164,18 +3155,23 @@ public class WindowManagerService extends IWindowManager.Stub
}
@Override
- public void registerPointerEventListener(PointerEventListener listener) {
- mPointerEventDispatcher.registerInputEventListener(listener);
+ public void registerPointerEventListener(PointerEventListener listener, int displayId) {
+ synchronized (mWindowMap) {
+ final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
+ if (displayContent != null) {
+ displayContent.registerPointerEventListener(listener);
+ }
+ }
}
@Override
- public void unregisterPointerEventListener(PointerEventListener listener) {
- mPointerEventDispatcher.unregisterInputEventListener(listener);
- }
-
- /** Check if the service is set to dispatch pointer events. */
- boolean canDispatchPointerEvents() {
- return mPointerEventDispatcher != null;
+ public void unregisterPointerEventListener(PointerEventListener listener, int displayId) {
+ synchronized (mWindowMap) {
+ final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
+ if (displayContent != null) {
+ displayContent.unregisterPointerEventListener(listener);
+ }
+ }
}
// Called by window manager policy. Not exposed externally.
@@ -4854,7 +4850,7 @@ public class WindowManagerService extends IWindowManager.Stub
synchronized (mWindowMap) {
mLastANRState = null;
}
- mAmInternal.clearSavedANRState();
+ mAtmInternal.clearSavedANRState();
}
break;
case WALLPAPER_DRAW_PENDING_TIMEOUT: {
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/core/jni/Android.bp b/services/core/jni/Android.bp
index 045f4ebf980f..15a3a1a3c378 100644
--- a/services/core/jni/Android.bp
+++ b/services/core/jni/Android.bp
@@ -99,6 +99,7 @@ cc_defaults {
"libutils",
"libhwui",
"libbpf",
+ "libnetdbpf",
"libnetdutils",
"android.hardware.audio.common@2.0",
"android.hardware.broadcastradio@1.0",
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index c66d03c3a5a3..3943dba7092e 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -217,7 +217,7 @@ public:
void setDisplayViewports(JNIEnv* env, jobjectArray viewportObjArray);
status_t registerInputChannel(JNIEnv* env, const sp<InputChannel>& inputChannel,
- const sp<InputWindowHandle>& inputWindowHandle, bool monitor);
+ const sp<InputWindowHandle>& inputWindowHandle, int32_t displayId);
status_t unregisterInputChannel(JNIEnv* env, const sp<InputChannel>& inputChannel);
void setInputWindows(JNIEnv* env, jobjectArray windowHandleObjArray, int32_t displayId);
@@ -442,11 +442,11 @@ void NativeInputManager::setDisplayViewports(JNIEnv* env, jobjectArray viewportO
}
status_t NativeInputManager::registerInputChannel(JNIEnv* /* env */,
- const sp<InputChannel>& inputChannel,
- const sp<InputWindowHandle>& inputWindowHandle, bool monitor) {
+ const sp<InputChannel>& inputChannel, const sp<InputWindowHandle>& inputWindowHandle,
+ int32_t displayId) {
ATRACE_CALL();
- return mInputManager->getDispatcher()->registerInputChannel(
- inputChannel, inputWindowHandle, monitor);
+ return mInputManager->getDispatcher()->registerInputChannel(inputChannel, inputWindowHandle,
+ displayId);
}
status_t NativeInputManager::unregisterInputChannel(JNIEnv* /* env */,
@@ -1316,7 +1316,7 @@ static void handleInputChannelDisposed(JNIEnv* env,
}
static void nativeRegisterInputChannel(JNIEnv* env, jclass /* clazz */,
- jlong ptr, jobject inputChannelObj, jobject inputWindowHandleObj, jboolean monitor) {
+ jlong ptr, jobject inputChannelObj, jobject inputWindowHandleObj, jint displayId) {
NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
sp<InputChannel> inputChannel = android_view_InputChannel_getInputChannel(env,
@@ -1330,7 +1330,7 @@ static void nativeRegisterInputChannel(JNIEnv* env, jclass /* clazz */,
android_server_InputWindowHandle_getHandle(env, inputWindowHandleObj);
status_t status = im->registerInputChannel(
- env, inputChannel, inputWindowHandle, monitor);
+ env, inputChannel, inputWindowHandle, displayId);
if (status) {
std::string message;
message += StringPrintf("Failed to register input channel. status=%d", status);
@@ -1338,7 +1338,8 @@ static void nativeRegisterInputChannel(JNIEnv* env, jclass /* clazz */,
return;
}
- if (! monitor) {
+ // If inputWindowHandle is null and displayId >= 0, treat inputChannel as monitor.
+ if (inputWindowHandle != nullptr || displayId == ADISPLAY_ID_NONE) {
android_view_InputChannel_setDisposeCallback(env, inputChannelObj,
handleInputChannelDisposed, im);
}
@@ -1639,7 +1640,7 @@ static const JNINativeMethod gInputManagerMethods[] = {
{ "nativeHasKeys", "(JII[I[Z)Z",
(void*) nativeHasKeys },
{ "nativeRegisterInputChannel",
- "(JLandroid/view/InputChannel;Lcom/android/server/input/InputWindowHandle;Z)V",
+ "(JLandroid/view/InputChannel;Lcom/android/server/input/InputWindowHandle;I)V",
(void*) nativeRegisterInputChannel },
{ "nativeUnregisterInputChannel", "(JLandroid/view/InputChannel;)V",
(void*) nativeUnregisterInputChannel },
diff --git a/services/core/jni/com_android_server_net_NetworkStatsService.cpp b/services/core/jni/com_android_server_net_NetworkStatsService.cpp
index 3302dea53506..649f1a56f011 100644
--- a/services/core/jni/com_android_server_net_NetworkStatsService.cpp
+++ b/services/core/jni/com_android_server_net_NetworkStatsService.cpp
@@ -30,8 +30,8 @@
#include <utils/Log.h>
#include "android-base/unique_fd.h"
-#include "bpf/BpfNetworkStats.h"
#include "bpf/BpfUtils.h"
+#include "netdbpf/BpfNetworkStats.h"
using android::bpf::Stats;
using android::bpf::hasBpfSupport;
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
index 4350596ee63e..2dbbf55a9347 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
@@ -15,7 +15,9 @@
*/
package com.android.server.devicepolicy;
+import android.app.admin.DevicePolicyManager;
import android.app.admin.IDevicePolicyManager;
+import android.content.ComponentName;
import com.android.server.SystemService;
@@ -68,7 +70,22 @@ abstract class BaseIDevicePolicyManager extends IDevicePolicyManager.Stub {
}
@Override
- public boolean checkDeviceIdentifierAccess(String packageName, int userHandle) {
+ public boolean checkDeviceIdentifierAccess(String packageName, int userHandle, int pid,
+ int uid) {
return false;
}
+
+ @Override
+ public void setGlobalPrivateDns(ComponentName who, int mode, String privateDnsHost) {
+ }
+
+ @Override
+ public int getGlobalPrivateDnsMode(ComponentName who) {
+ return DevicePolicyManager.PRIVATE_DNS_MODE_UNKNOWN;
+ }
+
+ @Override
+ public String getGlobalPrivateDnsHost(ComponentName who) {
+ return null;
+ }
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 913b844d8d57..26ea152761fb 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -55,12 +55,18 @@ import static android.app.admin.DevicePolicyManager.LOCK_TASK_FEATURE_NOTIFICATI
import static android.app.admin.DevicePolicyManager.LOCK_TASK_FEATURE_OVERVIEW;
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
+import static android.app.admin.DevicePolicyManager.PRIVATE_DNS_MODE_UNKNOWN;
+import static android.app.admin.DevicePolicyManager.PRIVATE_DNS_MODE_OFF;
+import static android.app.admin.DevicePolicyManager.PRIVATE_DNS_MODE_OPPORTUNISTIC;
+import static android.app.admin.DevicePolicyManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME;
import static android.app.admin.DevicePolicyManager.PROFILE_KEYGUARD_FEATURES_AFFECT_OWNER;
import static android.app.admin.DevicePolicyManager.WIPE_EUICC;
import static android.app.admin.DevicePolicyManager.WIPE_EXTERNAL_STORAGE;
import static android.app.admin.DevicePolicyManager.WIPE_RESET_PROTECTION_DATA;
import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES;
+import static android.provider.Settings.Global.PRIVATE_DNS_MODE;
+import static android.provider.Settings.Global.PRIVATE_DNS_SPECIFIER;
import static android.provider.Telephony.Carriers.DPC_URI;
import static android.provider.Telephony.Carriers.ENFORCE_KEY;
import static android.provider.Telephony.Carriers.ENFORCE_MANAGED_URI;
@@ -145,6 +151,7 @@ import android.media.AudioManager;
import android.media.IAudioService;
import android.net.ConnectivityManager;
import android.net.IIpConnectivityMetrics;
+import android.net.NetworkUtils;
import android.net.ProxyInfo;
import android.net.Uri;
import android.net.metrics.IpConnectivityLog;
@@ -395,6 +402,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
GLOBAL_SETTINGS_WHITELIST.add(Settings.Global.WIFI_SLEEP_POLICY);
GLOBAL_SETTINGS_WHITELIST.add(Settings.Global.STAY_ON_WHILE_PLUGGED_IN);
GLOBAL_SETTINGS_WHITELIST.add(Settings.Global.WIFI_DEVICE_OWNER_CONFIGS_LOCKDOWN);
+ GLOBAL_SETTINGS_WHITELIST.add(Settings.Global.PRIVATE_DNS_MODE);
+ GLOBAL_SETTINGS_WHITELIST.add(Settings.Global.PRIVATE_DNS_SPECIFIER);
GLOBAL_SETTINGS_DEPRECATED = new ArraySet<>();
GLOBAL_SETTINGS_DEPRECATED.add(Settings.Global.BLUETOOTH_ON);
@@ -7862,7 +7871,21 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
@Override
- public boolean checkDeviceIdentifierAccess(String packageName, int userHandle) {
+ public boolean checkDeviceIdentifierAccess(String packageName, int userHandle, int pid,
+ int uid) {
+ // If the caller is not a system app then it should only be able to check its own device
+ // identifier access.
+ int callingAppId = UserHandle.getAppId(mInjector.binderGetCallingUid());
+ if (callingAppId >= Process.FIRST_APPLICATION_UID
+ && callingAppId != UserHandle.getAppId(uid)) {
+ return false;
+ }
+ // A device or profile owner must also have the READ_PHONE_STATE permission to access device
+ // identifiers. If the package being checked does not have this permission then deny access.
+ if (mContext.checkPermission(android.Manifest.permission.READ_PHONE_STATE, pid, uid)
+ != PackageManager.PERMISSION_GRANTED) {
+ return false;
+ }
// Allow access to the device owner.
ComponentName deviceOwner = getDeviceOwnerComponent(true);
if (deviceOwner != null && deviceOwner.getPackageName().equals(packageName)) {
@@ -13114,4 +13137,78 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
private static String getManagedProvisioningPackage(Context context) {
return context.getResources().getString(R.string.config_managed_provisioning_package);
}
+
+ private void putPrivateDnsSettings(@Nullable String mode, @Nullable String host) {
+ // Set Private DNS settings using system permissions, as apps cannot write
+ // to global settings.
+ long origId = mInjector.binderClearCallingIdentity();
+ try {
+ mInjector.settingsGlobalPutString(PRIVATE_DNS_MODE, mode);
+ mInjector.settingsGlobalPutString(PRIVATE_DNS_SPECIFIER, host);
+ } finally {
+ mInjector.binderRestoreCallingIdentity(origId);
+ }
+ }
+
+ @Override
+ public void setGlobalPrivateDns(@NonNull ComponentName who, int mode, String privateDnsHost) {
+ if (!mHasFeature) {
+ return;
+ }
+
+ Preconditions.checkNotNull(who, "ComponentName is null");
+ enforceDeviceOwner(who);
+
+ switch (mode) {
+ case PRIVATE_DNS_MODE_OPPORTUNISTIC:
+ if (!TextUtils.isEmpty(privateDnsHost)) {
+ throw new IllegalArgumentException("A DNS host should not be provided when " +
+ "setting opportunistic mode.");
+ }
+ putPrivateDnsSettings(ConnectivityManager.PRIVATE_DNS_MODE_OPPORTUNISTIC, null);
+ break;
+ case PRIVATE_DNS_MODE_PROVIDER_HOSTNAME:
+ if (!NetworkUtils.isWeaklyValidatedHostname(privateDnsHost)) {
+ throw new IllegalArgumentException(
+ String.format("Provided hostname is not valid: %s", privateDnsHost));
+ }
+ putPrivateDnsSettings(ConnectivityManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME,
+ privateDnsHost);
+ break;
+ default:
+ throw new IllegalArgumentException(String.format("Unsupported mode: %d", mode));
+ }
+ }
+
+ @Override
+ public int getGlobalPrivateDnsMode(@NonNull ComponentName who) {
+ if (!mHasFeature) {
+ return PRIVATE_DNS_MODE_UNKNOWN;
+ }
+
+ Preconditions.checkNotNull(who, "ComponentName is null");
+ enforceDeviceOwner(who);
+ switch (mInjector.settingsGlobalGetString(PRIVATE_DNS_MODE)) {
+ case ConnectivityManager.PRIVATE_DNS_MODE_OFF:
+ return PRIVATE_DNS_MODE_OFF;
+ case ConnectivityManager.PRIVATE_DNS_MODE_OPPORTUNISTIC:
+ return PRIVATE_DNS_MODE_OPPORTUNISTIC;
+ case ConnectivityManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME:
+ return PRIVATE_DNS_MODE_PROVIDER_HOSTNAME;
+ }
+
+ return PRIVATE_DNS_MODE_UNKNOWN;
+ }
+
+ @Override
+ public String getGlobalPrivateDnsHost(@NonNull ComponentName who) {
+ if (!mHasFeature) {
+ return null;
+ }
+
+ Preconditions.checkNotNull(who, "ComponentName is null");
+ enforceDeviceOwner(who);
+
+ return mInjector.settingsGlobalGetString(PRIVATE_DNS_SPECIFIER);
+ }
}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index d93a6c767041..adff23ed28d6 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -474,6 +474,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 95ed00f3ad5b..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);
@@ -360,8 +425,56 @@ public class DeviceIdleControllerTest {
}
@Test
+ public void testStepIdleStateLocked_ValidStates_WithWakeFromIdleAlarmSoon() {
+ enterDeepState(STATE_ACTIVE);
+ // Return that there's an alarm coming soon.
+ doReturn(SystemClock.elapsedRealtime() + mConstants.MIN_TIME_TO_ALARM / 2).when(
+ mAlarmManager).getNextWakeFromIdleTime();
+ mDeviceIdleController.stepIdleStateLocked("testing");
+ verifyStateConditions(STATE_ACTIVE);
+
+ // Everything besides ACTIVE should end up as INACTIVE since the screen would be off.
+
+ enterDeepState(STATE_INACTIVE);
+ doReturn(SystemClock.elapsedRealtime() + mConstants.MIN_TIME_TO_ALARM / 2).when(
+ mAlarmManager).getNextWakeFromIdleTime();
+ mDeviceIdleController.stepIdleStateLocked("testing");
+ verifyStateConditions(STATE_INACTIVE);
+
+ enterDeepState(STATE_IDLE_PENDING);
+ doReturn(SystemClock.elapsedRealtime() + mConstants.MIN_TIME_TO_ALARM / 2).when(
+ mAlarmManager).getNextWakeFromIdleTime();
+ mDeviceIdleController.stepIdleStateLocked("testing");
+ verifyStateConditions(STATE_INACTIVE);
+
+ enterDeepState(STATE_SENSING);
+ doReturn(SystemClock.elapsedRealtime() + mConstants.MIN_TIME_TO_ALARM / 2).when(
+ mAlarmManager).getNextWakeFromIdleTime();
+ mDeviceIdleController.stepIdleStateLocked("testing");
+ verifyStateConditions(STATE_INACTIVE);
+
+ enterDeepState(STATE_LOCATING);
+ doReturn(SystemClock.elapsedRealtime() + mConstants.MIN_TIME_TO_ALARM / 2).when(
+ mAlarmManager).getNextWakeFromIdleTime();
+ mDeviceIdleController.stepIdleStateLocked("testing");
+ verifyStateConditions(STATE_INACTIVE);
+
+ enterDeepState(STATE_IDLE);
+ doReturn(SystemClock.elapsedRealtime() + mConstants.MIN_TIME_TO_ALARM / 2).when(
+ mAlarmManager).getNextWakeFromIdleTime();
+ mDeviceIdleController.stepIdleStateLocked("testing");
+ verifyStateConditions(STATE_INACTIVE);
+
+ enterDeepState(STATE_IDLE_MAINTENANCE);
+ doReturn(SystemClock.elapsedRealtime() + mConstants.MIN_TIME_TO_ALARM / 2).when(
+ mAlarmManager).getNextWakeFromIdleTime();
+ mDeviceIdleController.stepIdleStateLocked("testing");
+ verifyStateConditions(STATE_INACTIVE);
+ }
+
+ @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.
@@ -427,9 +540,9 @@ 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.
- // TODO: add tests for when there's a wake-from-idle alarm coming soon.
doReturn(Long.MAX_VALUE).when(mAlarmManager).getNextWakeFromIdleTime();
// Set state to INACTIVE.
mDeviceIdleController.becomeActiveLocked("testing", 0);
@@ -463,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);
@@ -903,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.
@@ -917,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
@@ -925,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;
@@ -954,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;
@@ -979,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/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
index 1eb88baafa48..113ee2df768e 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
@@ -26,13 +26,21 @@ import static android.net.NetworkPolicy.WARNING_DISABLED;
import static android.net.NetworkPolicyManager.POLICY_ALLOW_METERED_BACKGROUND;
import static android.net.NetworkPolicyManager.POLICY_NONE;
import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND;
+import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL;
+import static android.net.NetworkPolicyManager.RULE_ALLOW_METERED;
+import static android.net.NetworkPolicyManager.RULE_NONE;
+import static android.net.NetworkPolicyManager.RULE_REJECT_ALL;
+import static android.net.NetworkPolicyManager.RULE_REJECT_METERED;
+import static android.net.NetworkPolicyManager.RULE_TEMPORARY_ALLOW_METERED;
import static android.net.NetworkPolicyManager.uidPoliciesToString;
+import static android.net.NetworkPolicyManager.uidRulesToString;
import static android.net.NetworkStats.IFACE_ALL;
import static android.net.NetworkStats.SET_ALL;
import static android.net.NetworkStats.TAG_ALL;
import static android.net.NetworkTemplate.buildTemplateMobileAll;
import static android.net.NetworkTemplate.buildTemplateWifi;
import static android.net.TrafficStats.MB_IN_BYTES;
+import static android.os.Process.SYSTEM_UID;
import static android.telephony.CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED;
import static android.telephony.CarrierConfigManager.DATA_CYCLE_THRESHOLD_DISABLED;
import static android.telephony.CarrierConfigManager.DATA_CYCLE_USE_PLATFORM_DEFAULT;
@@ -124,6 +132,7 @@ import android.text.TextUtils;
import android.text.format.Time;
import android.util.DataUnit;
import android.util.Log;
+import android.util.Pair;
import android.util.Range;
import android.util.RecurrenceRule;
@@ -171,6 +180,7 @@ import java.time.Period;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Iterator;
@@ -1644,6 +1654,76 @@ public class NetworkPolicyManagerServiceTest {
true);
}
+ /**
+ * Exhaustively test isUidNetworkingBlocked to output the expected results based on external
+ * conditions.
+ */
+ @Test
+ public void testIsUidNetworkingBlocked() {
+ final ArrayList<Pair<Boolean, Integer>> expectedBlockedStates = new ArrayList<>();
+
+ // Metered network. Data saver on.
+ expectedBlockedStates.add(new Pair<>(true, RULE_NONE));
+ expectedBlockedStates.add(new Pair<>(false, RULE_ALLOW_METERED));
+ expectedBlockedStates.add(new Pair<>(false, RULE_TEMPORARY_ALLOW_METERED));
+ expectedBlockedStates.add(new Pair<>(true, RULE_REJECT_METERED));
+ expectedBlockedStates.add(new Pair<>(true, RULE_ALLOW_ALL));
+ expectedBlockedStates.add(new Pair<>(true, RULE_REJECT_ALL));
+ verifyNetworkBlockedState(
+ true /* metered */, true /* backgroundRestricted */, expectedBlockedStates);
+ expectedBlockedStates.clear();
+
+ // Metered network. Data saver off.
+ expectedBlockedStates.add(new Pair<>(false, RULE_NONE));
+ expectedBlockedStates.add(new Pair<>(false, RULE_ALLOW_METERED));
+ expectedBlockedStates.add(new Pair<>(false, RULE_TEMPORARY_ALLOW_METERED));
+ expectedBlockedStates.add(new Pair<>(true, RULE_REJECT_METERED));
+ expectedBlockedStates.add(new Pair<>(false, RULE_ALLOW_ALL));
+ expectedBlockedStates.add(new Pair<>(true, RULE_REJECT_ALL));
+ verifyNetworkBlockedState(
+ true /* metered */, false /* backgroundRestricted */, expectedBlockedStates);
+ expectedBlockedStates.clear();
+
+ // Non-metered network. Data saver on.
+ expectedBlockedStates.add(new Pair<>(false, RULE_NONE));
+ expectedBlockedStates.add(new Pair<>(false, RULE_ALLOW_METERED));
+ expectedBlockedStates.add(new Pair<>(false, RULE_TEMPORARY_ALLOW_METERED));
+ expectedBlockedStates.add(new Pair<>(false, RULE_REJECT_METERED));
+ expectedBlockedStates.add(new Pair<>(false, RULE_ALLOW_ALL));
+ expectedBlockedStates.add(new Pair<>(true, RULE_REJECT_ALL));
+ verifyNetworkBlockedState(
+ false /* metered */, true /* backgroundRestricted */, expectedBlockedStates);
+
+ // Non-metered network. Data saver off. The result is the same as previous case since
+ // the network is blocked only for RULE_REJECT_ALL regardless of data saver.
+ verifyNetworkBlockedState(
+ false /* metered */, false /* backgroundRestricted */, expectedBlockedStates);
+ expectedBlockedStates.clear();
+ }
+
+ private void verifyNetworkBlockedState(boolean metered, boolean backgroundRestricted,
+ ArrayList<Pair<Boolean, Integer>> expectedBlockedStateForRules) {
+ final NetworkPolicyManagerInternal npmi = LocalServices
+ .getService(NetworkPolicyManagerInternal.class);
+
+ for (Pair<Boolean, Integer> pair : expectedBlockedStateForRules) {
+ final boolean expectedResult = pair.first;
+ final int rule = pair.second;
+ assertEquals(formatBlockedStateError(UID_A, rule, metered, backgroundRestricted),
+ expectedResult,
+ npmi.isUidNetworkingBlocked(UID_A, rule, metered, backgroundRestricted));
+ assertFalse(formatBlockedStateError(SYSTEM_UID, rule, metered, backgroundRestricted),
+ npmi.isUidNetworkingBlocked(SYSTEM_UID, rule, metered, backgroundRestricted));
+ }
+ }
+
+ private String formatBlockedStateError(int uid, int rule, boolean metered,
+ boolean backgroundRestricted) {
+ return String.format(
+ "Unexpected BlockedState: (uid=%d, rule=%s, metered=%b, backgroundRestricted=%b)",
+ uid, uidRulesToString(rule), metered, backgroundRestricted);
+ }
+
private SubscriptionPlan buildMonthlyDataPlan(ZonedDateTime start, long limitBytes) {
return SubscriptionPlan.Builder
.createRecurringMonthly(start)
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/ActivityManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java
index c44e492e308b..f42f5b1fff2e 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java
@@ -64,6 +64,7 @@ import android.os.Process;
import android.os.RemoteException;
import android.os.SystemClock;
+import androidx.test.filters.FlakyTest;
import androidx.test.filters.MediumTest;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
@@ -102,6 +103,7 @@ import java.util.function.Function;
* com.android.frameworks.servicestests/androidx.test.runner.AndroidJUnitRunner
*/
@SmallTest
+@FlakyTest(bugId = 113616538)
@RunWith(AndroidJUnit4.class)
public class ActivityManagerServiceTest {
private static final String TAG = ActivityManagerServiceTest.class.getSimpleName();
@@ -173,7 +175,7 @@ public class ActivityManagerServiceTest {
true); // expectNotify
// Explicitly setting the seq counter for more verification.
- mAms.mProcStateSeqCounter = 42;
+ mAms.mProcessList.mProcStateSeqCounter = 42;
// Uid state is not moving from background to foreground or vice versa.
verifySeqCounterAndInteractions(uidRec,
@@ -260,7 +262,7 @@ public class ActivityManagerServiceTest {
final ProcessRecord appRec = new ProcessRecord(mAms, new ApplicationInfo(), TAG, uid, null);
appRec.thread = Mockito.mock(IApplicationThread.class);
- mAms.mLruProcesses.add(appRec);
+ mAms.mProcessList.mLruProcesses.add(appRec);
return uidRec;
}
@@ -275,11 +277,11 @@ public class ActivityManagerServiceTest {
uidRec.curProcState = curState;
mAms.incrementProcStateSeqAndNotifyAppsLocked();
- assertEquals(expectedGlobalCounter, mAms.mProcStateSeqCounter);
+ assertEquals(expectedGlobalCounter, mAms.mProcessList.mProcStateSeqCounter);
assertEquals(expectedCurProcStateSeq, uidRec.curProcStateSeq);
- for (int i = mAms.mLruProcesses.size() - 1; i >= 0; --i) {
- final ProcessRecord app = mAms.mLruProcesses.get(i);
+ for (int i = mAms.mProcessList.getLruSizeLocked() - 1; i >= 0; --i) {
+ final ProcessRecord app = mAms.mProcessList.mLruProcesses.get(i);
// AMS should notify apps only for block states other than NETWORK_STATE_NO_CHANGE.
if (app.uid == uidRec.uid && expectedBlockState == NETWORK_STATE_BLOCK) {
verify(app.thread).setNetworkBlockSeq(uidRec.curProcStateSeq);
@@ -829,4 +831,4 @@ public class ActivityManagerServiceTest {
mRestricted = restricted;
}
}
-} \ No newline at end of file
+}
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityManagerTest.java b/services/tests/servicestests/src/com/android/server/am/ActivityManagerTest.java
index ba25b1659bd2..2dfb3751c021 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityManagerTest.java
@@ -16,38 +16,59 @@
package com.android.server.am;
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertEquals;
+
import android.app.ActivityManager;
+import android.app.ActivityManager.RecentTaskInfo;
import android.app.IActivityManager;
-import android.os.ServiceManager;
-import android.os.UserHandle;
import android.os.RemoteException;
-import android.test.AndroidTestCase;
+import android.os.UserHandle;
+import android.platform.test.annotations.Presubmit;
+
+import org.junit.Before;
+import org.junit.Test;
import java.util.List;
-public class ActivityManagerTest extends AndroidTestCase {
+import androidx.test.filters.FlakyTest;
+
+/**
+ * Tests for {@link ActivityManager}.
+ *
+ * Build/Install/Run:
+ * atest FrameworksServicesTests:com.android.server.am.ActivityManagerTest
+ */
+@Presubmit
+@FlakyTest(detail = "Promote to presubmit if stable")
+public class ActivityManagerTest {
+
+ private IActivityManager service;
- IActivityManager service;
- @Override
+ @Before
public void setUp() throws Exception {
- super.setUp();
service = ActivityManager.getService();
}
+ @Test
public void testTaskIdsForRunningUsers() throws RemoteException {
- for(int userId : service.getRunningUserIds()) {
+ int[] runningUserIds = service.getRunningUserIds();
+ assertThat(runningUserIds).isNotEmpty();
+ for (int userId : runningUserIds) {
testTaskIdsForUser(userId);
}
}
private void testTaskIdsForUser(int userId) throws RemoteException {
- List<ActivityManager.RecentTaskInfo> recentTasks = service.getRecentTasks(
- 100, 0, userId).getList();
- if(recentTasks != null) {
- for(ActivityManager.RecentTaskInfo recentTask : recentTasks) {
- int taskId = recentTask.persistentId;
+ List<?> recentTasks = service.getRecentTasks(100, 0, userId).getList();
+ if (recentTasks != null) {
+ for (Object elem : recentTasks) {
+ assertThat(elem).isInstanceOf(RecentTaskInfo.class);
+ RecentTaskInfo recentTask = (RecentTaskInfo) elem;
+ int taskId = recentTask.taskId;
assertEquals("The task id " + taskId + " should not belong to user " + userId,
- taskId / UserHandle.PER_USER_RANGE, userId);
+ taskId / UserHandle.PER_USER_RANGE, userId);
}
}
}
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java
index 81a0934a3460..cc7a24d5700e 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java
@@ -18,6 +18,7 @@ package com.android.server.am;
import static android.app.ActivityManager.START_DELIVERED_TO_TOP;
import static android.app.ActivityManager.START_TASK_TO_FRONT;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY;
@@ -34,9 +35,11 @@ import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.contains;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
@@ -407,6 +410,57 @@ public class ActivityStackSupervisorTests extends ActivityTestsBase {
}
/**
+ * Verify that home stack would be moved to front when the top activity is Recents.
+ */
+ @Test
+ public void testFindTaskToMoveToFrontWhenRecentsOnTop() throws Exception {
+ // Create stack/task on default display.
+ final ActivityDisplay display = mSupervisor.getDefaultDisplay();
+ final ActivityStack targetStack = display.createStack(WINDOWING_MODE_FULLSCREEN,
+ ACTIVITY_TYPE_STANDARD, false /* onTop */);
+ final TaskRecord targetTask = new TaskBuilder(mSupervisor).setStack(targetStack).build();
+
+ // Create Recents on top of the display.
+ final ActivityStack stack = display.createStack(WINDOWING_MODE_FULLSCREEN,
+ ACTIVITY_TYPE_RECENTS, true /* onTop */);
+ final TaskRecord task = new TaskBuilder(mSupervisor).setStack(stack).build();
+ new ActivityBuilder(mService).setTask(task).build();
+
+ final String reason = "findTaskToMoveToFront";
+ mSupervisor.findTaskToMoveToFront(targetTask, 0, ActivityOptions.makeBasic(), reason,
+ false);
+
+ verify(display).moveHomeStackToFront(contains(reason));
+ }
+
+ /**
+ * Verify that home stack won't be moved to front if the top activity on other display is
+ * Recents.
+ */
+ @Test
+ public void testFindTaskToMoveToFrontWhenRecentsOnOtherDisplay() throws Exception {
+ // Create stack/task on default display.
+ final ActivityDisplay display = mSupervisor.getDefaultDisplay();
+ final ActivityStack targetStack = display.createStack(WINDOWING_MODE_FULLSCREEN,
+ ACTIVITY_TYPE_STANDARD, false /* onTop */);
+ final TaskRecord targetTask = new TaskBuilder(mSupervisor).setStack(targetStack).build();
+
+ // Create Recents on secondary display.
+ final TestActivityDisplay secondDisplay = addNewActivityDisplayAt(
+ ActivityDisplay.POSITION_TOP);
+ final ActivityStack stack = secondDisplay.createStack(WINDOWING_MODE_FULLSCREEN,
+ ACTIVITY_TYPE_RECENTS, true /* onTop */);
+ final TaskRecord task = new TaskBuilder(mSupervisor).setStack(stack).build();
+ new ActivityBuilder(mService).setTask(task).build();
+
+ final String reason = "findTaskToMoveToFront";
+ mSupervisor.findTaskToMoveToFront(targetTask, 0, ActivityOptions.makeBasic(), reason,
+ false);
+
+ verify(display, never()).moveHomeStackToFront(contains(reason));
+ }
+
+ /**
* Verify if a stack is not at the topmost position, it should be able to resume its activity if
* the stack is the top focused.
*/
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..ba64b51c9e84 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,8 @@ 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.ActivityDisplay.POSITION_TOP;
+import static com.android.server.am.ActivityTaskManagerService.ANIMATE;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
@@ -48,6 +49,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 +208,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 +356,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);
@@ -408,8 +412,9 @@ public class ActivityStarterTests extends ActivityTestsBase {
.setActivityOptions(new SafeActivityOptions(options))
.execute();
- // verify that values are passed to the modifier.
- verify(modifier, times(1)).onCalculate(any(), eq(windowLayout), any(), any(), eq(options),
+ // verify that values are passed to the modifier. Values are passed twice -- once for
+ // setting initial state, another when task is created.
+ verify(modifier, times(2)).onCalculate(any(), eq(windowLayout), any(), any(), eq(options),
any(), any());
}
@@ -510,7 +515,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 +533,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)
@@ -558,23 +563,13 @@ public class ActivityStarterTests extends ActivityTestsBase {
false /* mockGetLaunchStack */);
// Create a secondary display at bottom.
- final TestActivityDisplay secondaryDisplay = spy(addNewActivityDisplayAt(POSITION_BOTTOM));
+ final TestActivityDisplay secondaryDisplay = spy(createNewActivityDisplay());
+ mSupervisor.addChild(secondaryDisplay, POSITION_BOTTOM);
final ActivityStack stack = secondaryDisplay.createStack(WINDOWING_MODE_FULLSCREEN,
ACTIVITY_TYPE_STANDARD, true /* onTop */);
// Create an activity record on the top of secondary display.
- final ComponentName componentName = ComponentName.createRelative(
- DEFAULT_COMPONENT_PACKAGE_NAME,
- DEFAULT_COMPONENT_PACKAGE_NAME + ".ReusableActivity");
- final TaskRecord taskRecord = new TaskBuilder(mSupervisor)
- .setComponent(componentName)
- .setStack(stack)
- .build();
- final ActivityRecord topActivityOnSecondaryDisplay = new ActivityBuilder(mService)
- .setComponent(componentName)
- .setLaunchMode(LAUNCH_SINGLE_TASK)
- .setTask(taskRecord)
- .build();
+ final ActivityRecord topActivityOnSecondaryDisplay = createSingleTaskActivityOn(stack);
// Put an activity on default display as the top focused activity.
new ActivityBuilder(mService).setCreateTask(true).build();
@@ -596,6 +591,59 @@ public class ActivityStarterTests extends ActivityTestsBase {
}
/**
+ * This test ensures that when starting an existing non-top single task activity on secondary
+ * display which is the top focused display, it should bring the task to front without creating
+ * unused stack.
+ */
+ @Test
+ public void testBringTaskToFrontOnSecondaryDisplay() {
+ final ActivityStarter starter = prepareStarter(FLAG_ACTIVITY_NEW_TASK,
+ false /* mockGetLaunchStack */);
+
+ // Create a secondary display with an activity.
+ final TestActivityDisplay secondaryDisplay = spy(createNewActivityDisplay());
+ mSupervisor.addChild(secondaryDisplay, POSITION_TOP);
+ final ActivityRecord singleTaskActivity = createSingleTaskActivityOn(
+ secondaryDisplay.createStack(WINDOWING_MODE_FULLSCREEN,
+ ACTIVITY_TYPE_STANDARD, false /* onTop */));
+
+ // Create another activity on top of the secondary display.
+ final ActivityStack topStack = secondaryDisplay.createStack(WINDOWING_MODE_FULLSCREEN,
+ ACTIVITY_TYPE_STANDARD, true /* onTop */);
+ final TaskRecord topTask = new TaskBuilder(mSupervisor).setStack(topStack).build();
+ new ActivityBuilder(mService).setTask(topTask).build();
+
+ // Start activity with the same intent as {@code singleTaskActivity} on secondary display.
+ final ActivityOptions options = ActivityOptions.makeBasic()
+ .setLaunchDisplayId(secondaryDisplay.mDisplayId);
+ final int result = starter.setReason("testBringTaskToFrontOnSecondaryDisplay")
+ .setIntent(singleTaskActivity.intent)
+ .setActivityOptions(options.toBundle())
+ .execute();
+
+ // Ensure result is moving existing task to front.
+ assertEquals(START_TASK_TO_FRONT, result);
+
+ // Ensure secondary display only creates two stacks.
+ verify(secondaryDisplay, times(2)).createStack(anyInt(), anyInt(), anyBoolean());
+ }
+
+ private ActivityRecord createSingleTaskActivityOn(ActivityStack stack) {
+ final ComponentName componentName = ComponentName.createRelative(
+ DEFAULT_COMPONENT_PACKAGE_NAME,
+ DEFAULT_COMPONENT_PACKAGE_NAME + ".SingleTaskActivity");
+ final TaskRecord taskRecord = new TaskBuilder(mSupervisor)
+ .setComponent(componentName)
+ .setStack(stack)
+ .build();
+ return new ActivityBuilder(mService)
+ .setComponent(componentName)
+ .setLaunchMode(LAUNCH_SINGLE_TASK)
+ .setTask(taskRecord)
+ .build();
+ }
+
+ /**
* This test ensures that a reused top activity in the top focused stack is able to be
* reparented to another display.
*/
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..58fe70d7d992 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.
@@ -545,6 +546,11 @@ public class ActivityTestsBase {
ActivityDisplay getDefaultDisplay() {
return mDisplay;
}
+
+ @Override
+ void setWindowManager(WindowManagerService wm) {
+ mWindowManager = wm;
+ }
}
protected static class TestActivityDisplay extends ActivityDisplay {
diff --git a/services/tests/servicestests/src/com/android/server/am/AppErrorDialogTest.java b/services/tests/servicestests/src/com/android/server/am/AppErrorDialogTest.java
index 3819e2190d88..06d41f1919c8 100644
--- a/services/tests/servicestests/src/com/android/server/am/AppErrorDialogTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/AppErrorDialogTest.java
@@ -21,6 +21,7 @@ import android.os.Handler;
import androidx.test.InstrumentationRegistry;
import androidx.test.annotation.UiThreadTest;
+import androidx.test.filters.FlakyTest;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
@@ -37,6 +38,7 @@ import java.io.File;
*/
@RunWith(AndroidJUnit4.class)
@SmallTest
+@FlakyTest(bugId = 113616538)
public class AppErrorDialogTest {
private Context mContext;
diff --git a/services/tests/servicestests/src/com/android/server/am/AssistDataRequesterTest.java b/services/tests/servicestests/src/com/android/server/am/AssistDataRequesterTest.java
index a030210398d6..1b823ff8c6b4 100644
--- a/services/tests/servicestests/src/com/android/server/am/AssistDataRequesterTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/AssistDataRequesterTest.java
@@ -46,6 +46,7 @@ import android.util.Log;
import android.view.IWindowManager;
import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.FlakyTest;
import androidx.test.filters.MediumTest;
import androidx.test.runner.AndroidJUnit4;
@@ -67,6 +68,7 @@ import java.util.concurrent.TimeUnit;
* runtest --path frameworks/base/services/tests/servicestests/src/com/android/server/am/AssistDataRequesterTest.java
*/
@MediumTest
+@FlakyTest(bugId = 113616538)
@RunWith(AndroidJUnit4.class)
public class AssistDataRequesterTest extends ActivityTestsBase {
diff --git a/services/tests/servicestests/src/com/android/server/am/CoreSettingsObserverTest.java b/services/tests/servicestests/src/com/android/server/am/CoreSettingsObserverTest.java
index fe8256eeb977..719e0edc20b7 100644
--- a/services/tests/servicestests/src/com/android/server/am/CoreSettingsObserverTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/CoreSettingsObserverTest.java
@@ -132,15 +132,36 @@ public class CoreSettingsObserverTest {
settingsBundle.containsKey(TEST_SETTING_SYSTEM_STRING));
}
+ @Test
+ public void testPopulateSettings_settingDeleted() {
+ Settings.Secure.putInt(mContentResolver, TEST_SETTING_SECURE_INT, TEST_INT);
+ Settings.Global.putFloat(mContentResolver, TEST_SETTING_GLOBAL_FLOAT, TEST_FLOAT);
+ Settings.System.putString(mContentResolver, TEST_SETTING_SYSTEM_STRING, TEST_STRING);
+
+ Bundle settingsBundle = getPopulatedBundle();
+
+ assertEquals("Unexpected value of " + TEST_SETTING_SECURE_INT,
+ TEST_INT, settingsBundle.getInt(TEST_SETTING_SECURE_INT));
+ assertEquals("Unexpected value of " + TEST_SETTING_GLOBAL_FLOAT,
+ TEST_FLOAT, settingsBundle.getFloat(TEST_SETTING_GLOBAL_FLOAT), 0);
+ assertEquals("Unexpected value of " + TEST_SETTING_SYSTEM_STRING,
+ TEST_STRING, settingsBundle.getString(TEST_SETTING_SYSTEM_STRING));
+
+ Settings.Global.putString(mContentResolver, TEST_SETTING_GLOBAL_FLOAT, null);
+ settingsBundle = getPopulatedBundle();
+
+ assertFalse("Bundle should not contain " + TEST_SETTING_GLOBAL_FLOAT,
+ settingsBundle.containsKey(TEST_SETTING_GLOBAL_FLOAT));
+ assertEquals("Unexpected value of " + TEST_SETTING_SECURE_INT,
+ TEST_INT, settingsBundle.getInt(TEST_SETTING_SECURE_INT));
+ assertEquals("Unexpected value of " + TEST_SETTING_SYSTEM_STRING,
+ TEST_STRING, settingsBundle.getString(TEST_SETTING_SYSTEM_STRING));
+
+ }
+
private Bundle getPopulatedBundle() {
- final Bundle settingsBundle = new Bundle();
- mCoreSettingsObserver.populateSettings(settingsBundle,
- CoreSettingsObserver.sGlobalSettingToTypeMap);
- mCoreSettingsObserver.populateSettings(settingsBundle,
- CoreSettingsObserver.sSecureSettingToTypeMap);
- mCoreSettingsObserver.populateSettings(settingsBundle,
- CoreSettingsObserver.sSystemSettingToTypeMap);
- return settingsBundle;
+ mCoreSettingsObserver.onChange(false);
+ return mCoreSettingsObserver.getCoreSettingsLocked();
}
private class TestInjector extends Injector {
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..169204fe374a 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,1091 @@
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT 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 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 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();
- // 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();
+ mActivity = new ActivityBuilder(mService).build();
+ mActivity.appInfo.targetSdkVersion = Build.VERSION_CODES.N_MR1;
+ mActivity.info.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES;
- mPositioner = new TaskLaunchParamsModifier();
+ mTarget = new TaskLaunchParamsModifier(mSupervisor);
- mResult = new LaunchParamsController.LaunchParams();
- mCurrent = new LaunchParamsController.LaunchParams();
+ mCurrent = new LaunchParams();
+ mCurrent.reset();
+ mResult = new LaunchParams();
+ mResult.reset();
}
- /**
- * 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 testReturnsSkipWithEmptyActivity() {
+ final TaskRecord task = new TaskBuilder(mSupervisor).build();
+ assertEquals(RESULT_SKIP, mTarget.onCalculate(task, /* layout */ null,
+ /* activity */ null, /* source */ null, /* options */ null, mCurrent, mResult));
}
- /**
- * Ensures that a task positioned with no {@link WindowLayout} receives the default launch
- * position.
- * @throws Exception
- */
+ // =============================
+ // Display ID Related Tests
+ // =============================
@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 testDefaultToPrimaryDisplay() {
+ createNewActivityDisplay(WINDOWING_MODE_FREEFORM);
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+ mActivity, /* source */ null, /* options */ null, mCurrent, mResult));
+
+ assertEquals(DEFAULT_DISPLAY, 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 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 a {@link WindowLayout} gravity specified is positioned
- * according to specification.
- * @throws Exception
- */
@Test
- public void testlaunchWindowLayoutGravity() throws Exception {
- // Unspecified gravity should be ignored
- testGravity(Gravity.NO_GRAVITY);
+ public void testUsesSourcesDisplayIdIfSet() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+ final TestActivityDisplay fullscreenDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FULLSCREEN);
+
+ mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
- // Unsupported gravity should be ignored
- testGravity(Gravity.LEFT);
- testGravity(Gravity.RIGHT);
+ ActivityRecord source = createSourceActivity(fullscreenDisplay);
- // Test defaults for vertical gravities
- testGravity(Gravity.TOP);
- testGravity(Gravity.BOTTOM);
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+ mActivity, source, /* options */ null, mCurrent, mResult));
- // Test corners
- testGravity(Gravity.TOP | Gravity.LEFT);
- testGravity(Gravity.TOP | Gravity.RIGHT);
- testGravity(Gravity.BOTTOM | Gravity.LEFT);
- testGravity(Gravity.BOTTOM | Gravity.RIGHT);
+ assertEquals(fullscreenDisplay.mDisplayId, mResult.mPreferredDisplayId);
}
- 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 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);
+ }
+
+ // =====================================
+ // Launch Windowing Mode Related Tests
+ // =====================================
+ @Test
+ public void testBoundsInOptionsInfersFreeformOnFreeformDisplay() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ 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_FREEFORM, mResult.mWindowingMode,
+ WINDOWING_MODE_FREEFORM);
+ }
+
+ @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_FULLSCREEN, 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 testNonEmptyLayoutUsesFullscreenWithResizeableActivity() {
+ 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_FULLSCREEN, 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);
}
- /**
- * 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 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 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));
+ }
+
+ @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/am/TaskPersisterTest.java b/services/tests/servicestests/src/com/android/server/am/TaskPersisterTest.java
index 8d54bc236a66..48bfe1d963af 100644
--- a/services/tests/servicestests/src/com/android/server/am/TaskPersisterTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/TaskPersisterTest.java
@@ -16,34 +16,43 @@
package com.android.server.am;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import static androidx.test.InstrumentationRegistry.getTargetContext;
+
import android.content.pm.UserInfo;
-import android.os.Environment;
import android.os.UserHandle;
import android.os.UserManager;
-import android.test.AndroidTestCase;
-import android.util.Log;
+import android.platform.test.annotations.Presubmit;
import android.util.SparseBooleanArray;
-import com.android.server.am.TaskPersister;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
-import java.io.File;
-import java.util.Random;
+import androidx.test.filters.FlakyTest;
/**
- * atest FrameworksServicesTests:TaskPersisterTest
+ * Tests for {@link TaskPersister}.
+ *
+ * Build/Install/Run:
+ * atest FrameworksServicesTests:TaskPersisterTest
*/
-public class TaskPersisterTest extends AndroidTestCase {
+@Presubmit
+@FlakyTest(detail = "Promote to presubmit if stable")
+public class TaskPersisterTest {
private static final String TEST_USER_NAME = "AM-Test-User";
private TaskPersister mTaskPersister;
private int testUserId;
private UserManager mUserManager;
- @Override
+ @Before
public void setUp() throws Exception {
- super.setUp();
- mUserManager = UserManager.get(getContext());
- mTaskPersister = new TaskPersister(getContext().getFilesDir());
+ mUserManager = UserManager.get(getTargetContext());
+ mTaskPersister = new TaskPersister(getTargetContext().getFilesDir());
// In ARC, the maximum number of supported users is one, which is different from the ones of
// most phones (more than 4). This prevents TaskPersisterTest from creating another user for
// test. However, since guest users can be added as much as possible, we create guest user
@@ -51,9 +60,8 @@ public class TaskPersisterTest extends AndroidTestCase {
testUserId = createUser(TEST_USER_NAME, UserInfo.FLAG_GUEST);
}
- @Override
+ @After
public void tearDown() throws Exception {
- super.tearDown();
mTaskPersister.unloadUserDataFromMemory(testUserId);
removeUser(testUserId);
}
@@ -64,6 +72,7 @@ public class TaskPersisterTest extends AndroidTestCase {
return taskId;
}
+ @Test
public void testTaskIdsPersistence() {
SparseBooleanArray taskIdsOnFile = new SparseBooleanArray();
for (int i = 0; i < 100; i++) {
@@ -72,21 +81,18 @@ public class TaskPersisterTest extends AndroidTestCase {
mTaskPersister.writePersistedTaskIdsForUser(taskIdsOnFile, testUserId);
SparseBooleanArray newTaskIdsOnFile = mTaskPersister
.loadPersistedTaskIdsForUser(testUserId);
- assertTrue("TaskIds written differ from TaskIds read back from file",
- taskIdsOnFile.equals(newTaskIdsOnFile));
+ assertEquals("TaskIds written differ from TaskIds read back from file",
+ taskIdsOnFile, newTaskIdsOnFile);
}
private int createUser(String name, int flags) {
UserInfo user = mUserManager.createUser(name, flags);
- if (user == null) {
- fail("Error while creating the test user: " + TEST_USER_NAME);
- }
+ assertNotNull("Error while creating the test user: " + TEST_USER_NAME, user);
return user.id;
}
private void removeUser(int userId) {
- if (!mUserManager.removeUser(userId)) {
- fail("Error while removing the test user: " + TEST_USER_NAME);
- }
+ boolean userRemoved = mUserManager.removeUser(userId);
+ assertTrue("Error while removing the test user: " + TEST_USER_NAME, userRemoved);
}
-} \ No newline at end of file
+}
diff --git a/services/tests/servicestests/src/com/android/server/am/TaskRecordTests.java b/services/tests/servicestests/src/com/android/server/am/TaskRecordTests.java
index fa8a09cc2b85..921cdea2e646 100644
--- a/services/tests/servicestests/src/com/android/server/am/TaskRecordTests.java
+++ b/services/tests/servicestests/src/com/android/server/am/TaskRecordTests.java
@@ -69,13 +69,13 @@ public class TaskRecordTests extends ActivityTestsBase {
private static final String TASK_TAG = "task";
- private ActivityManagerService mService;
+ private ActivityTaskManagerService mService;
@Before
public void setUp() throws Exception {
super.setUp();
TaskRecord.setTaskRecordFactory(null);
- mService = createActivityManagerService();
+ mService = createActivityTaskManagerService();
}
@Test
@@ -150,7 +150,7 @@ public class TaskRecordTests extends ActivityTestsBase {
}
private TaskRecord createTaskRecord(int taskId) {
- return new TaskRecord(mService.mActivityTaskManager, taskId, new Intent(), null, null, null,
+ return new TaskRecord(mService, taskId, new Intent(), null, null, null,
ActivityBuilder.getDefaultComponent(), null, false, false, false, 0, 10050, null,
new ArrayList<>(), 0, false, null, 0, 0, 0, 0, 0, null, 0, false, false, false, 0, 0
);
diff --git a/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java b/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
index cc4f51987523..75e1d0d800db 100644
--- a/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
@@ -16,6 +16,41 @@
package com.android.server.am;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+import static android.testing.DexmakerShareClassLoaderRule.runWithDexmakerShareClassLoader;
+
+import static com.android.server.am.UserController.CONTINUE_USER_SWITCH_MSG;
+import static com.android.server.am.UserController.REPORT_LOCKED_BOOT_COMPLETE_MSG;
+import static com.android.server.am.UserController.REPORT_USER_SWITCH_COMPLETE_MSG;
+import static com.android.server.am.UserController.REPORT_USER_SWITCH_MSG;
+import static com.android.server.am.UserController.SYSTEM_USER_CURRENT_MSG;
+import static com.android.server.am.UserController.SYSTEM_USER_START_MSG;
+import static com.android.server.am.UserController.USER_SWITCH_TIMEOUT_MSG;
+
+import static com.google.android.collect.Lists.newArrayList;
+import static com.google.android.collect.Sets.newHashSet;
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyBoolean;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.eq;
+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;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.validateMockitoUsage;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import static androidx.test.InstrumentationRegistry.getTargetContext;
+
import android.app.IUserSwitchObserver;
import android.content.Context;
import android.content.IIntentReceiver;
@@ -31,80 +66,62 @@ import android.os.Message;
import android.os.RemoteException;
import android.os.UserManagerInternal;
import android.platform.test.annotations.Presubmit;
-import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
import android.util.Log;
import com.android.server.pm.UserManagerService;
import com.android.server.wm.WindowManagerService;
-import org.mockito.Mockito;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Collections;
-import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
-import static android.content.pm.PackageManager.PERMISSION_GRANTED;
-import static android.testing.DexmakerShareClassLoaderRule.runWithDexmakerShareClassLoader;
-import static com.android.server.am.UserController.CONTINUE_USER_SWITCH_MSG;
-import static com.android.server.am.UserController.REPORT_LOCKED_BOOT_COMPLETE_MSG;
-import static com.android.server.am.UserController.REPORT_USER_SWITCH_COMPLETE_MSG;
-import static com.android.server.am.UserController.REPORT_USER_SWITCH_MSG;
-import static com.android.server.am.UserController.SYSTEM_USER_CURRENT_MSG;
-import static com.android.server.am.UserController.SYSTEM_USER_START_MSG;
-import static com.android.server.am.UserController.USER_SWITCH_TIMEOUT_MSG;
-import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyBoolean;
-import static org.mockito.Matchers.anyInt;
-import static org.mockito.Matchers.eq;
-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;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.when;
+import androidx.test.filters.SmallTest;
/**
- * Usage: bit FrameworksServicesTests:com.android.server.am.UserControllerTest
+ * Tests for {@link UserController}.
+ *
+ * Build/Install/Run:
+ * atest FrameworksServicesTests:com.android.server.am.UserControllerTest
*/
@Presubmit
-public class UserControllerTest extends AndroidTestCase {
+@SmallTest
+public class UserControllerTest {
private static final int TEST_USER_ID = 10;
private static final int NONEXIST_USER_ID = 2;
private static String TAG = UserControllerTest.class.getSimpleName();
private UserController mUserController;
private TestInjector mInjector;
- private static final List<String> START_FOREGROUND_USER_ACTIONS =
- Arrays.asList(
- Intent.ACTION_USER_STARTED,
- Intent.ACTION_USER_SWITCHED,
- Intent.ACTION_USER_STARTING);
+ private static final List<String> START_FOREGROUND_USER_ACTIONS = newArrayList(
+ Intent.ACTION_USER_STARTED,
+ Intent.ACTION_USER_SWITCHED,
+ Intent.ACTION_USER_STARTING);
- private static final List<String> START_BACKGROUND_USER_ACTIONS =
- Arrays.asList(
- Intent.ACTION_USER_STARTED,
- Intent.ACTION_LOCKED_BOOT_COMPLETED,
- Intent.ACTION_USER_STARTING);
+ private static final List<String> START_BACKGROUND_USER_ACTIONS = newArrayList(
+ Intent.ACTION_USER_STARTED,
+ Intent.ACTION_LOCKED_BOOT_COMPLETED,
+ Intent.ACTION_USER_STARTING);
- private static final Set<Integer> START_FOREGROUND_USER_MESSAGE_CODES =
- new HashSet<>(Arrays.asList(REPORT_USER_SWITCH_MSG, USER_SWITCH_TIMEOUT_MSG,
- SYSTEM_USER_START_MSG, SYSTEM_USER_CURRENT_MSG));
+ private static final Set<Integer> START_FOREGROUND_USER_MESSAGE_CODES = newHashSet(
+ REPORT_USER_SWITCH_MSG,
+ USER_SWITCH_TIMEOUT_MSG,
+ SYSTEM_USER_START_MSG,
+ SYSTEM_USER_CURRENT_MSG);
- private static final Set<Integer> START_BACKGROUND_USER_MESSAGE_CODES =
- new HashSet<>(Arrays.asList(SYSTEM_USER_START_MSG, REPORT_LOCKED_BOOT_COMPLETE_MSG));
+ private static final Set<Integer> START_BACKGROUND_USER_MESSAGE_CODES = newHashSet(
+ SYSTEM_USER_START_MSG,
+ REPORT_LOCKED_BOOT_COMPLETE_MSG);
- @Override
+ @Before
public void setUp() throws Exception {
- super.setUp();
runWithDexmakerShareClassLoader(() -> {
- mInjector = Mockito.spy(new TestInjector(getContext()));
+ mInjector = spy(new TestInjector(getTargetContext()));
doNothing().when(mInjector).clearAllLockedTasks(anyString());
doNothing().when(mInjector).startHomeActivity(anyInt(), anyString());
doReturn(false).when(mInjector).stackSupervisorSwitchUser(anyInt(), any());
@@ -114,58 +131,54 @@ public class UserControllerTest extends AndroidTestCase {
});
}
- @Override
- protected void tearDown() throws Exception {
- super.tearDown();
+ @After
+ public void tearDown() throws Exception {
mInjector.handlerThread.quit();
- Mockito.validateMockitoUsage();
+ validateMockitoUsage();
}
- @SmallTest
- public void testStartUser_foreground() throws RemoteException {
+ @Test
+ public void testStartUser_foreground() {
mUserController.startUser(TEST_USER_ID, true /* foreground */);
- Mockito.verify(mInjector.getWindowManager()).startFreezingScreen(anyInt(), anyInt());
- Mockito.verify(mInjector.getWindowManager(), never()).stopFreezingScreen();
- Mockito.verify(mInjector.getWindowManager(), times(1)).setSwitchingUser(anyBoolean());
- Mockito.verify(mInjector.getWindowManager()).setSwitchingUser(true);
- Mockito.verify(mInjector).clearAllLockedTasks(anyString());
+ verify(mInjector.getWindowManager()).startFreezingScreen(anyInt(), anyInt());
+ verify(mInjector.getWindowManager(), never()).stopFreezingScreen();
+ verify(mInjector.getWindowManager(), times(1)).setSwitchingUser(anyBoolean());
+ verify(mInjector.getWindowManager()).setSwitchingUser(true);
+ verify(mInjector).clearAllLockedTasks(anyString());
startForegroundUserAssertions();
}
- @SmallTest
- public void testStartUser_background() throws RemoteException {
+ @Test
+ public void testStartUser_background() {
mUserController.startUser(TEST_USER_ID, false /* foreground */);
- Mockito.verify(
- mInjector.getWindowManager(), never()).startFreezingScreen(anyInt(), anyInt());
- Mockito.verify(mInjector.getWindowManager(), never()).setSwitchingUser(anyBoolean());
- Mockito.verify(mInjector, never()).clearAllLockedTasks(anyString());
+ verify(mInjector.getWindowManager(), never()).startFreezingScreen(anyInt(), anyInt());
+ verify(mInjector.getWindowManager(), never()).setSwitchingUser(anyBoolean());
+ verify(mInjector, never()).clearAllLockedTasks(anyString());
startBackgroundUserAssertions();
}
- @SmallTest
- public void testStartUserUIDisabled() throws RemoteException {
+ @Test
+ public void testStartUserUIDisabled() {
mUserController.mUserSwitchUiEnabled = false;
mUserController.startUser(TEST_USER_ID, true /* foreground */);
- Mockito.verify(mInjector.getWindowManager(), never())
- .startFreezingScreen(anyInt(), anyInt());
- Mockito.verify(mInjector.getWindowManager(), never()).stopFreezingScreen();
- Mockito.verify(mInjector.getWindowManager(), never()).setSwitchingUser(anyBoolean());
+ verify(mInjector.getWindowManager(), never()).startFreezingScreen(anyInt(), anyInt());
+ verify(mInjector.getWindowManager(), never()).stopFreezingScreen();
+ verify(mInjector.getWindowManager(), never()).setSwitchingUser(anyBoolean());
startForegroundUserAssertions();
}
private void startUserAssertions(
- List<String> expectedActions, Set<Integer> expectedMessageCodes)
- throws RemoteException {
+ List<String> expectedActions, Set<Integer> expectedMessageCodes) {
assertEquals(expectedActions, getActions(mInjector.sentIntents));
Set<Integer> actualCodes = mInjector.handler.getMessageCodes();
assertEquals("Unexpected message sent", expectedMessageCodes, actualCodes);
}
- private void startBackgroundUserAssertions() throws RemoteException {
+ private void startBackgroundUserAssertions() {
startUserAssertions(START_BACKGROUND_USER_ACTIONS, START_BACKGROUND_USER_MESSAGE_CODES);
}
- private void startForegroundUserAssertions() throws RemoteException {
+ private void startForegroundUserAssertions() {
startUserAssertions(START_FOREGROUND_USER_ACTIONS, START_FOREGROUND_USER_MESSAGE_CODES);
Message reportMsg = mInjector.handler.getMessageForCode(REPORT_USER_SWITCH_MSG);
assertNotNull(reportMsg);
@@ -177,15 +190,15 @@ public class UserControllerTest extends AndroidTestCase {
assertEquals("Unexpected new user id", TEST_USER_ID, reportMsg.arg2);
}
- @SmallTest
- public void testFailedStartUserInForeground() throws RemoteException {
+ @Test
+ public void testFailedStartUserInForeground() {
mUserController.mUserSwitchUiEnabled = false;
mUserController.startUserInForeground(NONEXIST_USER_ID);
- Mockito.verify(mInjector.getWindowManager(), times(1)).setSwitchingUser(anyBoolean());
- Mockito.verify(mInjector.getWindowManager()).setSwitchingUser(false);
+ verify(mInjector.getWindowManager(), times(1)).setSwitchingUser(anyBoolean());
+ verify(mInjector.getWindowManager()).setSwitchingUser(false);
}
- @SmallTest
+ @Test
public void testDispatchUserSwitch() throws RemoteException {
// Prepare mock observer and register it
IUserSwitchObserver observer = mock(IUserSwitchObserver.class);
@@ -206,7 +219,7 @@ public class UserControllerTest extends AndroidTestCase {
// Call dispatchUserSwitch and verify that observer was called only once
mInjector.handler.clearAllRecordedMessages();
mUserController.dispatchUserSwitch(userState, oldUserId, newUserId);
- Mockito.verify(observer, times(1)).onUserSwitching(eq(TEST_USER_ID), any());
+ verify(observer, times(1)).onUserSwitching(eq(TEST_USER_ID), any());
Set<Integer> expectedCodes = Collections.singleton(CONTINUE_USER_SWITCH_MSG);
Set<Integer> actualCodes = mInjector.handler.getMessageCodes();
assertEquals("Unexpected message sent", expectedCodes, actualCodes);
@@ -220,7 +233,7 @@ public class UserControllerTest extends AndroidTestCase {
assertEquals("Unexpected new user id", TEST_USER_ID, conMsg.arg2);
}
- @SmallTest
+ @Test
public void testDispatchUserSwitchBadReceiver() throws RemoteException {
// Prepare mock observer which doesn't notify the callback and register it
IUserSwitchObserver observer = mock(IUserSwitchObserver.class);
@@ -236,14 +249,14 @@ public class UserControllerTest extends AndroidTestCase {
// Call dispatchUserSwitch and verify that observer was called only once
mInjector.handler.clearAllRecordedMessages();
mUserController.dispatchUserSwitch(userState, oldUserId, newUserId);
- Mockito.verify(observer, times(1)).onUserSwitching(eq(TEST_USER_ID), any());
+ verify(observer, times(1)).onUserSwitching(eq(TEST_USER_ID), any());
// Verify that CONTINUE_USER_SWITCH_MSG is not sent (triggers timeout)
Set<Integer> actualCodes = mInjector.handler.getMessageCodes();
- assertTrue("No messages should be sent", actualCodes.isEmpty());
+ assertWithMessage("No messages should be sent").that(actualCodes).isEmpty();
}
- @SmallTest
- public void testContinueUserSwitch() throws RemoteException {
+ @Test
+ public void testContinueUserSwitch() {
// Start user -- this will update state of mUserController
mUserController.startUser(TEST_USER_ID, true);
Message reportMsg = mInjector.handler.getMessageForCode(REPORT_USER_SWITCH_MSG);
@@ -254,12 +267,12 @@ public class UserControllerTest extends AndroidTestCase {
mInjector.handler.clearAllRecordedMessages();
// Verify that continueUserSwitch worked as expected
mUserController.continueUserSwitch(userState, oldUserId, newUserId);
- Mockito.verify(mInjector.getWindowManager(), times(1)).stopFreezingScreen();
+ verify(mInjector.getWindowManager(), times(1)).stopFreezingScreen();
continueUserSwitchAssertions();
}
- @SmallTest
- public void testContinueUserSwitchUIDisabled() throws RemoteException {
+ @Test
+ public void testContinueUserSwitchUIDisabled() {
mUserController.mUserSwitchUiEnabled = false;
// Start user -- this will update state of mUserController
mUserController.startUser(TEST_USER_ID, true);
@@ -271,11 +284,11 @@ public class UserControllerTest extends AndroidTestCase {
mInjector.handler.clearAllRecordedMessages();
// Verify that continueUserSwitch worked as expected
mUserController.continueUserSwitch(userState, oldUserId, newUserId);
- Mockito.verify(mInjector.getWindowManager(), never()).stopFreezingScreen();
+ verify(mInjector.getWindowManager(), never()).stopFreezingScreen();
continueUserSwitchAssertions();
}
- private void continueUserSwitchAssertions() throws RemoteException {
+ private void continueUserSwitchAssertions() {
Set<Integer> expectedCodes = Collections.singleton(REPORT_USER_SWITCH_COMPLETE_MSG);
Set<Integer> actualCodes = mInjector.handler.getMessageCodes();
assertEquals("Unexpected message sent", expectedCodes, actualCodes);
@@ -284,7 +297,7 @@ public class UserControllerTest extends AndroidTestCase {
assertEquals("Unexpected userId", TEST_USER_ID, msg.arg1);
}
- @SmallTest
+ @Test
public void testDispatchUserSwitchComplete() throws RemoteException {
// Prepare mock observer and register it
IUserSwitchObserver observer = mock(IUserSwitchObserver.class);
@@ -298,12 +311,12 @@ public class UserControllerTest extends AndroidTestCase {
mInjector.handler.clearAllRecordedMessages();
// Mockito can't reset only interactions, so just verify that this hasn't been
// called with 'false' until after dispatchUserSwitchComplete.
- Mockito.verify(mInjector.getWindowManager(), never()).setSwitchingUser(false);
+ verify(mInjector.getWindowManager(), never()).setSwitchingUser(false);
// Call dispatchUserSwitchComplete
mUserController.dispatchUserSwitchComplete(newUserId);
- Mockito.verify(observer, times(1)).onUserSwitchComplete(anyInt());
- Mockito.verify(observer).onUserSwitchComplete(TEST_USER_ID);
- Mockito.verify(mInjector.getWindowManager(), times(1)).setSwitchingUser(false);
+ verify(observer, times(1)).onUserSwitchComplete(anyInt());
+ verify(observer).onUserSwitchComplete(TEST_USER_ID);
+ verify(mInjector.getWindowManager(), times(1)).setSwitchingUser(false);
}
private void setUpUser(int userId, int flags) {
@@ -320,7 +333,7 @@ public class UserControllerTest extends AndroidTestCase {
}
// Should be public to allow mocking
- public static class TestInjector extends UserController.Injector {
+ private static class TestInjector extends UserController.Injector {
TestHandler handler;
TestHandler uiHandler;
HandlerThread handlerThread;
@@ -438,4 +451,4 @@ public class UserControllerTest extends AndroidTestCase {
return super.sendMessageAtTime(msg, uptimeMillis);
}
}
-} \ No newline at end of file
+}
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/DisplayContentTests.java b/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
index 3dcdd23acf1a..cb8ca7e4bfc6 100644
--- a/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
@@ -39,6 +39,7 @@ import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.doNothing;
@@ -288,34 +289,25 @@ public class DisplayContentTests extends WindowTestsBase {
final WindowTestUtils.TestAppWindowToken token =
WindowTestUtils.createTestAppWindowToken(dc0);
task0.addChild(token, 0);
- dc0.mTapDetector = new TaskTapPointerEventListener(sWm, dc0);
- sWm.registerPointerEventListener(dc0.mTapDetector);
+ dc0.configureDisplayPolicy();
+ assertNotNull(dc0.mTapDetector);
+
final TaskStack stack1 = createTaskStackOnDisplay(dc1);
final Task task1 = createTaskInStack(stack1, 0 /* userId */);
final WindowTestUtils.TestAppWindowToken token1 =
WindowTestUtils.createTestAppWindowToken(dc0);
task1.addChild(token1, 0);
- dc1.mTapDetector = new TaskTapPointerEventListener(sWm, dc0);
- sWm.registerPointerEventListener(dc1.mTapDetector);
-
- // tap on primary display (by sending ACTION_DOWN followed by ACTION_UP)
- DisplayMetrics dm0 = dc0.getDisplayMetrics();
- dc0.mTapDetector.onPointerEvent(
- createTapEvent(dm0.widthPixels / 2, dm0.heightPixels / 2, true));
- dc0.mTapDetector.onPointerEvent(
- createTapEvent(dm0.widthPixels / 2, dm0.heightPixels / 2, false));
+ dc1.configureDisplayPolicy();
+ assertNotNull(dc1.mTapDetector);
+ // tap on primary display.
+ tapOnDisplay(dc0);
// Check focus is on primary display.
assertEquals(sWm.mRoot.getTopFocusedDisplayContent().mCurrentFocus,
dc0.findFocusedWindow());
- // Tap on secondary display
- DisplayMetrics dm1 = dc1.getDisplayMetrics();
- dc1.mTapDetector.onPointerEvent(
- createTapEvent(dm1.widthPixels / 2, dm1.heightPixels / 2, true));
- dc1.mTapDetector.onPointerEvent(
- createTapEvent(dm1.widthPixels / 2, dm1.heightPixels / 2, false));
-
+ // Tap on secondary display.
+ tapOnDisplay(dc1);
// Check focus is on secondary.
assertEquals(sWm.mRoot.getTopFocusedDisplayContent().mCurrentFocus,
dc1.findFocusedWindow());
@@ -626,17 +618,32 @@ public class DisplayContentTests extends WindowTestsBase {
return result;
}
- private MotionEvent createTapEvent(float x, float y, boolean isDownEvent) {
+ private void tapOnDisplay(final DisplayContent dc) {
+ final DisplayMetrics dm = dc.getDisplayMetrics();
+ final float x = dm.widthPixels / 2;
+ final float y = dm.heightPixels / 2;
final long downTime = SystemClock.uptimeMillis();
final long eventTime = SystemClock.uptimeMillis() + 100;
- final int metaState = 0;
+ // sending ACTION_DOWN
+ final MotionEvent downEvent = MotionEvent.obtain(
+ downTime,
+ downTime,
+ MotionEvent.ACTION_DOWN,
+ x,
+ y,
+ 0 /*metaState*/);
+ downEvent.setDisplayId(dc.getDisplayId());
+ dc.mTapDetector.onPointerEvent(downEvent);
- return MotionEvent.obtain(
+ // sending ACTION_UP
+ final MotionEvent upEvent = MotionEvent.obtain(
downTime,
eventTime,
- isDownEvent ? MotionEvent.ACTION_DOWN : MotionEvent.ACTION_UP,
+ MotionEvent.ACTION_UP,
x,
y,
- metaState);
+ 0 /*metaState*/);
+ upEvent.setDisplayId(dc.getDisplayId());
+ dc.mTapDetector.onPointerEvent(upEvent);
}
}
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/TaskPositioningControllerTests.java b/services/tests/servicestests/src/com/android/server/wm/TaskPositioningControllerTests.java
index ced084717494..f8e740390291 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TaskPositioningControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TaskPositioningControllerTests.java
@@ -30,6 +30,7 @@ import static org.mockito.Mockito.when;
import android.platform.test.annotations.Presubmit;
import android.view.InputChannel;
+import androidx.test.filters.FlakyTest;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
@@ -43,6 +44,7 @@ import org.junit.runner.RunWith;
* atest com.android.server.wm.TaskPositioningControllerTests
*/
@SmallTest
+@FlakyTest(bugId = 117924387)
@RunWith(AndroidJUnit4.class)
@Presubmit
public class TaskPositioningControllerTests extends WindowTestsBase {
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/WindowManagerServiceRule.java b/services/tests/servicestests/src/com/android/server/wm/WindowManagerServiceRule.java
index 54fd7db9b537..389eba52d88d 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowManagerServiceRule.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowManagerServiceRule.java
@@ -34,8 +34,8 @@ import android.hardware.display.DisplayManagerInternal;
import android.os.PowerManagerInternal;
import android.os.PowerSaveState;
import android.view.InputChannel;
-
-import androidx.test.InstrumentationRegistry;
+import android.view.SurfaceControl;
+import android.view.SurfaceControl.Transaction;
import com.android.server.LocalServices;
import com.android.server.input.InputManagerService;
@@ -46,6 +46,12 @@ import org.junit.runner.Description;
import org.junit.runners.model.Statement;
import org.mockito.invocation.InvocationOnMock;
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.List;
+
+import androidx.test.InstrumentationRegistry;
+
/**
* A test rule that sets up a fresh WindowManagerService instance before each test and makes sure
* to properly tear it down after.
@@ -61,6 +67,12 @@ public class WindowManagerServiceRule implements TestRule {
private WindowManagerService mService;
private TestWindowManagerPolicy mPolicy;
+ // Record all {@link SurfaceControl.Transaction} created while testing and releases native
+ // resources when test finishes.
+ private final List<WeakReference<Transaction>> mSurfaceTransactions = new ArrayList<>();
+ // Record all {@link SurfaceControl} created while testing and releases native resources when
+ // test finishes.
+ private final List<WeakReference<SurfaceControl>> mSurfaceControls = new ArrayList<>();
@Override
public Statement apply(Statement base, Description description) {
@@ -108,12 +120,25 @@ public class WindowManagerServiceRule implements TestRule {
// InputChannel is final and can't be mocked.
InputChannel[] input = InputChannel.openInputChannelPair(TAG_WM);
if (input != null && input.length > 1) {
- doReturn(input[1]).when(ims).monitorInput(anyString());
+ doReturn(input[1]).when(ims).monitorInput(anyString(), anyInt());
}
mService = WindowManagerService.main(context, ims, false,
false, mPolicy = new TestWindowManagerPolicy(
WindowManagerServiceRule.this::getWindowManagerService));
+ mService.mTransactionFactory = () -> {
+ final SurfaceControl.Transaction transaction = new SurfaceControl.Transaction();
+ mSurfaceTransactions.add(new WeakReference<>(transaction));
+ return transaction;
+ };
+ mService.mSurfaceBuilderFactory = session -> new SurfaceControl.Builder(session) {
+ @Override
+ public SurfaceControl build() {
+ final SurfaceControl control = super.build();
+ mSurfaceControls.add(new WeakReference<>(control));
+ return control;
+ }
+ };
mService.onInitReady();
@@ -135,6 +160,8 @@ public class WindowManagerServiceRule implements TestRule {
private void tearDown() {
waitUntilWindowManagerHandlersIdle();
+ destroyAllSurfaceTransactions();
+ destroyAllSurfaceControls();
removeServices();
mService = null;
mPolicy = null;
@@ -158,4 +185,24 @@ public class WindowManagerServiceRule implements TestRule {
SurfaceAnimationThread.getHandler().runWithScissors(() -> { }, 0);
}
}
+
+ private void destroyAllSurfaceTransactions() {
+ for (final WeakReference<Transaction> reference : mSurfaceTransactions) {
+ final Transaction transaction = reference.get();
+ if (transaction != null) {
+ reference.clear();
+ transaction.close();
+ }
+ }
+ }
+
+ private void destroyAllSurfaceControls() {
+ for (final WeakReference<SurfaceControl> reference : mSurfaceControls) {
+ final SurfaceControl control = reference.get();
+ if (control != null) {
+ reference.clear();
+ control.destroy();
+ }
+ }
+ }
}
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..3a8c4ae73493 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;
@@ -99,23 +98,26 @@ public class ZOrderingTests extends WindowTestsBase {
super(s);
}
+ @Override
public SurfaceControl.Builder setParent(SurfaceControl sc) {
mPendingParent = sc;
return super.setParent(sc);
}
+
+ @Override
public SurfaceControl build() {
SurfaceControl sc = super.build();
mParentFor.put(sc, mPendingParent);
mPendingParent = null;
return sc;
}
- };
+ }
- class HierarchyRecordingBuilderFactory implements SurfaceBuilderFactory {
+ private class HierarchyRecordingBuilderFactory implements SurfaceBuilderFactory {
public SurfaceControl.Builder make(SurfaceSession s) {
return new HierarchyRecorder(s);
}
- };
+ }
private LayerRecordingTransaction mTransaction;
@@ -132,11 +134,12 @@ public class ZOrderingTests extends WindowTestsBase {
@After
public void after() {
mTransaction.close();
+ mParentFor.keySet().forEach(SurfaceControl::destroy);
mParentFor.clear();
}
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 +156,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 +171,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 +188,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 +205,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 +224,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 +250,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 +273,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 +300,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 +314,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 +344,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 +361,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 +378,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/usb/java/com/android/server/usb/UsbSerialReader.java b/services/usb/java/com/android/server/usb/UsbSerialReader.java
index 5bf94afd7683..32fc796e7e05 100644
--- a/services/usb/java/com/android/server/usb/UsbSerialReader.java
+++ b/services/usb/java/com/android/server/usb/UsbSerialReader.java
@@ -75,14 +75,21 @@ class UsbSerialReader extends IUsbSerialReader.Stub {
if (uid != Process.SYSTEM_UID) {
enforcePackageBelongsToUid(uid, packageName);
- PackageInfo pkg;
+ int packageTargetSdkVersion;
+ long token = Binder.clearCallingIdentity();
try {
- pkg = mContext.getPackageManager().getPackageInfo(packageName, 0);
- } catch (PackageManager.NameNotFoundException e) {
- throw new RemoteException("package " + packageName + " cannot be found");
+ PackageInfo pkg;
+ try {
+ pkg = mContext.getPackageManager().getPackageInfo(packageName, 0);
+ } catch (PackageManager.NameNotFoundException e) {
+ throw new RemoteException("package " + packageName + " cannot be found");
+ }
+ packageTargetSdkVersion = pkg.applicationInfo.targetSdkVersion;
+ } finally {
+ Binder.restoreCallingIdentity(token);
}
- if (pkg.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.Q) {
+ if (packageTargetSdkVersion >= Build.VERSION_CODES.Q) {
if (mContext.checkPermission(android.Manifest.permission.MANAGE_USB, pid, uid)
== PackageManager.PERMISSION_DENIED) {
UsbUserSettingsManager settings = mSettingsManager.getSettingsForUser(
diff --git a/startop/iorap/TEST_MAPPING b/startop/iorap/TEST_MAPPING
new file mode 100644
index 000000000000..8c9d4dfb0894
--- /dev/null
+++ b/startop/iorap/TEST_MAPPING
@@ -0,0 +1,12 @@
+{
+ "presubmit": [
+ {
+ "name": "libiorap-java-tests"
+ }
+ ],
+ "imports": [
+ {
+ "path": "system/iorap"
+ }
+ ]
+}
diff --git a/startop/iorap/tests/AndroidTest.xml b/startop/iorap/tests/AndroidTest.xml
new file mode 100644
index 000000000000..f83a16ec0916
--- /dev/null
+++ b/startop/iorap/tests/AndroidTest.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<configuration description="Runs libiorap-java-tests.">
+ <option name="test-suite-tag" value="apct" />
+ <option name="test-suite-tag" value="apct-instrumentation" />
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true" />
+ <option name="test-file-name" value="libiorap-java-tests.apk" />
+ </target_preparer>
+
+ <!--
+ Our IIorapIntegrationTest.kt requires setlinux to be disabled:
+ it connects to the iorapd binder service but this requires selinux permissions:
+
+ avc: denied { find } for service=iorapd pid=2738 uid=10050
+ scontext=u:r:platform_app:s0:c512,c768 tcontext=u:object_r:iorapd_service:s0
+ tclass=service_manager permissive=0
+ -->
+ <target_preparer class="com.android.tradefed.targetprep.DisableSELinuxTargetPreparer">
+ </target_preparer>
+
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+ <option name="package" value="com.google.android.startop.iorap.tests" />
+ <option name="runner" value="android.support.test.runner.AndroidJUnitRunner" />
+ </test>
+</configuration>
+
diff --git a/startop/iorap/tests/src/com/google/android/startop/iorap/IIorapIntegrationTest.kt b/startop/iorap/tests/src/com/google/android/startop/iorap/IIorapIntegrationTest.kt
index 4ba44a93f2a8..16dcbe20f46a 100644
--- a/startop/iorap/tests/src/com/google/android/startop/iorap/IIorapIntegrationTest.kt
+++ b/startop/iorap/tests/src/com/google/android/startop/iorap/IIorapIntegrationTest.kt
@@ -77,17 +77,21 @@ class IIorapIntegrationTest {
inOrder.verifyNoMoreInteractions()
} finally {
- iorapService.setTaskListener(null)
+ // iorapService.setTaskListener(null)
+ // FIXME: null is broken, C++ side sees a non-null object.
}
}
@Test
fun testOnPackageEvent() {
+ /*
testAnyMethod { requestId : RequestId ->
iorapService.onPackageEvent(requestId,
PackageEvent.createReplaced(
Uri.parse("https://www.google.com"), "com.fake.package"))
}
+ */
+ // FIXME: Broken for some reason. C++ side never sees this call.
}
@Test
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 c65a99b7a441..de2368624a4c 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -410,7 +410,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/telephony/java/android/provider/Telephony.java b/telephony/java/android/provider/Telephony.java
index 2e8ea5cc2268..0aa51955bf05 100644
--- a/telephony/java/android/provider/Telephony.java
+++ b/telephony/java/android/provider/Telephony.java
@@ -18,6 +18,7 @@ package android.provider;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
+import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.annotation.UnsupportedAppUsage;
import android.app.job.JobService;
@@ -2940,100 +2941,131 @@ public final class Telephony {
public static final String SUBSCRIPTION_ID = "sub_id";
/**
- * The profile_id to which the APN saved in modem
+ * The profile_id to which the APN saved in modem.
* <p>Type: INTEGER</p>
*@hide
*/
public static final String PROFILE_ID = "profile_id";
/**
- * Is the apn setting to be set in modem
- * <P>Type: INTEGER (boolean)</P>
+ * If set to {@code true}, then the APN setting will persist to the modem.
+ * <p>Type: INTEGER (boolean)</p>
*@hide
*/
+ @SystemApi
public static final String MODEM_COGNITIVE = "modem_cognitive";
/**
- * The max connections of this apn
+ * The max connections of this APN.
* <p>Type: INTEGER</p>
*@hide
*/
+ @SystemApi
public static final String MAX_CONNS = "max_conns";
/**
- * The wait time for retry of the apn
+ * The wait time for retry of the APN.
* <p>Type: INTEGER</p>
*@hide
*/
+ @SystemApi
public static final String WAIT_TIME = "wait_time";
/**
- * The time to limit max connection for the apn
+ * The time to limit max connection for the APN.
* <p>Type: INTEGER</p>
*@hide
*/
+ @SystemApi
public static final String MAX_CONNS_TIME = "max_conns_time";
/**
- * The MTU size of the mobile interface to which the APN connected
+ * The MTU(Maxinum transmit unit) size of the mobile interface to which the APN connected.
* <p>Type: INTEGER </p>
* @hide
*/
+ @SystemApi
public static final String MTU = "mtu";
/**
- * Is this APN added/edited/deleted by a user or carrier?
+ * APN edit status. APN could be added/edited/deleted by a user or carrier.
* <p>Type: INTEGER </p>
* @hide
*/
+ @SystemApi
public static final String EDITED = "edited";
/**
- * Is this APN visible to the user?
- * <p>Type: INTEGER (boolean) </p>
+ * {@code true} if this APN visible to the user, {@code false} otherwise.
+ * <p>Type: INTEGER (boolean)</p>
* @hide
*/
+ @SystemApi
public static final String USER_VISIBLE = "user_visible";
/**
- * Is the user allowed to edit this APN?
- * <p>Type: INTEGER (boolean) </p>
+ * {@code true} if the user allowed to edit this APN, {@code false} otherwise.
+ * <p>Type: INTEGER (boolean)</p>
* @hide
*/
+ @SystemApi
public static final String USER_EDITABLE = "user_editable";
/**
- * Following are possible values for the EDITED field
+ * {@link #EDITED APN edit status} indicates that this APN has not been edited or fails to
+ * edit.
+ * <p>Type: INTEGER </p>
* @hide
*/
+ @SystemApi
public static final int UNEDITED = 0;
+
/**
- * @hide
+ * {@link #EDITED APN edit status} indicates that this APN has been edited by users.
+ * <p>Type: INTEGER </p>
+ * @hide
*/
+ @SystemApi
public static final int USER_EDITED = 1;
+
/**
- * @hide
+ * {@link #EDITED APN edit status} indicates that this APN has been deleted by users.
+ * <p>Type: INTEGER </p>
+ * @hide
*/
+ @SystemApi
public static final int USER_DELETED = 2;
+
/**
- * DELETED_BUT_PRESENT is an intermediate value used to indicate that an entry deleted
- * by the user is still present in the new APN database and therefore must remain tagged
- * as user deleted rather than completely removed from the database
+ * {@link #EDITED APN edit status} is an intermediate value used to indicate that an entry
+ * deleted by the user is still present in the new APN database and therefore must remain
+ * tagged as user deleted rather than completely removed from the database.
* @hide
*/
public static final int USER_DELETED_BUT_PRESENT_IN_XML = 3;
+
/**
- * @hide
+ * {@link #EDITED APN edit status} indicates that this APN has been edited by carriers.
+ * <p>Type: INTEGER </p>
+ * @hide
*/
+ @SystemApi
public static final int CARRIER_EDITED = 4;
+
/**
- * CARRIER_DELETED values are currently not used as there is no usecase. If they are used,
+ * {@link #EDITED APN edit status} indicates that this APN has been deleted by carriers.
+ * CARRIER_DELETED values are currently not used as there is no use case. If they are used,
* delete() will have to change accordingly. Currently it is hardcoded to USER_DELETED.
+ * <p>Type: INTEGER </p>
* @hide
*/
public static final int CARRIER_DELETED = 5;
+
/**
- * @hide
+ * {@link #EDITED APN edit status} is an intermediate value used to indicate that an entry
+ * deleted by the carrier is still present in the new APN database and therefore must remain
+ * tagged as user deleted rather than completely removed from the database.
+ * @hide
*/
public static final int CARRIER_DELETED_BUT_PRESENT_IN_XML = 6;
@@ -3062,16 +3094,20 @@ public final class Telephony {
* The APN set id. When the user manually selects an APN or the framework sets an APN as
* preferred, all APNs with the same set id as the selected APN should be prioritized over
* APNs in other sets.
+ * <p>Type: INTEGER</p>
* @hide
*/
+ @SystemApi
public static final String APN_SET_ID = "apn_set_id";
/**
- * Possible value for the APN_SET_ID field. By default APNs will not belong to a set. If the
- * user manually selects an APN with no set set, there is no need to prioritize any specific
- * APN set ids.
+ * Possible value for the{@link #APN_SET_ID} field. By default APNs will not belong to a
+ * set. If the user manually selects an APN with no set set, there is no need to prioritize
+ * any specific APN set ids.
+ * <p>Type: INTEGER</p>
* @hide
*/
+ @SystemApi
public static final int NO_SET_SET = 0;
}
@@ -3340,7 +3376,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;
}
@@ -3576,6 +3611,18 @@ public final class Telephony {
public static final String CARRIER_ID = "carrier_id";
/**
+ * A unique mno carrier id. mno carrier shares the same {@link All#MCCMNC} as carrier id
+ * and can be solely identified by {@link All#MCCMNC} only. If there is no such mno
+ * carrier, then mno carrier id equals to {@link #CARRIER_ID carrier id}.
+ *
+ * <p>mno carrier id can be used as fallback id. When the exact carrier id configurations
+ * are not found, usually fall back to its mno carrier id.
+ * <P>Type: INTEGER </P>
+ * @hide
+ */
+ public static final String MNO_CARRIER_ID = "mno_carrier_id";
+
+ /**
* Contains mappings between matching rules with carrier id for all carriers.
* @hide
*/
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 0b66bca4423d..38426f3f61b8 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -1217,6 +1217,20 @@ public class CarrierConfigManager {
"always_show_data_rat_icon_bool";
/**
+ * Boolean indicating if default data account should show LTE or 4G icon
+ * @hide
+ */
+ public static final String KEY_SHOW_4G_FOR_LTE_DATA_ICON_BOOL =
+ "show_4g_for_lte_data_icon_bool";
+
+ /**
+ * Boolean indicating if lte+ icon should be shown if available
+ * @hide
+ */
+ public static final String KEY_HIDE_LTE_PLUS_DATA_ICON_BOOL =
+ "hide_lte_plus_data_icon_bool";
+
+ /**
* Boolean to decide whether to show precise call failed cause to user
* @hide
*/
@@ -1993,6 +2007,31 @@ public class CarrierConfigManager {
public static final String KEY_RTT_SUPPORTED_BOOL = "rtt_supported_bool";
/**
+ * Indicates if the carrier supports auto-upgrading a call to RTT when receiving a call from a
+ * RTT-supported device.
+ * @hide
+ */
+ public static final String KEY_RTT_AUTO_UPGRADE_BOOL = "rtt_auto_upgrade_bool";
+
+ /**
+ * Indicates if the carrier supports RTT during a video call.
+ * @hide
+ */
+ public static final String KEY_RTT_SUPPORTED_FOR_VT_BOOL = "rtt_supported_for_vt_bool";
+
+ /**
+ * Indicates if the carrier supports upgrading a voice call to an RTT call during the call.
+ * @hide
+ */
+ public static final String KEY_RTT_UPGRADE_SUPPORTED_BOOL = "rtt_upgrade_supported_bool";
+
+ /**
+ * Indicates if the carrier supports downgrading a RTT call to a voice call during the call.
+ * @hide
+ */
+ public static final String KEY_RTT_DOWNGRADE_SUPPORTED_BOOL = "rtt_downgrade_supported_bool";
+
+ /**
* The flag to disable the popup dialog which warns the user of data charges.
* @hide
*/
@@ -2536,6 +2575,8 @@ public class CarrierConfigManager {
sDefaults.putBoolean(KEY_SHOW_PRECISE_FAILED_CAUSE_BOOL, false);
sDefaults.putBoolean(KEY_SPN_DISPLAY_RULE_USE_ROAMING_FROM_SERVICE_STATE_BOOL, false);
sDefaults.putBoolean(KEY_ALWAYS_SHOW_DATA_RAT_ICON_BOOL, false);
+ sDefaults.putBoolean(KEY_SHOW_4G_FOR_LTE_DATA_ICON_BOOL, true);
+ sDefaults.putBoolean(KEY_HIDE_LTE_PLUS_DATA_ICON_BOOL, false);
sDefaults.putBoolean(KEY_CARRIER_CONFIG_APPLIED_BOOL, false);
sDefaults.putBoolean(KEY_CHECK_PRICING_WITH_CARRIER_FOR_DATA_ROAMING_BOOL, false);
sDefaults.putIntArray(KEY_LTE_RSRP_THRESHOLDS_INT_ARRAY,
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/PhoneStateListener.java b/telephony/java/android/telephony/PhoneStateListener.java
index 3ea018af97cf..c83d6aa3897d 100644
--- a/telephony/java/android/telephony/PhoneStateListener.java
+++ b/telephony/java/android/telephony/PhoneStateListener.java
@@ -17,6 +17,7 @@
package android.telephony;
import android.annotation.NonNull;
+import android.annotation.SystemApi;
import android.annotation.UnsupportedAppUsage;
import android.os.Bundle;
import android.os.Handler;
@@ -291,6 +292,15 @@ public class PhoneStateListener {
*/
public static final int LISTEN_PREFERRED_DATA_SUBID_CHANGE = 0x00400000;
+ /**
+ * Listen for changes to the radio power state.
+ *
+ * @see #onRadioPowerStateChanged
+ * @hide
+ */
+ @SystemApi
+ public static final int LISTEN_RADIO_POWER_STATE_CHANGED = 0x00800000;
+
/*
* Subscription used to listen to the phone state changes
* @hide
@@ -420,6 +430,9 @@ public class PhoneStateListener {
case LISTEN_PREFERRED_DATA_SUBID_CHANGE:
PhoneStateListener.this.onPreferredDataSubIdChanged((int) msg.obj);
break;
+ case LISTEN_RADIO_POWER_STATE_CHANGED:
+ PhoneStateListener.this.onRadioPowerStateChanged((int) msg.obj);
+ break;
}
}
};
@@ -672,6 +685,17 @@ public class PhoneStateListener {
}
/**
+ * Callback invoked when modem radio power state changes. Requires
+ * the READ_PRIVILEGED_PHONE_STATE permission.
+ * @param state the modem radio power state
+ * @hide
+ */
+ @SystemApi
+ public void onRadioPowerStateChanged(@TelephonyManager.RadioPowerState int state) {
+ // default implementation empty
+ }
+
+ /**
* Callback invoked when telephony has received notice from a carrier
* app that a network action that could result in connectivity loss
* has been requested by an app using
@@ -807,6 +831,10 @@ public class PhoneStateListener {
send(LISTEN_PREFERRED_DATA_SUBID_CHANGE, 0, 0, subId);
}
+ public void onRadioPowerStateChanged(@TelephonyManager.RadioPowerState int state) {
+ send(LISTEN_RADIO_POWER_STATE_CHANGED, 0, 0, state);
+ }
+
}
/**
diff --git a/telephony/java/android/telephony/RcsManager.java b/telephony/java/android/telephony/RcsManager.java
new file mode 100644
index 000000000000..00ce03a1f668
--- /dev/null
+++ b/telephony/java/android/telephony/RcsManager.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony;
+
+import android.os.RemoteException;
+import android.os.ServiceManager;
+
+import com.android.internal.telephony.IRcs;
+
+/**
+ * RcsManager is the application interface to RcsProvider and provides access methods to
+ * RCS related database tables.
+ * @hide - TODO make this public
+ */
+public class RcsManager {
+ private static final String TAG = "RcsManager";
+ private static final boolean VDBG = false;
+
+ /**
+ * Delete the RcsThread identified by the given threadId.
+ * @param threadId threadId of the thread to be deleted.
+ */
+ public void deleteThread(int threadId) {
+ if (VDBG) logd("deleteThread: threadId: " + threadId);
+ try {
+ IRcs iRcs = IRcs.Stub.asInterface(ServiceManager.getService("ircs"));
+ if (iRcs != null) {
+ iRcs.deleteThread(threadId);
+ }
+ } catch (RemoteException re) {
+
+ }
+ }
+
+ private static void logd(String msg) {
+ Rlog.d(TAG, msg);
+ }
+}
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index 7469186a5d51..e0ec2c50ab5b 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -20,6 +20,7 @@ import android.annotation.IntDef;
import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.annotation.UnsupportedAppUsage;
+import android.content.Intent;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
@@ -57,7 +58,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 +66,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 +201,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,8 +240,6 @@ 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;
@@ -259,8 +269,6 @@ public class ServiceState implements Parcelable {
@UnsupportedAppUsage
private int mCdmaEriIconMode;
- private boolean mIsDataRoamingFromRegistration;
-
@UnsupportedAppUsage
private boolean mIsUsingCarrierAggregation;
@@ -332,8 +340,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 +357,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 +372,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 +389,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 +400,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 +417,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);
@@ -535,17 +534,21 @@ public class ServiceState implements Parcelable {
*/
@UnsupportedAppUsage
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;
}
/**
@@ -555,19 +558,7 @@ public class ServiceState implements Parcelable {
*/
@UnsupportedAppUsage
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 +567,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 +581,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 +760,6 @@ public class ServiceState implements Parcelable {
return Objects.hash(
mVoiceRegState,
mDataRegState,
- mVoiceRoamingType,
- mDataRoamingType,
mChannelNumber,
mCellBandwidths,
mVoiceOperatorAlphaLong,
@@ -780,7 +779,6 @@ public class ServiceState implements Parcelable {
mCdmaEriIconIndex,
mCdmaEriIconMode,
mIsEmergencyOnly,
- mIsDataRoamingFromRegistration,
mIsUsingCarrierAggregation,
mLteEarfcnRsrpBoost,
mNetworkRegistrationStates);
@@ -794,8 +792,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 +809,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 +928,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 +944,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 +954,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 +973,6 @@ public class ServiceState implements Parcelable {
mCdmaEriIconIndex = -1;
mCdmaEriIconMode = -1;
mIsEmergencyOnly = false;
- mIsDataRoamingFromRegistration = false;
mIsUsingCarrierAggregation = false;
mLteEarfcnRsrpBoost = 0;
mNetworkRegistrationStates = new ArrayList<>();
@@ -1029,32 +1018,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 +1173,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 +1187,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 +1209,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 76e6afddcf12..3b4016437e9a 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,7 @@ public class SubscriptionManager {
/** @hide */
public static final int INVALID_PHONE_INDEX = -1;
- /** An invalid slot identifier */
- /** @hide */
+ /** Indicates invalid sim slot. This can be returned by {@link #getSlotIndex(int)}. */
public static final int INVALID_SIM_SLOT_INDEX = -1;
/** Indicates the default subscription ID in Telephony. */
@@ -116,6 +117,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>
@@ -1262,15 +1309,15 @@ public class SubscriptionManager {
/**
* Get slotIndex associated with the subscription.
- * @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
+ *
+ * @param subscriptionId the unique SubscriptionInfo index in database
+ * @return slotIndex as a positive integer or {@link #INVALID_SIM_SLOT_INDEX} if the supplied
+ * subscriptionId doesn't have an associated slot index.
*/
- @UnsupportedAppUsage
- public static int getSlotIndex(int subId) {
- if (!isValidSubscriptionId(subId)) {
+ public static int getSlotIndex(int subscriptionId) {
+ if (!isValidSubscriptionId(subscriptionId)) {
if (DBG) {
- logd("[getSlotIndex]- fail");
+ logd("[getSlotIndex]- supplied subscriptionId is invalid.");
}
}
@@ -1279,7 +1326,7 @@ public class SubscriptionManager {
try {
ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
if (iSub != null) {
- result = iSub.getSlotIndex(subId);
+ result = iSub.getSlotIndex(subscriptionId);
}
} catch (RemoteException ex) {
// ignore it
@@ -1603,7 +1650,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.
@@ -2185,9 +2232,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 1fd30a2cd285..0da42bf7af64 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -17,6 +17,7 @@
package android.telephony;
import static android.content.Context.TELECOM_SERVICE;
+
import static com.android.internal.util.Preconditions.checkNotNull;
import android.annotation.IntDef;
@@ -59,7 +60,9 @@ import android.telephony.ims.aidl.IImsConfig;
import android.telephony.ims.aidl.IImsMmTelFeature;
import android.telephony.ims.aidl.IImsRcsFeature;
import android.telephony.ims.aidl.IImsRegistration;
+import android.telephony.ims.feature.MmTelFeature;
import android.telephony.ims.stub.ImsRegistrationImplBase;
+import android.text.TextUtils;
import android.util.Log;
import com.android.ims.internal.IImsServiceFeatureCallback;
@@ -704,7 +707,7 @@ public class TelephonyManager {
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
@Deprecated
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
+ @UnsupportedAppUsage
public static final String ACTION_PRECISE_DATA_CONNECTION_STATE_CHANGED =
"android.intent.action.PRECISE_DATA_CONNECTION_STATE_CHANGED";
@@ -1161,6 +1164,16 @@ public class TelephonyManager {
public static final String EXTRA_CARRIER_ID = "android.telephony.extra.CARRIER_ID";
/**
+ * An int extra used with {@link #ACTION_SUBSCRIPTION_CARRIER_IDENTITY_CHANGED} which indicates
+ * the updated mno carrier id of the current subscription.
+ * <p>Will be {@link TelephonyManager#UNKNOWN_CARRIER_ID} if the subscription is unavailable or
+ * the carrier cannot be identified.
+ *
+ *@hide
+ */
+ public static final String EXTRA_MNO_CARRIER_ID = "android.telephony.extra.MNO_CARRIER_ID";
+
+ /**
* An string extra used with {@link #ACTION_SUBSCRIPTION_CARRIER_IDENTITY_CHANGED} which
* indicates the updated carrier name of the current subscription.
* {@see TelephonyManager#getSimCarrierIdName()}
@@ -1219,6 +1232,38 @@ public class TelephonyManager {
*/
public static final String EXTRA_RECOVERY_ACTION = "recoveryAction";
+ /**
+ * Broadcast intent action indicating that the telephony provider DB got lost.
+ *
+ * <p>
+ * The {@link #EXTRA_IS_CORRUPTED} extra indicates whether the database is lost
+ * due to corruption or not
+ *
+ * <p class="note">
+ * Requires the MODIFY_PHONE_STATE permission.
+ *
+ * <p class="note">
+ * This is a protected intent that can only be sent by the system.
+ *
+ * @see #EXTRA_IS_CORRUPTED
+ *
+ * @hide
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+ public static final String ACTION_MMSSMS_DATABASE_LOST =
+ "android.intent.action.MMSSMS_DATABASE_LOST";
+
+ /**
+ * A boolean extra used with {@link #ACTION_MMSSMS_DATABASE_LOST} to indicate
+ * whether the database is lost due to corruption or not.
+ *
+ * @see #ACTION_MMSSMS_DATABASE_LOST
+ *
+ * @hide
+ */
+ public static final String EXTRA_IS_CORRUPTED = "isCorrupted";
+
//
//
// Device Info
@@ -1266,11 +1311,11 @@ 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: 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.
+ * <p>Requires Permission: READ_PRIVILEGED_PHONE_STATE, or for the calling package to be the
+ * device or profile owner and have the READ_PHONE_STATE permission. 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.
@@ -1295,11 +1340,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: 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.
+ * <p>Requires Permission: READ_PRIVILEGED_PHONE_STATE, or for the calling package to be the
+ * device or profile owner and have the READ_PHONE_STATE permission. 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
*
@@ -1328,11 +1373,11 @@ public class TelephonyManager {
* Returns the IMEI (International Mobile Equipment Identity). Return null if IMEI is not
* available.
*
- * <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.
+ * <p>Requires Permission: READ_PRIVILEGED_PHONE_STATE, or for the calling package to be the
+ * device or profile owner and have the READ_PHONE_STATE permission. 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 // No support for device / profile owner.
@RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
@@ -1344,11 +1389,11 @@ public class TelephonyManager {
* Returns the IMEI (International Mobile Equipment Identity). Return null if IMEI is not
* available.
*
- * <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.
+ * <p>Requires Permission: READ_PRIVILEGED_PHONE_STATE, or for the calling package to be the
+ * device or profile owner and have the READ_PHONE_STATE permission. 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
*/
@@ -1397,11 +1442,11 @@ public class TelephonyManager {
/**
* Returns the MEID (Mobile Equipment Identifier). Return null if MEID is not available.
*
- * <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.
+ * <p>Requires Permission: READ_PRIVILEGED_PHONE_STATE, or for the calling package to be the
+ * device or profile owner and have the READ_PHONE_STATE permission. 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 // No support for device / profile owner.
@RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
@@ -1412,11 +1457,11 @@ public class TelephonyManager {
/**
* Returns the MEID (Mobile Equipment Identifier). Return null if MEID is not available.
*
- * <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.
+ * <p>Requires Permission: READ_PRIVILEGED_PHONE_STATE, or for the calling package to be the
+ * device or profile owner and have the READ_PHONE_STATE permission. 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
*/
@@ -1620,8 +1665,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) {
@@ -1724,7 +1768,7 @@ public class TelephonyManager {
}
/** {@hide} */
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
+ @UnsupportedAppUsage
private int getPhoneTypeFromProperty(int phoneId) {
String type = getTelephonyProperty(phoneId,
TelephonyProperties.CURRENT_ACTIVE_PHONE, null);
@@ -2449,39 +2493,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
@@ -2908,11 +2959,11 @@ public class TelephonyManager {
* 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.
+ * profile owner and have the READ_PHONE_STATE permission, 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_PRIVILEGED_PHONE_STATE)
@@ -2925,11 +2976,11 @@ public class TelephonyManager {
* 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.
+ * profile owner and have the READ_PHONE_STATE permission, 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
@@ -3071,11 +3122,11 @@ public class TelephonyManager {
* 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.
+ * profile owner and have the READ_PHONE_STATE permission, 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_PRIVILEGED_PHONE_STATE)
@@ -3089,11 +3140,11 @@ public class TelephonyManager {
* 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.
+ * profile owner and have the READ_PHONE_STATE permission, 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
@@ -5401,7 +5452,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 */
@@ -6868,6 +6919,60 @@ public class TelephonyManager {
}
/** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = {"RADIO_POWER_"},
+ value = {RADIO_POWER_OFF,
+ RADIO_POWER_ON,
+ RADIO_POWER_UNAVAILABLE,
+ })
+ public @interface RadioPowerState {}
+
+ /**
+ * Radio explicitly powered off (e.g, airplane mode).
+ * @hide
+ */
+ @SystemApi
+ public static final int RADIO_POWER_OFF = 0;
+
+ /**
+ * Radio power is on.
+ * @hide
+ */
+ @SystemApi
+ public static final int RADIO_POWER_ON = 1;
+
+ /**
+ * Radio power unavailable (eg, modem resetting or not booted).
+ * @hide
+ */
+ @SystemApi
+ public static final int RADIO_POWER_UNAVAILABLE = 2;
+
+ /**
+ * @return current modem radio state.
+ *
+ * <p>Requires permission: {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE} or
+ * {@link android.Manifest.permission#READ_PHONE_STATE} or that the calling
+ * app has carrier privileges (see {@link #hasCarrierPrivileges}).
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(anyOf = {android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
+ android.Manifest.permission.READ_PHONE_STATE})
+ public @RadioPowerState int getRadioPowerState() {
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony != null) {
+ return telephony.getRadioPowerState(getSlotIndex(), mContext.getOpPackageName());
+ }
+ } catch (RemoteException ex) {
+ // This could happen if binder process crashes.
+ }
+ return RADIO_POWER_UNAVAILABLE;
+ }
+
+ /** @hide */
@SystemApi
@SuppressLint("Doclava125")
public void updateServiceLocation() {
@@ -7338,7 +7443,9 @@ public class TelephonyManager {
@UnsupportedAppUsage
public boolean isVolteAvailable() {
try {
- return getITelephony().isVolteAvailable(getSubId());
+ return getITelephony().isAvailable(getSubId(),
+ MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE,
+ ImsRegistrationImplBase.REGISTRATION_TECH_LTE, getOpPackageName());
} catch (RemoteException | NullPointerException ex) {
return false;
}
@@ -8277,20 +8384,31 @@ public class TelephonyManager {
}
/**
- * Action set from carrier signalling broadcast receivers to enable/disable metered apns
- * Permissions android.Manifest.permission.MODIFY_PHONE_STATE is required
- * @param subId the subscription ID that this action applies to.
- * @param enabled control enable or disable metered apns.
+ * Used to enable or disable carrier data by the system based on carrier signalling or
+ * carrier privileged apps. Different from {@link #setDataEnabled(boolean)} which is linked to
+ * user settings, carrier data on/off won't affect user settings but will bypass the
+ * settings and turns off data internally if set to {@code false}.
+ *
+ * <p>If this object has been created with {@link #createForSubscriptionId}, applies to the
+ * given subId. Otherwise, applies to {@link SubscriptionManager#getDefaultDataSubscriptionId()}
+ *
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}.
+ *
+ * @param enabled control enable or disable carrier data.
* @hide
*/
- public void carrierActionSetMeteredApnsEnabled(int subId, boolean enabled) {
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+ public void setCarrierDataEnabled(boolean enabled) {
try {
ITelephony service = getITelephony();
if (service != null) {
- service.carrierActionSetMeteredApnsEnabled(subId, enabled);
+ service.carrierActionSetMeteredApnsEnabled(
+ getSubId(SubscriptionManager.getDefaultDataSubscriptionId()), enabled);
}
} catch (RemoteException e) {
- Log.e(TAG, "Error calling ITelephony#carrierActionSetMeteredApnsEnabled", e);
+ Log.e(TAG, "Error calling ITelephony#setCarrierDataEnabled", e);
}
}
diff --git a/telephony/java/android/telephony/data/ApnSetting.java b/telephony/java/android/telephony/data/ApnSetting.java
index 8379f8cefda0..aabefe324d82 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. */
@@ -257,7 +257,7 @@ public class ApnSetting implements Parcelable {
private final int mProfileId;
- private final boolean mModemCognitive;
+ private final boolean mPersistent;
private final int mMaxConns;
private final int mWaitTime;
private final int mMaxConnsTime;
@@ -290,13 +290,13 @@ public class ApnSetting implements Parcelable {
}
/**
- * Returns if the APN setting is to be set in modem.
+ * Returns if the APN setting is persistent on the modem.
*
* @return is the APN setting to be set in modem
* @hide
*/
- public boolean getModemCognitive() {
- return mModemCognitive;
+ public boolean isPersistent() {
+ return mPersistent;
}
/**
@@ -616,7 +616,7 @@ public class ApnSetting implements Parcelable {
this.mCarrierEnabled = builder.mCarrierEnabled;
this.mNetworkTypeBitmask = builder.mNetworkTypeBitmask;
this.mProfileId = builder.mProfileId;
- this.mModemCognitive = builder.mModemCognitive;
+ this.mPersistent = builder.mModemCognitive;
this.mMaxConns = builder.mMaxConns;
this.mWaitTime = builder.mWaitTime;
this.mMaxConnsTime = builder.mMaxConnsTime;
@@ -740,7 +740,7 @@ public class ApnSetting implements Parcelable {
apn.mProxyAddress, apn.mProxyPort, apn.mMmsc, apn.mMmsProxyAddress,
apn.mMmsProxyPort, apn.mUser, apn.mPassword, apn.mAuthType, apn.mApnTypeBitmask,
apn.mProtocol, apn.mRoamingProtocol, apn.mCarrierEnabled, apn.mNetworkTypeBitmask,
- apn.mProfileId, apn.mModemCognitive, apn.mMaxConns, apn.mWaitTime,
+ apn.mProfileId, apn.mPersistent, apn.mMaxConns, apn.mWaitTime,
apn.mMaxConnsTime, apn.mMtu, apn.mMvnoType, apn.mMvnoMatchData, apn.mApnSetId);
}
@@ -947,7 +947,7 @@ public class ApnSetting implements Parcelable {
sb.append(", ").append(PROTOCOL_INT_MAP.get(mRoamingProtocol));
sb.append(", ").append(mCarrierEnabled);
sb.append(", ").append(mProfileId);
- sb.append(", ").append(mModemCognitive);
+ sb.append(", ").append(mPersistent);
sb.append(", ").append(mMaxConns);
sb.append(", ").append(mWaitTime);
sb.append(", ").append(mMaxConnsTime);
@@ -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;
@@ -1029,7 +1029,7 @@ public class ApnSetting implements Parcelable {
&& Objects.equals(mMmsc, other.mMmsc)
&& Objects.equals(mMmsProxyAddress, other.mMmsProxyAddress)
&& Objects.equals(mMmsProxyPort, other.mMmsProxyPort)
- && Objects.equals(mProxyPort,other.mProxyPort)
+ && Objects.equals(mProxyPort, other.mProxyPort)
&& Objects.equals(mUser, other.mUser)
&& Objects.equals(mPassword, other.mPassword)
&& Objects.equals(mAuthType, other.mAuthType)
@@ -1038,7 +1038,7 @@ public class ApnSetting implements Parcelable {
&& Objects.equals(mRoamingProtocol, other.mRoamingProtocol)
&& Objects.equals(mCarrierEnabled, other.mCarrierEnabled)
&& Objects.equals(mProfileId, other.mProfileId)
- && Objects.equals(mModemCognitive, other.mModemCognitive)
+ && Objects.equals(mPersistent, other.mPersistent)
&& Objects.equals(mMaxConns, other.mMaxConns)
&& Objects.equals(mWaitTime, other.mWaitTime)
&& Objects.equals(mMaxConnsTime, other.mMaxConnsTime)
@@ -1080,11 +1080,11 @@ public class ApnSetting implements Parcelable {
&& Objects.equals(mPassword, other.mPassword)
&& Objects.equals(mAuthType, other.mAuthType)
&& Objects.equals(mApnTypeBitmask, other.mApnTypeBitmask)
- && (isDataRoaming || Objects.equals(mProtocol,other.mProtocol))
+ && (isDataRoaming || Objects.equals(mProtocol, other.mProtocol))
&& (!isDataRoaming || Objects.equals(mRoamingProtocol, other.mRoamingProtocol))
&& Objects.equals(mCarrierEnabled, other.mCarrierEnabled)
&& Objects.equals(mProfileId, other.mProfileId)
- && Objects.equals(mModemCognitive, other.mModemCognitive)
+ && Objects.equals(mPersistent, other.mPersistent)
&& Objects.equals(mMaxConns, other.mMaxConns)
&& Objects.equals(mWaitTime, other.mWaitTime)
&& Objects.equals(mMaxConnsTime, other.mMaxConnsTime)
diff --git a/telephony/java/android/telephony/data/DataProfile.java b/telephony/java/android/telephony/data/DataProfile.java
index e8597b221391..da4822cc1d14 100644
--- a/telephony/java/android/telephony/data/DataProfile.java
+++ b/telephony/java/android/telephony/data/DataProfile.java
@@ -68,17 +68,15 @@ public final class DataProfile implements Parcelable {
private final int mMtu;
- private final String mMvnoType;
+ private final boolean mPersistent;
- private final String mMvnoMatchData;
+ private final boolean mPreferred;
- private final boolean mModemCognitive;
-
- public DataProfile(int profileId, String apn, String protocol, int authType,
- String userName, String password, int type, int maxConnsTime, int maxConns,
- int waitTime, boolean enabled, int supportedApnTypesBitmap, String roamingProtocol,
- int bearerBitmap, int mtu, String mvnoType, String mvnoMatchData,
- boolean modemCognitive) {
+ /** @hide */
+ public DataProfile(int profileId, String apn, String protocol, int authType, String userName,
+ String password, int type, int maxConnsTime, int maxConns, int waitTime,
+ boolean enabled, int supportedApnTypesBitmap, String roamingProtocol,
+ int bearerBitmap, int mtu, boolean persistent, boolean preferred) {
this.mProfileId = profileId;
this.mApn = apn;
@@ -100,11 +98,11 @@ public final class DataProfile implements Parcelable {
this.mRoamingProtocol = roamingProtocol;
this.mBearerBitmap = bearerBitmap;
this.mMtu = mtu;
- this.mMvnoType = mvnoType;
- this.mMvnoMatchData = mvnoMatchData;
- this.mModemCognitive = modemCognitive;
+ this.mPersistent = persistent;
+ this.mPreferred = preferred;
}
+ /** @hide */
public DataProfile(Parcel source) {
mProfileId = source.readInt();
mApn = source.readString();
@@ -121,9 +119,8 @@ public final class DataProfile implements Parcelable {
mRoamingProtocol = source.readString();
mBearerBitmap = source.readInt();
mMtu = source.readInt();
- mMvnoType = source.readString();
- mMvnoMatchData = source.readString();
- mModemCognitive = source.readBoolean();
+ mPersistent = source.readBoolean();
+ mPreferred = source.readBoolean();
}
/**
@@ -207,23 +204,17 @@ public final class DataProfile implements Parcelable {
public int getMtu() { return mMtu; }
/**
- * @return The MVNO type: possible values are "imsi", "gid", "spn".
- */
- public String getMvnoType() { return mMvnoType; }
-
- /**
- * @return The MVNO match data. For example,
- * SPN: A MOBILE, BEN NL, ...
- * IMSI: 302720x94, 2060188, ...
- * GID: 4E, 33, ...
+ * @return {@code true} if modem must persist this data profile.
*/
- public String getMvnoMatchData() { return mMvnoMatchData; }
+ public boolean isPersistent() { return mPersistent; }
/**
- * @return True if the data profile was sent to the modem through setDataProfile earlier.
+ * @return {@code true} if this data profile was used to bring up the last default
+ * (i.e internet) data connection successfully.
*/
- public boolean isModemCognitive() { return mModemCognitive; }
+ public boolean isPreferred() { return mPreferred; }
+ /** @hide */
@Override
public int describeContents() {
return 0;
@@ -233,11 +224,11 @@ public final class DataProfile implements Parcelable {
public String toString() {
return "DataProfile=" + mProfileId + "/" + mProtocol + "/" + mAuthType
+ "/" + (Build.IS_USER ? "***/***/***" :
- (mApn + "/" + mUserName + "/" + mPassword))
- + "/" + mType + "/" + mMaxConnsTime
- + "/" + mMaxConns + "/" + mWaitTime + "/" + mEnabled + "/"
- + mSupportedApnTypesBitmap + "/" + mRoamingProtocol + "/" + mBearerBitmap + "/"
- + mMtu + "/" + mMvnoType + "/" + mMvnoMatchData + "/" + mModemCognitive;
+ (mApn + "/" + mUserName + "/" + mPassword)) + "/" + mType + "/"
+ + mMaxConnsTime + "/" + mMaxConns + "/"
+ + mWaitTime + "/" + mEnabled + "/" + mSupportedApnTypesBitmap + "/"
+ + mRoamingProtocol + "/" + mBearerBitmap + "/" + mMtu + "/" + mPersistent + "/"
+ + mPreferred;
}
@Override
@@ -246,6 +237,7 @@ public final class DataProfile implements Parcelable {
return (o == this || toString().equals(o.toString()));
}
+ /** @hide */
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(mProfileId);
@@ -263,11 +255,11 @@ public final class DataProfile implements Parcelable {
dest.writeString(mRoamingProtocol);
dest.writeInt(mBearerBitmap);
dest.writeInt(mMtu);
- dest.writeString(mMvnoType);
- dest.writeString(mMvnoMatchData);
- dest.writeBoolean(mModemCognitive);
+ dest.writeBoolean(mPersistent);
+ dest.writeBoolean(mPreferred);
}
+ /** @hide */
public static final Parcelable.Creator<DataProfile> CREATOR =
new Parcelable.Creator<DataProfile>() {
@Override
diff --git a/telephony/java/android/telephony/emergency/EmergencyNumber.java b/telephony/java/android/telephony/emergency/EmergencyNumber.java
index d6a08543b9cd..bdba8c860db0 100644
--- a/telephony/java/android/telephony/emergency/EmergencyNumber.java
+++ b/telephony/java/android/telephony/emergency/EmergencyNumber.java
@@ -33,7 +33,7 @@ import java.util.Set;
* A parcelable class that wraps and retrieves the information of number, service category(s) and
* country code for a specific emergency number.
*/
-public final class EmergencyNumber implements Parcelable {
+public final class EmergencyNumber implements Parcelable, Comparable<EmergencyNumber> {
private static final String LOG_TAG = "EmergencyNumber";
@@ -235,20 +235,22 @@ public final class EmergencyNumber implements Parcelable {
}
/**
- * Returns the bitmask of emergency service categories {@link EmergencyServiceCategories} of
- * the emergency number.
+ * Returns the bitmask of emergency service categories of the emergency number.
*
- * @return bitmask of the emergency service categories {@link EmergencyServiceCategories}
+ * @return bitmask of the emergency service categories
*/
public @EmergencyServiceCategories int getEmergencyServiceCategoryBitmask() {
return mEmergencyServiceCategoryBitmask;
}
/**
- * Returns the emergency service categories {@link EmergencyServiceCategories} of the emergency
- * number.
+ * Returns the emergency service categories of the emergency number.
*
- * @return a list of the emergency service categories {@link EmergencyServiceCategories}
+ * Note: if the emergency number is in {@link #EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED}, only
+ * {@link #EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED} is returned and it means the number is in
+ * all categories.
+ *
+ * @return a list of the emergency service categories
*/
public List<Integer> getEmergencyServiceCategories() {
List<Integer> categories = new ArrayList<>();
@@ -276,34 +278,37 @@ public final class EmergencyNumber implements Parcelable {
}
/**
- * Checks if the emergency number is in the specified emergency service category(s)
- * {@link EmergencyServiceCategories}.
+ * Checks if the emergency number is in the supplied emergency service category(s).
*
- * @return {@code true} if the emergency number is in the specified emergency service
- * category(s) {@link EmergencyServiceCategories}; {@code false} otherwise.
+ * @param categories - the supplied emergency service categories
*
- * @param categories - emergency service categories {@link EmergencyServiceCategories}
+ * @return {@code true} if the emergency number is in the specified emergency service
+ * category(s) or if its emergency service category is
+ * {@link #EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED}; {@code false} otherwise.
*/
public boolean isInEmergencyServiceCategories(@EmergencyServiceCategories int categories) {
if (categories == EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED) {
return serviceUnspecified();
}
+ if (serviceUnspecified()) {
+ return true;
+ }
return (mEmergencyServiceCategoryBitmask & categories) == categories;
}
/**
- * Returns the bitmask of the sources {@link EmergencyNumberSources} of the emergency number.
+ * Returns the bitmask of the sources of the emergency number.
*
- * @return bitmask of the emergency number sources {@link EmergencyNumberSources}
+ * @return bitmask of the emergency number sources
*/
public @EmergencyNumberSources int getEmergencyNumberSourceBitmask() {
return mEmergencyNumberSourceBitmask;
}
/**
- * Returns a list of {@link EmergencyNumberSources} of the emergency number.
+ * Returns a list of sources of the emergency number.
*
- * @return a list of {@link EmergencyNumberSources}
+ * @return a list of emergency number sources
*/
public List<Integer> getEmergencyNumberSources() {
List<Integer> sources = new ArrayList<>();
@@ -316,13 +321,12 @@ public final class EmergencyNumber implements Parcelable {
}
/**
- * Checks if the emergency number is from the specified emergency number source(s)
- * {@link EmergencyNumberSources}.
+ * Checks if the emergency number is from the specified emergency number source(s).
*
* @return {@code true} if the emergency number is from the specified emergency number
- * source(s) {@link EmergencyNumberSources}; {@code false} otherwise.
+ * source(s); {@code false} otherwise.
*
- * @param sources - {@link EmergencyNumberSources}
+ * @param sources - the supplied emergency number sources
*/
public boolean isFromSources(@EmergencyNumberSources int sources) {
return (mEmergencyNumberSourceBitmask & sources) == sources;
@@ -359,6 +363,62 @@ public final class EmergencyNumber implements Parcelable {
return (o == this || toString().equals(o.toString()));
}
+ /**
+ * Calculate the score for display priority.
+ *
+ * A higher display priority score means the emergency number has a higher display priority.
+ * The score is higher if the source is defined for a higher display priority.
+ *
+ * The priority of sources are defined as follows:
+ * EMERGENCY_NUMBER_SOURCE_NETWORK_SIGNALING >
+ * EMERGENCY_NUMBER_SOURCE_SIM >
+ * EMERGENCY_NUMBER_SOURCE_DEFAULT >
+ * EMERGENCY_NUMBER_SOURCE_MODEM_CONFIG
+ *
+ */
+ private int getDisplayPriorityScore() {
+ int score = 0;
+ if (this.isFromSources(EMERGENCY_NUMBER_SOURCE_NETWORK_SIGNALING)) {
+ score += 1 << 4;
+ }
+ if (this.isFromSources(EMERGENCY_NUMBER_SOURCE_SIM)) {
+ score += 1 << 3;
+ }
+ // TODO add a score if the number comes from Google's emergency number database
+ if (this.isFromSources(EMERGENCY_NUMBER_SOURCE_DEFAULT)) {
+ score += 1 << 1;
+ }
+ if (this.isFromSources(EMERGENCY_NUMBER_SOURCE_MODEM_CONFIG)) {
+ score += 1 << 0;
+ }
+ return score;
+ }
+
+ /**
+ * Compare the display priority for this emergency number and the supplied emergency number.
+ *
+ * @param emergencyNumber the supplied emergency number
+ * @return a negative value if the supplied emergency number has a lower display priority;
+ * a positive value if the supplied emergency number has a higher display priority;
+ * 0 if both have equal display priority.
+ */
+ @Override
+ public int compareTo(EmergencyNumber emergencyNumber) {
+ if (this.getDisplayPriorityScore()
+ > emergencyNumber.getDisplayPriorityScore()) {
+ return -1;
+ } else if (this.getDisplayPriorityScore()
+ < emergencyNumber.getDisplayPriorityScore()) {
+ return 1;
+ } else {
+ /**
+ * TODO if both numbers have the same display priority score, the number matches the
+ * Google's emergency number database has a higher display priority.
+ */
+ return 0;
+ }
+ }
+
public static final Parcelable.Creator<EmergencyNumber> CREATOR =
new Parcelable.Creator<EmergencyNumber>() {
@Override
diff --git a/telephony/java/android/telephony/ims/ImsExternalCallState.java b/telephony/java/android/telephony/ims/ImsExternalCallState.java
index 8d18ae8ed281..f2d0cbf13cc9 100644
--- a/telephony/java/android/telephony/ims/ImsExternalCallState.java
+++ b/telephony/java/android/telephony/ims/ImsExternalCallState.java
@@ -16,22 +16,19 @@
package android.telephony.ims;
+import android.annotation.IntDef;
import android.annotation.SystemApi;
-import android.annotation.UnsupportedAppUsage;
import android.net.Uri;
import android.os.Parcel;
import android.os.Parcelable;
import android.telecom.Log;
import android.telephony.Rlog;
-/*
- * This file contains all the api's through which
- * information received in Dialog Event Package can be
- * queried
- */
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
/**
- * Parcelable object to handle MultiEndpoint Dialog Information
+ * Parcelable object to handle MultiEndpoint Dialog Event Package Information.
* @hide
*/
@SystemApi
@@ -40,8 +37,39 @@ public final class ImsExternalCallState implements Parcelable {
private static final String TAG = "ImsExternalCallState";
// Dialog States
+ /**
+ * The external call is in the confirmed dialog state.
+ */
public static final int CALL_STATE_CONFIRMED = 1;
+ /**
+ * The external call is in the terminated dialog state.
+ */
public static final int CALL_STATE_TERMINATED = 2;
+
+ /**@hide*/
+ @IntDef(flag = true,
+ value = {
+ CALL_STATE_CONFIRMED,
+ CALL_STATE_TERMINATED
+ },
+ prefix = "CALL_STATE_")
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ExternalCallState {}
+
+ /**@hide*/
+ @IntDef(flag = true,
+ value = {
+ ImsCallProfile.CALL_TYPE_VOICE,
+ ImsCallProfile.CALL_TYPE_VT_TX,
+ ImsCallProfile.CALL_TYPE_VT_RX,
+ ImsCallProfile.CALL_TYPE_VT
+ },
+ prefix = "CALL_TYPE_")
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ExternalCallType {}
+
+
+
// Dialog Id
private int mCallId;
// Number
@@ -58,10 +86,9 @@ public final class ImsExternalCallState implements Parcelable {
public ImsExternalCallState() {
}
- /** @hide */
- @UnsupportedAppUsage
- public ImsExternalCallState(int callId, Uri address, boolean isPullable, int callState,
- int callType, boolean isCallheld) {
+ /**@hide*/
+ public ImsExternalCallState(int callId, Uri address, boolean isPullable,
+ @ExternalCallState int callState, int callType, boolean isCallheld) {
mCallId = callId;
mAddress = address;
mIsPullable = isPullable;
@@ -71,9 +98,10 @@ public final class ImsExternalCallState implements Parcelable {
Rlog.d(TAG, "ImsExternalCallState = " + this);
}
- /** @hide */
+ /**@hide*/
public ImsExternalCallState(int callId, Uri address, Uri localAddress,
- boolean isPullable, int callState, int callType, boolean isCallheld) {
+ boolean isPullable, @ExternalCallState int callState, int callType,
+ boolean isCallheld) {
mCallId = callId;
mAddress = address;
mLocalAddress = localAddress;
@@ -84,6 +112,31 @@ public final class ImsExternalCallState implements Parcelable {
Rlog.d(TAG, "ImsExternalCallState = " + this);
}
+ /**
+ * Create a new ImsExternalCallState instance to contain Multiendpoint Dialog information.
+ * @param callId The unique ID of the call, which will be used to identify this external
+ * connection.
+ * @param address A {@link Uri} containing the remote address of this external connection.
+ * @param localAddress A {@link Uri} containing the local address information.
+ * @param isPullable A flag determining if this external connection can be pulled to the current
+ * device.
+ * @param callState The state of the external call.
+ * @param callType The type of external call.
+ * @param isCallheld A flag determining if the external connection is currently held.
+ */
+ public ImsExternalCallState(String callId, Uri address, Uri localAddress,
+ boolean isPullable, @ExternalCallState int callState, @ExternalCallType int callType,
+ boolean isCallheld) {
+ mCallId = getIdForString(callId);
+ mAddress = address;
+ mLocalAddress = localAddress;
+ mIsPullable = isPullable;
+ mCallState = callState;
+ mCallType = callType;
+ mIsHeld = isCallheld;
+ Rlog.d(TAG, "ImsExternalCallState = " + this);
+ }
+
/** @hide */
public ImsExternalCallState(Parcel in) {
mCallId = in.readInt();
@@ -135,7 +188,9 @@ public final class ImsExternalCallState implements Parcelable {
return mAddress;
}
- /** @hide */
+ /**
+ * @return A {@link Uri} containing the local address from the Multiendpoint Dialog Information.
+ */
public Uri getLocalAddress() {
return mLocalAddress;
}
@@ -144,11 +199,11 @@ public final class ImsExternalCallState implements Parcelable {
return mIsPullable;
}
- public int getCallState() {
+ public @ExternalCallState int getCallState() {
return mCallState;
}
- public int getCallType() {
+ public @ExternalCallType int getCallType() {
return mCallType;
}
@@ -166,4 +221,15 @@ public final class ImsExternalCallState implements Parcelable {
", mCallType = " + mCallType +
", mIsHeld = " + mIsHeld + "}";
}
+
+ private int getIdForString(String idString) {
+ try {
+ return Integer.parseInt(idString);
+ } catch (NumberFormatException e) {
+ // In the case that there are alphanumeric characters, we will create a hash of the
+ // String value as a backup.
+ // TODO: Modify call IDs to use Strings as keys instead of integers in telephony/telecom
+ return idString.hashCode();
+ }
+ }
}
diff --git a/telephony/java/android/telephony/ims/ImsMmTelManager.java b/telephony/java/android/telephony/ims/ImsMmTelManager.java
new file mode 100644
index 000000000000..c9cf473bb482
--- /dev/null
+++ b/telephony/java/android/telephony/ims/ImsMmTelManager.java
@@ -0,0 +1,760 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony.ims;
+
+
+import android.Manifest;
+import android.annotation.CallbackExecutor;
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
+import android.content.Context;
+import android.net.Uri;
+import android.os.Binder;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.telephony.SubscriptionManager;
+import android.telephony.ims.aidl.IImsCapabilityCallback;
+import android.telephony.ims.aidl.IImsRegistrationCallback;
+import android.telephony.ims.feature.ImsFeature;
+import android.telephony.ims.feature.MmTelFeature;
+import android.telephony.ims.stub.ImsRegistrationImplBase;
+
+import com.android.internal.telephony.ITelephony;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.concurrent.Executor;
+
+/**
+ * A manager for the MmTel (Multimedia Telephony) feature of an IMS network, given an associated
+ * subscription.
+ *
+ * Allows a user to query the IMS MmTel feature information for a subscription, register for
+ * registration and MmTel capability status callbacks, as well as query/modify user settings for the
+ * associated subscription.
+ *
+ * @see #createForSubscriptionId(Context, int)
+ * @hide
+ */
+public class ImsMmTelManager {
+
+ private static final String TAG = "ImsMmTelManager";
+
+ /**
+ * @hide
+ */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = "WIFI_MODE_", value = {
+ WIFI_MODE_WIFI_ONLY,
+ WIFI_MODE_CELLULAR_PREFERRED,
+ WIFI_MODE_WIFI_PREFERRED
+ })
+ public @interface WiFiCallingMode {}
+
+ /**
+ * Register for IMS over IWLAN if WiFi signal quality is high enough. Do not hand over to LTE
+ * registration if signal quality degrades.
+ * @hide
+ */
+ @SystemApi
+ public static final int WIFI_MODE_WIFI_ONLY = 0;
+
+ /**
+ * Prefer registering for IMS over LTE if LTE signal quality is high enough.
+ * @hide
+ */
+ @SystemApi
+ public static final int WIFI_MODE_CELLULAR_PREFERRED = 1;
+
+ /**
+ * Prefer registering for IMS over IWLAN if possible if WiFi signal quality is high enough.
+ * @hide
+ */
+ @SystemApi
+ public static final int WIFI_MODE_WIFI_PREFERRED = 2;
+
+ /**
+ * Callback class for receiving Registration callback events.
+ * @see #addImsRegistrationCallback(Executor, RegistrationCallback) (RegistrationCallback)
+ * @see #removeImsRegistrationCallback(RegistrationCallback)
+ */
+ public static class RegistrationCallback {
+
+ private static class RegistrationBinder extends IImsRegistrationCallback.Stub {
+
+ private final RegistrationCallback mLocalCallback;
+ private Executor mExecutor;
+
+ RegistrationBinder(RegistrationCallback localCallback) {
+ mLocalCallback = localCallback;
+ }
+
+ @Override
+ public void onRegistered(int imsRadioTech) {
+ if (mLocalCallback == null) return;
+
+ Binder.withCleanCallingIdentity(() ->
+ mExecutor.execute(() -> mLocalCallback.onRegistered(imsRadioTech)));
+ }
+
+ @Override
+ public void onRegistering(int imsRadioTech) {
+ if (mLocalCallback == null) return;
+
+ Binder.withCleanCallingIdentity(() ->
+ mExecutor.execute(() -> mLocalCallback.onRegistering(imsRadioTech)));
+ }
+
+ @Override
+ public void onDeregistered(ImsReasonInfo info) {
+ if (mLocalCallback == null) return;
+
+ Binder.withCleanCallingIdentity(() ->
+ mExecutor.execute(() -> mLocalCallback.onDeregistered(info)));
+ }
+
+ @Override
+ public void onTechnologyChangeFailed(int imsRadioTech, ImsReasonInfo info) {
+ if (mLocalCallback == null) return;
+
+ Binder.withCleanCallingIdentity(() ->
+ mExecutor.execute(() ->
+ mLocalCallback.onTechnologyChangeFailed(imsRadioTech, info)));
+ }
+
+ @Override
+ public void onSubscriberAssociatedUriChanged(Uri[] uris) {
+ if (mLocalCallback == null) return;
+
+ Binder.withCleanCallingIdentity(() ->
+ mExecutor.execute(() ->
+ mLocalCallback.onSubscriberAssociatedUriChanged(uris)));
+ }
+
+ private void setExecutor(Executor executor) {
+ mExecutor = executor;
+ }
+ }
+
+ private final RegistrationBinder mBinder = new RegistrationBinder(this);
+
+ /**
+ * Notifies the framework when the IMS Provider is registered to the IMS network.
+ *
+ * @param imsRadioTech the radio access technology. Valid values are defined in
+ * {@link ImsRegistrationImplBase.ImsRegistrationTech}.
+ */
+ public void onRegistered(@ImsRegistrationImplBase.ImsRegistrationTech int imsRadioTech) {
+ }
+
+ /**
+ * Notifies the framework when the IMS Provider is trying to register the IMS network.
+ *
+ * @param imsRadioTech the radio access technology. Valid values are defined in
+ * {@link ImsRegistrationImplBase.ImsRegistrationTech}.
+ */
+ public void onRegistering(@ImsRegistrationImplBase.ImsRegistrationTech int imsRadioTech) {
+ }
+
+ /**
+ * Notifies the framework when the IMS Provider is deregistered from the IMS network.
+ *
+ * @param info the {@link ImsReasonInfo} associated with why registration was disconnected.
+ */
+ public void onDeregistered(ImsReasonInfo info) {
+ }
+
+ /**
+ * A failure has occurred when trying to handover registration to another technology type,
+ * defined in {@link ImsRegistrationImplBase.ImsRegistrationTech}
+ *
+ * @param imsRadioTech The {@link ImsRegistrationImplBase.ImsRegistrationTech} type that has
+ * failed
+ * @param info A {@link ImsReasonInfo} that identifies the reason for failure.
+ */
+ public void onTechnologyChangeFailed(
+ @ImsRegistrationImplBase.ImsRegistrationTech int imsRadioTech, ImsReasonInfo info) {
+ }
+
+ /**
+ * Returns a list of subscriber {@link Uri}s associated with this IMS subscription when
+ * it changes. Per RFC3455, an associated URI is a URI that the service provider has
+ * allocated to a user for their own usage. A user's phone number is typically one of the
+ * associated URIs.
+ * @param uris new array of subscriber {@link Uri}s that are associated with this IMS
+ * subscription.
+ * @hide
+ */
+ public void onSubscriberAssociatedUriChanged(Uri[] uris) {
+ }
+
+ /**@hide*/
+ public final IImsRegistrationCallback getBinder() {
+ return mBinder;
+ }
+
+ /**@hide*/
+ //Only exposed as public for compatibility with deprecated ImsManager APIs.
+ public void setExecutor(Executor executor) {
+ mBinder.setExecutor(executor);
+ }
+ }
+
+ /**
+ * Receives IMS capability status updates from the ImsService.
+ *
+ * @see #addMmTelCapabilityCallback(Executor, CapabilityCallback) (CapabilityCallback)
+ * @see #removeMmTelCapabilityCallback(CapabilityCallback)
+ */
+ public static class CapabilityCallback {
+
+ private static class CapabilityBinder extends IImsCapabilityCallback.Stub {
+
+ private final CapabilityCallback mLocalCallback;
+ private Executor mExecutor;
+
+ CapabilityBinder(CapabilityCallback c) {
+ mLocalCallback = c;
+ }
+
+ @Override
+ public void onCapabilitiesStatusChanged(int config) {
+ if (mLocalCallback == null) return;
+
+ Binder.withCleanCallingIdentity(() ->
+ mExecutor.execute(() -> mLocalCallback.onCapabilitiesStatusChanged(
+ new MmTelFeature.MmTelCapabilities(config))));
+ }
+
+ @Override
+ public void onQueryCapabilityConfiguration(int capability, int radioTech,
+ boolean isEnabled) {
+ // This is not used for public interfaces.
+ }
+
+ @Override
+ public void onChangeCapabilityConfigurationError(int capability, int radioTech,
+ @ImsFeature.ImsCapabilityError int reason) {
+ // This is not used for public interfaces
+ }
+
+ private void setExecutor(Executor executor) {
+ mExecutor = executor;
+ }
+ }
+
+ private final CapabilityBinder mBinder = new CapabilityBinder(this);
+
+ /**
+ * The status of the feature's capabilities has changed to either available or unavailable.
+ * If unavailable, the feature is not able to support the unavailable capability at this
+ * time.
+ *
+ * @param capabilities The new availability of the capabilities.
+ */
+ public void onCapabilitiesStatusChanged(
+ MmTelFeature.MmTelCapabilities capabilities) {
+ }
+
+ /**@hide*/
+ public final IImsCapabilityCallback getBinder() {
+ return mBinder;
+ }
+
+ /**@hide*/
+ // Only exposed as public method for compatibility with deprecated ImsManager APIs.
+ // TODO: clean up dependencies and change back to private visibility.
+ public void setExecutor(Executor executor) {
+ mBinder.setExecutor(executor);
+ }
+ }
+
+ private Context mContext;
+ private int mSubId;
+
+ /**
+ * Create an instance of ImsManager for the subscription id specified.
+ *
+ * @param context
+ * @param subId The ID of the subscription that this ImsManager will use.
+ * @see android.telephony.SubscriptionManager#getActiveSubscriptionInfoList()
+ * @throws IllegalArgumentException if the subscription is invalid or
+ * the subscription ID is not an active subscription.
+ */
+ public static ImsMmTelManager createForSubscriptionId(Context context, int subId) {
+ if (!SubscriptionManager.isValidSubscriptionId(subId)
+ || !getSubscriptionManager(context).isActiveSubscriptionId(subId)) {
+ throw new IllegalArgumentException("Invalid subscription ID");
+ }
+
+ return new ImsMmTelManager(context, subId);
+ }
+
+ private ImsMmTelManager(Context context, int subId) {
+ mContext = context;
+ mSubId = subId;
+ }
+
+ /**
+ * Registers a {@link RegistrationCallback} with the system, which will provide registration
+ * updates for the subscription specified in {@link #createForSubscriptionId(Context, int)}. Use
+ * {@link SubscriptionManager.OnSubscriptionsChangedListener} to listen to Subscription changed
+ * events and call {@link #removeImsRegistrationCallback(RegistrationCallback)} to clean up
+ * after a subscription is removed.
+ * @param executor The executor the callback events should be run on.
+ * @param c The {@link RegistrationCallback} to be added.
+ * @see #removeImsRegistrationCallback(RegistrationCallback)
+ */
+ @RequiresPermission(Manifest.permission.READ_PHONE_STATE)
+ public void addImsRegistrationCallback(@CallbackExecutor Executor executor,
+ @NonNull RegistrationCallback c) {
+ if (c == null) {
+ throw new IllegalArgumentException("Must include a non-null RegistrationCallback.");
+ }
+ if (executor == null) {
+ throw new IllegalArgumentException("Must include a non-null Executor.");
+ }
+ c.setExecutor(executor);
+ try {
+ getITelephony().addImsRegistrationCallback(mSubId, c.getBinder(),
+ mContext.getOpPackageName());
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ }
+ }
+
+ /**
+ * Removes an existing {@link RegistrationCallback}. Ensure to call this method when cleaning
+ * up to avoid memory leaks or when the subscription is removed.
+ * @param c The {@link RegistrationCallback} to be removed.
+ * @see SubscriptionManager.OnSubscriptionsChangedListener
+ * @see #addImsRegistrationCallback(Executor, RegistrationCallback)
+ */
+ @RequiresPermission(Manifest.permission.READ_PHONE_STATE)
+ public void removeImsRegistrationCallback(@NonNull RegistrationCallback c) {
+ if (c == null) {
+ throw new IllegalArgumentException("Must include a non-null RegistrationCallback.");
+ }
+ try {
+ getITelephony().removeImsRegistrationCallback(mSubId, c.getBinder(),
+ mContext.getOpPackageName());
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ }
+ }
+
+ /**
+ * Registers a {@link CapabilityCallback} with the system, which will provide MmTel capability
+ * updates for the subscription specified in {@link #createForSubscriptionId(Context, int)}.
+ * Use {@link SubscriptionManager.OnSubscriptionsChangedListener} to listen to
+ * subscription changed events and call
+ * {@link #removeImsRegistrationCallback(RegistrationCallback)} to clean up after a subscription
+ * is removed.
+ * @param executor The executor the callback events should be run on.
+ * @param c The MmTel {@link CapabilityCallback} to be registered.
+ * @see #removeMmTelCapabilityCallback(CapabilityCallback)
+ */
+ @RequiresPermission(Manifest.permission.READ_PHONE_STATE)
+ public void addMmTelCapabilityCallback(@CallbackExecutor Executor executor,
+ @NonNull CapabilityCallback c) {
+ if (c == null) {
+ throw new IllegalArgumentException("Must include a non-null RegistrationCallback.");
+ }
+ if (executor == null) {
+ throw new IllegalArgumentException("Must include a non-null Executor.");
+ }
+ c.setExecutor(executor);
+ try {
+ getITelephony().addMmTelCapabilityCallback(mSubId, c.getBinder(),
+ mContext.getOpPackageName());
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ }
+ }
+
+ /**
+ * Removes an existing MmTel {@link CapabilityCallback}. Be sure to call this when cleaning
+ * up to avoid memory leaks.
+ * @param c The MmTel {@link CapabilityCallback} to be removed.
+ * @see #addMmTelCapabilityCallback(Executor, CapabilityCallback)
+ */
+ @RequiresPermission(Manifest.permission.READ_PHONE_STATE)
+ public void removeMmTelCapabilityCallback(@NonNull CapabilityCallback c) {
+ if (c == null) {
+ throw new IllegalArgumentException("Must include a non-null RegistrationCallback.");
+ }
+ try {
+ getITelephony().removeMmTelCapabilityCallback(mSubId, c.getBinder(),
+ mContext.getOpPackageName());
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ }
+ }
+
+ /**
+ * Query the user's setting for whether or not to use MmTel capabilities over IMS,
+ * such as voice and video, depending on carrier configuration for the current subscription.
+ * @see #setAdvancedCallingSetting(boolean)
+ * @return true if the user’s setting for advanced calling is enabled and false otherwise.
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ public boolean isAdvancedCallingSettingEnabled() {
+ try {
+ return getITelephony().isAdvancedCallingSettingEnabled(mSubId);
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ }
+ }
+
+ /**
+ * Modify the user’s setting for “Advanced Calling” or "Enhanced 4G LTE", which is used to
+ * enable MmTel IMS features, such as voice and video calling, depending on the carrier
+ * configuration for the current subscription. Modifying this value may also trigger an IMS
+ * registration or deregistration, depending on the new value.
+ * @see #isAdvancedCallingEnabled()
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
+ public void setAdvancedCallingSetting(boolean isEnabled) {
+ try {
+ getITelephony().setAdvancedCallingSetting(mSubId, isEnabled);
+ return;
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ }
+ }
+
+ /**
+ * Query the IMS MmTel capability for a given registration technology. This does not
+ * necessarily mean that we are registered and the capability is available, but rather the
+ * subscription is capable of this service over IMS.
+ *
+ * @see android.telephony.CarrierConfigManager#KEY_CARRIER_VOLTE_AVAILABLE_BOOL
+ * @see android.telephony.CarrierConfigManager#KEY_CARRIER_VT_AVAILABLE_BOOL
+ * @see android.telephony.CarrierConfigManager#KEY_CARRIER_IMS_GBA_REQUIRED_BOOL
+ * @see #isAvailable(int, int)
+ *
+ * @param imsRegTech The IMS registration technology, can be one of the following:
+ * {@link ImsRegistrationImplBase#REGISTRATION_TECH_LTE},
+ * {@link ImsRegistrationImplBase#REGISTRATION_TECH_IWLAN}
+ * @param capability The IMS MmTel capability to query, can be one of the following:
+ * {@link MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_VOICE},
+ * {@link MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_VIDEO,
+ * {@link MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_UT},
+ * {@link MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_SMS}
+ * @return {@code true} if the MmTel IMS capability is capable for this subscription, false
+ * otherwise.
+ */
+ @RequiresPermission(Manifest.permission.READ_PHONE_STATE)
+ public boolean isCapable(@MmTelFeature.MmTelCapabilities.MmTelCapability int capability,
+ @ImsRegistrationImplBase.ImsRegistrationTech int imsRegTech) {
+ try {
+ return getITelephony().isCapable(mSubId, capability, imsRegTech,
+ mContext.getOpPackageName());
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ }
+ }
+
+ /**
+ * Query the availability of an IMS MmTel capability for a given registration technology. If
+ * a capability is available, IMS is registered and the service is currently available over IMS.
+ *
+ * @see #isCapable(int, int)
+ *
+ * @param imsRegTech The IMS registration technology, can be one of the following:
+ * {@link ImsRegistrationImplBase#REGISTRATION_TECH_LTE},
+ * {@link ImsRegistrationImplBase#REGISTRATION_TECH_IWLAN}
+ * @param capability The IMS MmTel capability to query, can be one of the following:
+ * {@link MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_VOICE},
+ * {@link MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_VIDEO,
+ * {@link MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_UT},
+ * {@link MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_SMS}
+ * @return {@code true} if the MmTel IMS capability is available for this subscription, false
+ * otherwise.
+ */
+ @RequiresPermission(Manifest.permission.READ_PHONE_STATE)
+ public boolean isAvailable(@MmTelFeature.MmTelCapabilities.MmTelCapability int capability,
+ @ImsRegistrationImplBase.ImsRegistrationTech int imsRegTech) {
+ try {
+ return getITelephony().isAvailable(mSubId, capability, imsRegTech,
+ mContext.getOpPackageName());
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ }
+ }
+
+ /**
+ * The user's setting for whether or not they have enabled the "Video Calling" setting.
+ * @return true if the user’s “Video Calling” setting is currently enabled.
+ * @see #setVtSetting(boolean)
+ */
+ @SystemApi
+ @RequiresPermission(Manifest.permission.READ_PHONE_STATE)
+ public boolean isVtSettingEnabled() {
+ try {
+ return getITelephony().isVtSettingEnabled(mSubId, mContext.getOpPackageName());
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ }
+ }
+
+ /**
+ * Change the user's setting for Video Telephony and enable the Video Telephony capability.
+ * @see #isVtSettingEnabled()
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
+ public void setVtSetting(boolean isEnabled) {
+ try {
+ getITelephony().setVtSetting(mSubId, isEnabled);
+ return;
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ }
+ }
+
+ /**
+ * @return true if the user's setting for Voice over WiFi is enabled and false if it is not.
+ * @see #setVoWiFiSetting(boolean)
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ public boolean isVoWiFiSettingEnabled() {
+ try {
+ return getITelephony().isVoWiFiSettingEnabled(mSubId);
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ }
+ }
+
+ /**
+ * Sets the user's setting for whether or not Voice over WiFi is enabled.
+ * @param isEnabled true if the user's setting for Voice over WiFi is enabled, false otherwise=
+ * @see #isVoWiFiSettingEnabled()
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
+ public void setVoWiFiSetting(boolean isEnabled) {
+ try {
+ getITelephony().setVoWiFiSetting(mSubId, isEnabled);
+ return;
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ }
+ }
+
+ /**
+ * @return true if the user's setting for Voice over WiFi while roaming is enabled, false
+ * if disabled.
+ * @see #setVoWiFiRoamingSetting(boolean)
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ public boolean isVoWiFiRoamingSettingEnabled() {
+ try {
+ return getITelephony().isVoWiFiRoamingSettingEnabled(mSubId);
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ }
+ }
+
+ /**
+ * Change the user's setting for Voice over WiFi while roaming.
+ * @param isEnabled true if the user's setting for Voice over WiFi while roaming is enabled,
+ * false otherwise.
+ * @see #isVoWiFiRoamingSettingEnabled()
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
+ public void setVoWiFiRoamingSetting(boolean isEnabled) {
+ try {
+ getITelephony().setVoWiFiRoamingSetting(mSubId, isEnabled);
+ return;
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ }
+ }
+
+ /**
+ * Overrides the Voice over WiFi capability to true for IMS, but do not persist the setting.
+ * Typically used during the Voice over WiFi registration process for some carriers.
+ *
+ * @param isCapable true if the IMS stack should try to register for IMS over IWLAN, false
+ * otherwise.
+ * @param mode the Voice over WiFi mode preference to set, which can be one of the following:
+ * - {@link #WIFI_MODE_WIFI_ONLY}
+ * - {@link #WIFI_MODE_CELLULAR_PREFERRED}
+ * - {@link #WIFI_MODE_WIFI_PREFERRED}
+ * @see #setVoWiFiSetting(boolean)
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
+ public void setVoWiFiNonPersistent(boolean isCapable, int mode) {
+ try {
+ getITelephony().setVoWiFiNonPersistent(mSubId, isCapable, mode);
+ return;
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ }
+ }
+
+ /**
+ * @return The Voice over WiFi Mode preference set by the user, which can be one of the
+ * following:
+ * - {@link #WIFI_MODE_WIFI_ONLY}
+ * - {@link #WIFI_MODE_CELLULAR_PREFERRED}
+ * - {@link #WIFI_MODE_WIFI_PREFERRED}
+ * @see #setVoWiFiSetting(boolean)
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ public @WiFiCallingMode int getVoWiFiModeSetting() {
+ try {
+ return getITelephony().getVoWiFiModeSetting(mSubId);
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ }
+ }
+
+ /**
+ * Set the user's preference for Voice over WiFi calling mode.
+ * @param mode The user's preference for the technology to register for IMS over, can be one of
+ * the following:
+ * - {@link #WIFI_MODE_WIFI_ONLY}
+ * - {@link #WIFI_MODE_CELLULAR_PREFERRED}
+ * - {@link #WIFI_MODE_WIFI_PREFERRED}
+ * @see #getVoWiFiModeSetting()
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
+ public void setVoWiFiModeSetting(@WiFiCallingMode int mode) {
+ try {
+ getITelephony().setVoWiFiModeSetting(mSubId, mode);
+ return;
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ }
+ }
+
+ /**
+ * Set the user's preference for Voice over WiFi calling mode while the device is roaming on
+ * another network.
+ *
+ * @return The user's preference for the technology to register for IMS over when roaming on
+ * another network, can be one of the following:
+ * - {@link #WIFI_MODE_WIFI_ONLY}
+ * - {@link #WIFI_MODE_CELLULAR_PREFERRED}
+ * - {@link #WIFI_MODE_WIFI_PREFERRED}
+ * @see #setVoWiFiRoamingSetting(boolean)
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ @WiFiCallingMode int getVoWiFiRoamingModeSetting() {
+ try {
+ return getITelephony().getVoWiFiRoamingModeSetting(mSubId);
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ }
+ }
+
+ /**
+ * Set the user's preference for Voice over WiFi mode while the device is roaming on another
+ * network.
+ *
+ * @param mode The user's preference for the technology to register for IMS over when roaming on
+ * another network, can be one of the following:
+ * - {@link #WIFI_MODE_WIFI_ONLY}
+ * - {@link #WIFI_MODE_CELLULAR_PREFERRED}
+ * - {@link #WIFI_MODE_WIFI_PREFERRED}
+ * @see #getVoWiFiRoamingModeSetting()
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
+ public void setVoWiFiRoamingModeSetting(@WiFiCallingMode int mode) {
+ try {
+ getITelephony().setVoWiFiRoamingModeSetting(mSubId, mode);
+ return;
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ }
+ }
+
+ /**
+ * Change the user's setting for RTT capability of this device.
+ * @param isEnabled if true RTT will be enabled during calls.
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
+ public void setRttCapabilitySetting(boolean isEnabled) {
+ try {
+ getITelephony().setRttCapabilitySetting(mSubId, isEnabled);
+ return;
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ }
+ }
+
+ /**
+ * @return true if TTY over VoLTE is supported
+ * @see android.telecom.TelecomManager#getCurrentTtyMode
+ * @see android.telephony.CarrierConfigManager#KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ boolean isTtyOverVolteEnabled() {
+ try {
+ return getITelephony().isTtyOverVolteEnabled(mSubId);
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ }
+ }
+
+ private static SubscriptionManager getSubscriptionManager(Context context) {
+ SubscriptionManager manager = context.getSystemService(SubscriptionManager.class);
+ if (manager == null) {
+ throw new RuntimeException("Could not find SubscriptionManager.");
+ }
+ return manager;
+ }
+
+ private static ITelephony getITelephony() {
+ ITelephony binder = ITelephony.Stub.asInterface(
+ ServiceManager.getService(Context.TELEPHONY_SERVICE));
+ if (binder == null) {
+ throw new RuntimeException("Could not find Telephony Service.");
+ }
+ return binder;
+ }
+}
diff --git a/telephony/java/android/telephony/ims/aidl/IImsRegistrationCallback.aidl b/telephony/java/android/telephony/ims/aidl/IImsRegistrationCallback.aidl
index 4f37caa33680..749b1916962e 100644
--- a/telephony/java/android/telephony/ims/aidl/IImsRegistrationCallback.aidl
+++ b/telephony/java/android/telephony/ims/aidl/IImsRegistrationCallback.aidl
@@ -23,7 +23,7 @@ import android.telephony.ims.stub.ImsFeatureConfiguration;
import android.telephony.ims.ImsReasonInfo;
/**
- * See ImsRegistrationImplBase.Callback for more information.
+ * See {@link ImsManager#RegistrationCallback} for more information.
*
* {@hide}
*/
diff --git a/telephony/java/android/telephony/ims/feature/ImsFeature.java b/telephony/java/android/telephony/ims/feature/ImsFeature.java
index b77881e29f1e..7f69f43f6cea 100644
--- a/telephony/java/android/telephony/ims/feature/ImsFeature.java
+++ b/telephony/java/android/telephony/ims/feature/ImsFeature.java
@@ -167,59 +167,6 @@ public abstract class ImsFeature {
*/
public static final int CAPABILITY_SUCCESS = 0;
-
- /**
- * The framework implements this callback in order to register for Feature Capability status
- * updates, via {@link #onCapabilitiesStatusChanged(Capabilities)}, query Capability
- * configurations, via {@link #onQueryCapabilityConfiguration}, as well as to receive error
- * callbacks when the ImsService can not change the capability as requested, via
- * {@link #onChangeCapabilityConfigurationError}.
- *
- * @hide
- */
- public static class CapabilityCallback extends IImsCapabilityCallback.Stub {
-
- @Override
- public final void onCapabilitiesStatusChanged(int config) throws RemoteException {
- onCapabilitiesStatusChanged(new Capabilities(config));
- }
-
- /**
- * Returns the result of a query for the capability configuration of a requested capability.
- *
- * @param capability The capability that was requested.
- * @param radioTech The IMS radio technology associated with the capability.
- * @param isEnabled true if the capability is enabled, false otherwise.
- */
- @Override
- public void onQueryCapabilityConfiguration(int capability, int radioTech,
- boolean isEnabled) {
-
- }
-
- /**
- * Called when a change to the capability configuration has returned an error.
- *
- * @param capability The capability that was requested to be changed.
- * @param radioTech The IMS radio technology associated with the capability.
- * @param reason error associated with the failure to change configuration.
- */
- @Override
- public void onChangeCapabilityConfigurationError(int capability, int radioTech,
- @ImsCapabilityError int reason) {
- }
-
- /**
- * The status of the feature's capabilities has changed to either available or unavailable.
- * If unavailable, the feature is not able to support the unavailable capability at this
- * time.
- *
- * @param config The new availability of the capabilities.
- */
- public void onCapabilitiesStatusChanged(Capabilities config) {
- }
- }
-
/**
* Used by the ImsFeature to call back to the CapabilityCallback that the framework has
* provided.
diff --git a/telephony/java/android/telephony/ims/feature/MmTelFeature.java b/telephony/java/android/telephony/ims/feature/MmTelFeature.java
index 7681aefc07dc..969959433f23 100644
--- a/telephony/java/android/telephony/ims/feature/MmTelFeature.java
+++ b/telephony/java/android/telephony/ims/feature/MmTelFeature.java
@@ -17,6 +17,8 @@
package android.telephony.ims.feature;
import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.os.Bundle;
import android.os.Message;
@@ -222,21 +224,31 @@ public class MmTelFeature extends ImsFeature {
* This MmTelFeature can then return the status of each of these capabilities (enabled or not)
* by sending a {@link #notifyCapabilitiesStatusChanged} callback to the framework. The current
* status can also be queried using {@link #queryCapabilityStatus()}.
+ * @see #isCapable(int)
*/
public static class MmTelCapabilities extends Capabilities {
/**
- * @hide
+ * Create a new empty {@link MmTelCapabilities} instance.
+ * @see #addCapabilities(int)
+ * @see #removeCapabilities(int)
*/
@VisibleForTesting
public MmTelCapabilities() {
super();
}
+ /**@deprecated Use {@link MmTelCapabilities} to construct a new instance instead.*/
+ @Deprecated
public MmTelCapabilities(Capabilities c) {
mCapabilities = c.mCapabilities;
}
+ /**
+ * Create a new {link @MmTelCapabilities} instance with the provided capabilities.
+ * @param capabilities The capabilities that are supported for MmTel in the form of a
+ * bitfield.
+ */
public MmTelCapabilities(int capabilities) {
mCapabilities = capabilities;
}
@@ -406,7 +418,10 @@ public class MmTelFeature extends ImsFeature {
* support the capability that is enabled. A capability that is disabled by the framework (via
* {@link #changeEnabledCapabilities}) should also show the status as disabled.
*/
- public final void notifyCapabilitiesStatusChanged(MmTelCapabilities c) {
+ public final void notifyCapabilitiesStatusChanged(@NonNull MmTelCapabilities c) {
+ if (c == null) {
+ throw new IllegalArgumentException("MmTelCapabilities must be non-null!");
+ }
super.notifyCapabilitiesStatusChanged(c);
}
@@ -414,7 +429,12 @@ public class MmTelFeature extends ImsFeature {
* Notify the framework of an incoming call.
* @param c The {@link ImsCallSessionImplBase} of the new incoming call.
*/
- public final void notifyIncomingCall(ImsCallSessionImplBase c, Bundle extras) {
+ public final void notifyIncomingCall(@NonNull ImsCallSessionImplBase c,
+ @NonNull Bundle extras) {
+ if (c == null || extras == null) {
+ throw new IllegalArgumentException("ImsCallSessionImplBase and Bundle can not be "
+ + "null.");
+ }
synchronized (mLock) {
if (mListener == null) {
throw new IllegalStateException("Session is not available.");
@@ -434,7 +454,12 @@ public class MmTelFeature extends ImsFeature {
* This can be null if no call information is available for the rejected call.
* @param reason The {@link ImsReasonInfo} call rejection reason.
*/
- public final void notifyRejectedCall(ImsCallProfile callProfile, ImsReasonInfo reason) {
+ public final void notifyRejectedCall(@NonNull ImsCallProfile callProfile,
+ @NonNull ImsReasonInfo reason) {
+ if (callProfile == null || reason == null) {
+ throw new IllegalArgumentException("ImsCallProfile and ImsReasonInfo must not be "
+ + "null.");
+ }
synchronized (mLock) {
if (mListener == null) {
throw new IllegalStateException("Session is not available.");
@@ -508,8 +533,8 @@ public class MmTelFeature extends ImsFeature {
* the framework.
*/
@Override
- public void changeEnabledCapabilities(CapabilityChangeRequest request,
- CapabilityCallbackProxy c) {
+ public void changeEnabledCapabilities(@NonNull CapabilityChangeRequest request,
+ @NonNull CapabilityCallbackProxy c) {
// Base implementation, no-op
}
@@ -531,7 +556,7 @@ public class MmTelFeature extends ImsFeature {
* {@link ImsCallProfile#CALL_TYPE_VS_RX}
* @return a {@link ImsCallProfile} object
*/
- public ImsCallProfile createCallProfile(int callSessionType, int callType) {
+ public @Nullable ImsCallProfile createCallProfile(int callSessionType, int callType) {
// Base Implementation - Should be overridden
return null;
}
@@ -552,7 +577,7 @@ public class MmTelFeature extends ImsFeature {
*
* @param profile a call profile to make the call
*/
- public ImsCallSessionImplBase createCallSession(ImsCallProfile profile) {
+ public @Nullable ImsCallSessionImplBase createCallSession(@NonNull ImsCallProfile profile) {
// Base Implementation - Should be overridden
return null;
}
@@ -569,7 +594,7 @@ public class MmTelFeature extends ImsFeature {
* @return a {@link ProcessCallResult} to the framework, which will be used to determine if the
* call will be placed over IMS or via CSFB.
*/
- public @ProcessCallResult int shouldProcessCall(String[] numbers) {
+ public @ProcessCallResult int shouldProcessCall(@NonNull String[] numbers) {
return PROCESS_CALL_IMS;
}
@@ -602,7 +627,7 @@ public class MmTelFeature extends ImsFeature {
* @return The {@link ImsUtImplBase} Ut interface implementation for the supplementary service
* configuration.
*/
- public ImsUtImplBase getUt() {
+ public @NonNull ImsUtImplBase getUt() {
// Base Implementation - Should be overridden
return new ImsUtImplBase();
}
@@ -611,7 +636,7 @@ public class MmTelFeature extends ImsFeature {
* @return The {@link ImsEcbmImplBase} Emergency call-back mode interface for emergency VoLTE
* calls that support it.
*/
- public ImsEcbmImplBase getEcbm() {
+ public @NonNull ImsEcbmImplBase getEcbm() {
// Base Implementation - Should be overridden
return new ImsEcbmImplBase();
}
@@ -620,7 +645,7 @@ public class MmTelFeature extends ImsFeature {
* @return The {@link ImsMultiEndpointImplBase} implementation for implementing Dialog event
* package processing for multi-endpoint.
*/
- public ImsMultiEndpointImplBase getMultiEndpoint() {
+ public @NonNull ImsMultiEndpointImplBase getMultiEndpoint() {
// Base Implementation - Should be overridden
return new ImsMultiEndpointImplBase();
}
@@ -646,7 +671,7 @@ public class MmTelFeature extends ImsFeature {
* }
* }
*/
- public void setUiTtyMode(int mode, Message onCompleteMessage) {
+ public void setUiTtyMode(int mode, @Nullable Message onCompleteMessage) {
// Base Implementation - Should be overridden
}
@@ -680,7 +705,7 @@ public class MmTelFeature extends ImsFeature {
* @return an instance of {@link ImsSmsImplBase} which should be implemented by the IMS
* Provider.
*/
- public ImsSmsImplBase getSmsImplementation() {
+ public @NonNull ImsSmsImplBase getSmsImplementation() {
return new ImsSmsImplBase();
}
diff --git a/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java b/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java
index cecf2e26f139..a08e0313bb5b 100644
--- a/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java
@@ -76,64 +76,6 @@ public class ImsRegistrationImplBase {
private static final int REGISTRATION_STATE_REGISTERING = 1;
private static final int REGISTRATION_STATE_REGISTERED = 2;
- /**
- * Callback class for receiving Registration callback events.
- * @hide
- */
- public static class Callback extends IImsRegistrationCallback.Stub {
- /**
- * Notifies the framework when the IMS Provider is connected to the IMS network.
- *
- * @param imsRadioTech the radio access technology. Valid values are defined in
- * {@link ImsRegistrationTech}.
- */
- @Override
- public void onRegistered(@ImsRegistrationTech int imsRadioTech) {
- }
-
- /**
- * Notifies the framework when the IMS Provider is trying to connect the IMS network.
- *
- * @param imsRadioTech the radio access technology. Valid values are defined in
- * {@link ImsRegistrationTech}.
- */
- @Override
- public void onRegistering(@ImsRegistrationTech int imsRadioTech) {
- }
-
- /**
- * Notifies the framework when the IMS Provider is disconnected from the IMS network.
- *
- * @param info the {@link ImsReasonInfo} associated with why registration was disconnected.
- */
- @Override
- public void onDeregistered(ImsReasonInfo info) {
- }
-
- /**
- * A failure has occurred when trying to handover registration to another technology type,
- * defined in {@link ImsRegistrationTech}
- *
- * @param imsRadioTech The {@link ImsRegistrationTech} type that has failed
- * @param info A {@link ImsReasonInfo} that identifies the reason for failure.
- */
- @Override
- public void onTechnologyChangeFailed(@ImsRegistrationTech int imsRadioTech,
- ImsReasonInfo info) {
- }
-
- /**
- * Returns a list of subscriber {@link Uri}s associated with this IMS subscription when
- * it changes.
- * @param uris new array of subscriber {@link Uri}s that are associated with this IMS
- * subscription.
- */
- @Override
- public void onSubscriberAssociatedUriChanged(Uri[] uris) {
-
- }
- }
-
private final IImsRegistration mBinder = new IImsRegistration.Stub() {
@Override
diff --git a/telephony/java/com/android/internal/telephony/DctConstants.java b/telephony/java/com/android/internal/telephony/DctConstants.java
index 86cb1b74abd3..b0c875e0c6f2 100644
--- a/telephony/java/com/android/internal/telephony/DctConstants.java
+++ b/telephony/java/com/android/internal/telephony/DctConstants.java
@@ -100,6 +100,7 @@ public class DctConstants {
public static final int EVENT_DATA_RECONNECT = BASE + 47;
public static final int EVENT_ROAMING_SETTING_CHANGE = BASE + 48;
public static final int EVENT_DATA_SERVICE_BINDING_CHANGED = BASE + 49;
+ public static final int EVENT_DEVICE_PROVISIONING_DATA_SETTING_CHANGE = BASE + 50;
/***** Constants *****/
diff --git a/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl b/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl
index 38a1bc73c94d..9e42f12d685d 100644
--- a/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl
+++ b/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl
@@ -53,5 +53,6 @@ oneway interface IPhoneStateListener {
void onUserMobileDataStateChanged(in boolean enabled);
void onPhoneCapabilityChanged(in PhoneCapability capability);
void onPreferredDataSubIdChanged(in int subId);
+ void onRadioPowerStateChanged(in int state);
}
diff --git a/telephony/java/com/android/internal/telephony/IRcs.aidl b/telephony/java/com/android/internal/telephony/IRcs.aidl
new file mode 100644
index 000000000000..ede8695ef08e
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/IRcs.aidl
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony;
+
+interface IRcs {
+ void deleteThread(int threadId);
+} \ No newline at end of file
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 32eb12b49cf0..dc233585dea4 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -38,10 +38,12 @@ import android.telephony.ServiceState;
import android.telephony.SignalStrength;
import android.telephony.TelephonyHistogram;
import android.telephony.VisualVoicemailSmsFilterSettings;
+import android.telephony.ims.aidl.IImsCapabilityCallback;
import android.telephony.ims.aidl.IImsConfig;
import android.telephony.ims.aidl.IImsMmTelFeature;
import android.telephony.ims.aidl.IImsRcsFeature;
import android.telephony.ims.aidl.IImsRegistration;
+import android.telephony.ims.aidl.IImsRegistrationCallback;
import com.android.ims.internal.IImsServiceFeatureCallback;
import com.android.internal.telephony.CellNetworkScanResult;
import com.android.internal.telephony.OperatorInfo;
@@ -280,7 +282,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();
@@ -1057,11 +1059,6 @@ interface ITelephony {
*/
boolean isWifiCallingAvailable(int subId);
- /**
- * Returns the Status of VoLTE for the subscription ID specified.
- */
- boolean isVolteAvailable(int subId);
-
/**
* Returns the Status of VT (video telephony) for the subscription ID specified.
*/
@@ -1499,4 +1496,123 @@ interface ITelephony {
* Set the default SMS app to a given package on a given user.
*/
void setDefaultSmsApp(int userId, String packageName);
+
+ /**
+ * Return the modem radio power state for slot index.
+ *
+ */
+ int getRadioPowerState(int slotIndex, String callingPackage);
+
+ // IMS specific AIDL commands, see ImsMmTelManager.java
+
+ /**
+ * Adds an IMS registration status callback for the subscription id specified.
+ */
+ oneway void addImsRegistrationCallback(int subId, IImsRegistrationCallback c,
+ String callingPackage);
+ /**
+ * Removes an existing IMS registration status callback for the subscription specified.
+ */
+ oneway void removeImsRegistrationCallback(int subId, IImsRegistrationCallback c,
+ String callingPackage);
+
+ /**
+ * Adds an IMS MmTel capabilities callback for the subscription specified.
+ */
+ oneway void addMmTelCapabilityCallback(int subId, IImsCapabilityCallback c,
+ String callingPackage);
+
+ /**
+ * Removes an existing IMS MmTel capabilities callback for the subscription specified.
+ */
+ oneway void removeMmTelCapabilityCallback(int subId, IImsCapabilityCallback c,
+ String callingPackage);
+
+ /**
+ * return true if the IMS MmTel capability for the given registration tech is capable.
+ */
+ boolean isCapable(int subId, int capability, int regTech, String callingPackage);
+
+ /**
+ * return true if the IMS MmTel capability for the given registration tech is available.
+ */
+ boolean isAvailable(int subId, int capability, int regTech, String callingPackage);
+
+ /**
+ * Returns true if the user's setting for 4G LTE is enabled, for the subscription specified.
+ */
+ boolean isAdvancedCallingSettingEnabled(int subId);
+
+ /**
+ * Modify the user's setting for whether or not 4G LTE is enabled.
+ */
+ void setAdvancedCallingSetting(int subId, boolean isEnabled);
+
+ /**
+ * return true if the user's setting for VT is enabled for the subscription.
+ */
+ boolean isVtSettingEnabled(int subId, String callingPackage);
+
+ /**
+ * Modify the user's setting for whether or not VT is available for the subscrption specified.
+ */
+ void setVtSetting(int subId, boolean isEnabled);
+
+ /**
+ * return true if the user's setting for whether or not Voice over WiFi is currently enabled.
+ */
+ boolean isVoWiFiSettingEnabled(int subId);
+
+ /**
+ * sets the user's setting for Voice over WiFi enabled state.
+ */
+ void setVoWiFiSetting(int subId, boolean isEnabled);
+
+ /**
+ * return true if the user's setting for Voice over WiFi while roaming is enabled.
+ */
+ boolean isVoWiFiRoamingSettingEnabled(int subId);
+
+ /**
+ * Sets the user's preference for whether or not Voice over WiFi is enabled for the current
+ * subscription while roaming.
+ */
+ void setVoWiFiRoamingSetting(int subId, boolean isEnabled);
+
+ /**
+ * Set the Voice over WiFi enabled state, but do not persist the setting.
+ */
+ void setVoWiFiNonPersistent(int subId, boolean isCapable, int mode);
+
+ /**
+ * return the Voice over WiFi mode preference set by the user for the subscription specified.
+ */
+ int getVoWiFiModeSetting(int subId);
+
+ /**
+ * sets the user's preference for the Voice over WiFi mode for the subscription specified.
+ */
+ void setVoWiFiModeSetting(int subId, int mode);
+
+ /**
+ * return the Voice over WiFi mode preference set by the user for the subscription specified
+ * while roaming.
+ */
+ int getVoWiFiRoamingModeSetting(int subId);
+
+ /**
+ * sets the user's preference for the Voice over WiFi mode for the subscription specified
+ * while roaming.
+ */
+ void setVoWiFiRoamingModeSetting(int subId, int mode);
+
+ /**
+ * Modify the user's setting for whether or not RTT is enabled for the subscrption specified.
+ */
+ void setRttCapabilitySetting(int subId, boolean isEnabled);
+
+ /**
+ * return true if TTY over VoLTE is enabled for the subscription specified.
+ */
+ boolean isTtyOverVolteEnabled(int subId);
}
diff --git a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
index c03065c34ca8..0baf860efac4 100644
--- a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
@@ -80,4 +80,5 @@ interface ITelephonyRegistry {
void notifyUserMobileDataStateChangedForPhoneId(in int phoneId, in int subId, in boolean state);
void notifyPhoneCapabilityChanged(in PhoneCapability capability);
void notifyPreferredDataSubIdChanged(int preferredSubId);
+ void notifyRadioPowerStateChanged(in int state);
}
diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java
index 0e7c654613e4..40ee0c891dd2 100644
--- a/telephony/java/com/android/internal/telephony/RILConstants.java
+++ b/telephony/java/com/android/internal/telephony/RILConstants.java
@@ -423,6 +423,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 dac7e04be07a..eda8e7766054 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
@@ -29,9 +29,11 @@ import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
+import android.provider.Settings;
import android.telephony.Rlog;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
+import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
@@ -275,31 +277,47 @@ public final class TelephonyPermissions {
*/
private static boolean reportAccessDeniedToReadIdentifiers(Context context, int subId, int pid,
int uid, String callingPackage, String message) {
- 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;
+ Log.wtf(LOG_TAG,
+ "reportAccessDeniedToReadIdentifiers:" + callingPackage + ":" + message);
+ // if the device identifier check is relaxed then revert to the READ_PHONE_STATE permission
+ // check that was previously required to access device identifiers.
+ boolean relaxDeviceIdentifierCheck = Settings.Global.getInt(context.getContentResolver(),
+ Settings.Global.PRIVILEGED_DEVICE_IDENTIFIER_CHECK_ENABLED, 0) == 0;
+ if (relaxDeviceIdentifierCheck) {
+ return checkReadPhoneState(context, subId, pid, uid, callingPackage, message);
+ } else {
+ boolean targetQBehaviorDisabled = Settings.Global.getInt(context.getContentResolver(),
+ Settings.Global.PRIVILEGED_DEVICE_IDENTIFIER_TARGET_Q_BEHAVIOR_ENABLED, 0) == 0;
+ if (callingPackage != null) {
+ try {
+ // if the target SDK is pre-Q or the target Q behavior is disabled 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
+ || targetQBehaviorDisabled)) {
+ 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.
}
- } 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 meet the requirements to access device identifiers.");
}
- throw new SecurityException(message + ": The user " + uid + " does not have the "
- + "READ_PRIVILEGED_PHONE_STATE permission to access the device identifiers");
}
/**
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/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java b/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
index 976848c60dc7..eed8ae7c1f70 100644
--- a/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
+++ b/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
@@ -92,7 +92,9 @@ public class AppLaunch extends InstrumentationTestCase {
"com.google.android.wearable.action.GOOGLE";
private static final int INITIAL_LAUNCH_IDLE_TIMEOUT = 5000; // 5s to allow app to idle
private static final int POST_LAUNCH_IDLE_TIMEOUT = 750; // 750ms idle for non initial launches
- private static final int BETWEEN_LAUNCH_SLEEP_TIMEOUT = 5000; // 5s between launching apps
+ private static final int BEFORE_FORCE_STOP_SLEEP_TIMEOUT = 1000; // 1s before force stopping
+ private static final int BEFORE_KILL_APP_SLEEP_TIMEOUT = 1000; // 1s before killing
+ private static final int BETWEEN_LAUNCH_SLEEP_TIMEOUT = 3000; // 3s between launching apps
private static final int PROFILE_SAVE_SLEEP_TIMEOUT = 1000; // Allow 1s for the profile to save
private static final String LAUNCH_SUB_DIRECTORY = "launch_logs";
private static final String LAUNCH_FILE = "applaunch.txt";
@@ -327,7 +329,14 @@ public class AppLaunch extends InstrumentationTestCase {
}
}
if(mForceStopApp) {
- closeApp(launch.getApp());
+ sleep(BEFORE_FORCE_STOP_SLEEP_TIMEOUT);
+ forceStopApp(launch.getApp());
+ sleep(BEFORE_KILL_APP_SLEEP_TIMEOUT);
+ // Close again for good measure (just in case).
+ forceStopApp(launch.getApp());
+ // Kill the backgrounded process in the case forceStopApp only sent it to
+ // background.
+ killBackgroundApp(launch.getApp());
} else {
startHomeIntent();
}
@@ -638,7 +647,7 @@ public class AppLaunch extends InstrumentationTestCase {
// Kill all the apps
for (String appName : mNameToIntent.keySet()) {
Log.w(TAG, String.format("killing %s", appName));
- closeApp(appName);
+ forceStopApp(appName);
}
// Drop all the cache.
assertNotNull("Issue in dropping the cache",
@@ -646,7 +655,7 @@ public class AppLaunch extends InstrumentationTestCase {
.executeShellCommand(DROP_CACHE_SCRIPT));
}
- private void closeApp(String appName) {
+ private void forceStopApp(String appName) {
Intent startIntent = mNameToIntent.get(appName);
if (startIntent != null) {
String packageName = startIntent.getComponent().getPackageName();
@@ -658,6 +667,18 @@ public class AppLaunch extends InstrumentationTestCase {
}
}
+ private void killBackgroundApp(String appName) {
+ Intent startIntent = mNameToIntent.get(appName);
+ if (startIntent != null) {
+ String packageName = startIntent.getComponent().getPackageName();
+ try {
+ mAm.killBackgroundProcesses(packageName, UserHandle.USER_CURRENT);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Error closing app", e);
+ }
+ }
+ }
+
private void sleep(int time) {
try {
Thread.sleep(time);
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/tests/net/java/android/net/ConnectivityManagerTest.java b/tests/net/java/android/net/ConnectivityManagerTest.java
index 03a617c354fa..6174c6ca6190 100644
--- a/tests/net/java/android/net/ConnectivityManagerTest.java
+++ b/tests/net/java/android/net/ConnectivityManagerTest.java
@@ -219,7 +219,7 @@ public class ConnectivityManagerTest {
// callback triggers
captor.getValue().send(makeMessage(request, ConnectivityManager.CALLBACK_AVAILABLE));
verify(callback, timeout(500).times(1)).onAvailable(any(Network.class),
- any(NetworkCapabilities.class), any(LinkProperties.class));
+ any(NetworkCapabilities.class), any(LinkProperties.class), anyBoolean());
// unregister callback
manager.unregisterNetworkCallback(callback);
@@ -247,7 +247,7 @@ public class ConnectivityManagerTest {
// callback triggers
captor.getValue().send(makeMessage(req1, ConnectivityManager.CALLBACK_AVAILABLE));
verify(callback, timeout(100).times(1)).onAvailable(any(Network.class),
- any(NetworkCapabilities.class), any(LinkProperties.class));
+ any(NetworkCapabilities.class), any(LinkProperties.class), anyBoolean());
// unregister callback
manager.unregisterNetworkCallback(callback);
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 1c77fcc568f6..17bcea05b294 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -51,6 +51,10 @@ import static android.net.NetworkCapabilities.TRANSPORT_ETHERNET;
import static android.net.NetworkCapabilities.TRANSPORT_VPN;
import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
import static android.net.NetworkCapabilities.TRANSPORT_WIFI_AWARE;
+import static android.net.NetworkPolicyManager.RULE_ALLOW_METERED;
+import static android.net.NetworkPolicyManager.RULE_NONE;
+import static android.net.NetworkPolicyManager.RULE_REJECT_ALL;
+import static android.net.NetworkPolicyManager.RULE_REJECT_METERED;
import static com.android.internal.util.TestUtils.waitForIdleHandler;
import static com.android.internal.util.TestUtils.waitForIdleLooper;
@@ -92,6 +96,7 @@ import android.net.ConnectivityManager.PacketKeepalive;
import android.net.ConnectivityManager.PacketKeepaliveCallback;
import android.net.ConnectivityManager.TooManyRequestsException;
import android.net.ConnectivityThread;
+import android.net.INetworkPolicyListener;
import android.net.INetworkPolicyManager;
import android.net.INetworkStatsService;
import android.net.InterfaceConfiguration;
@@ -148,6 +153,7 @@ import com.android.server.connectivity.MockableSystemProperties;
import com.android.server.connectivity.Nat464Xlat;
import com.android.server.connectivity.NetworkAgentInfo;
import com.android.server.connectivity.NetworkMonitor;
+import com.android.server.connectivity.Tethering;
import com.android.server.connectivity.Vpn;
import com.android.server.net.NetworkPinner;
import com.android.server.net.NetworkPolicyManagerInternal;
@@ -215,11 +221,13 @@ public class ConnectivityServiceTest {
private MockNetworkAgent mEthernetNetworkAgent;
private MockVpn mMockVpn;
private Context mContext;
+ private INetworkPolicyListener mPolicyListener;
@Mock IpConnectivityMetrics.Logger mMetricsService;
@Mock DefaultNetworkMetrics mDefaultNetworkMetrics;
@Mock INetworkManagementService mNetworkManagementService;
@Mock INetworkStatsService mStatsService;
+ @Mock INetworkPolicyManager mNpm;
private ArgumentCaptor<String[]> mStringArrayCaptor = ArgumentCaptor.forClass(String[].class);
@@ -934,6 +942,11 @@ public class ConnectivityServiceTest {
}
@Override
+ protected Tethering makeTethering() {
+ return mock(Tethering.class);
+ }
+
+ @Override
protected int reserveNetId() {
while (true) {
final int netId = super.reserveNetId();
@@ -1023,6 +1036,20 @@ public class ConnectivityServiceTest {
public void waitForIdle() {
waitForIdle(TIMEOUT_MS);
}
+
+ public void setUidRulesChanged(int uidRules) {
+ try {
+ mPolicyListener.onUidRulesChanged(Process.myUid(), uidRules);
+ } catch (RemoteException ignored) {
+ }
+ }
+
+ public void setRestrictBackgroundChanged(boolean restrictBackground) {
+ try {
+ mPolicyListener.onRestrictBackgroundChanged(restrictBackground);
+ } catch (RemoteException ignored) {
+ }
+ }
}
/**
@@ -1055,12 +1082,18 @@ public class ConnectivityServiceTest {
LocalServices.removeServiceForTest(NetworkPolicyManagerInternal.class);
LocalServices.addService(
NetworkPolicyManagerInternal.class, mock(NetworkPolicyManagerInternal.class));
+
mService = new WrappedConnectivityService(mServiceContext,
mNetworkManagementService,
mStatsService,
- mock(INetworkPolicyManager.class),
+ mNpm,
mock(IpConnectivityLog.class));
+ final ArgumentCaptor<INetworkPolicyListener> policyListenerCaptor =
+ ArgumentCaptor.forClass(INetworkPolicyListener.class);
+ verify(mNpm).registerListener(policyListenerCaptor.capture());
+ mPolicyListener = policyListenerCaptor.getValue();
+
// Create local CM before sending system ready so that we can answer
// getSystemService() correctly.
mCm = new WrappedConnectivityManager(InstrumentationRegistry.getContext(), mService);
@@ -1441,7 +1474,8 @@ public class ConnectivityServiceTest {
RESUMED,
LOSING,
LOST,
- UNAVAILABLE
+ UNAVAILABLE,
+ BLOCKED_STATUS
}
private static class CallbackInfo {
@@ -1522,6 +1556,11 @@ public class ConnectivityServiceTest {
setLastCallback(CallbackState.LOST, network, null);
}
+ @Override
+ public void onBlockedStatusChanged(Network network, boolean blocked) {
+ setLastCallback(CallbackState.BLOCKED_STATUS, network, blocked);
+ }
+
public Network getLastAvailableNetwork() {
return mLastAvailableNetwork;
}
@@ -1582,6 +1621,7 @@ public class ConnectivityServiceTest {
// - onSuspended, iff the network was suspended when the callbacks fire.
// - onCapabilitiesChanged.
// - onLinkPropertiesChanged.
+ // - onBlockedStatusChanged.
//
// @param agent the network to expect the callbacks on.
// @param expectSuspended whether to expect a SUSPENDED callback.
@@ -1589,7 +1629,7 @@ public class ConnectivityServiceTest {
// onCapabilitiesChanged callback.
// @param timeoutMs how long to wait for the callbacks.
void expectAvailableCallbacks(MockNetworkAgent agent, boolean expectSuspended,
- boolean expectValidated, int timeoutMs) {
+ boolean expectValidated, boolean expectBlocked, int timeoutMs) {
expectCallback(CallbackState.AVAILABLE, agent, timeoutMs);
if (expectSuspended) {
expectCallback(CallbackState.SUSPENDED, agent, timeoutMs);
@@ -1600,19 +1640,28 @@ public class ConnectivityServiceTest {
expectCapabilitiesWithout(NET_CAPABILITY_VALIDATED, agent, timeoutMs);
}
expectCallback(CallbackState.LINK_PROPERTIES, agent, timeoutMs);
+ expectBlockedStatusCallback(expectBlocked, agent);
}
// Expects the available callbacks (validated), plus onSuspended.
void expectAvailableAndSuspendedCallbacks(MockNetworkAgent agent, boolean expectValidated) {
- expectAvailableCallbacks(agent, true, expectValidated, TEST_CALLBACK_TIMEOUT_MS);
+ expectAvailableCallbacks(agent, true, expectValidated, false, TEST_CALLBACK_TIMEOUT_MS);
}
void expectAvailableCallbacksValidated(MockNetworkAgent agent) {
- expectAvailableCallbacks(agent, false, true, TEST_CALLBACK_TIMEOUT_MS);
+ expectAvailableCallbacks(agent, false, true, false, TEST_CALLBACK_TIMEOUT_MS);
+ }
+
+ void expectAvailableCallbacksValidatedAndBlocked(MockNetworkAgent agent) {
+ expectAvailableCallbacks(agent, false, true, true, TEST_CALLBACK_TIMEOUT_MS);
}
void expectAvailableCallbacksUnvalidated(MockNetworkAgent agent) {
- expectAvailableCallbacks(agent, false, false, TEST_CALLBACK_TIMEOUT_MS);
+ expectAvailableCallbacks(agent, false, false, false, TEST_CALLBACK_TIMEOUT_MS);
+ }
+
+ void expectAvailableCallbacksUnvalidatedAndBlocked(MockNetworkAgent agent) {
+ expectAvailableCallbacks(agent, false, false, true, TEST_CALLBACK_TIMEOUT_MS);
}
// Expects the available callbacks (where the onCapabilitiesChanged must contain the
@@ -1623,6 +1672,9 @@ public class ConnectivityServiceTest {
expectCallback(CallbackState.AVAILABLE, agent, TEST_CALLBACK_TIMEOUT_MS);
NetworkCapabilities nc1 = expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, agent);
expectCallback(CallbackState.LINK_PROPERTIES, agent, TEST_CALLBACK_TIMEOUT_MS);
+ // Implicitly check the network is allowed to use.
+ // TODO: should we need to consider if network is in blocked status in this case?
+ expectBlockedStatusCallback(false, agent);
NetworkCapabilities nc2 = expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, agent);
assertEquals(nc1, nc2);
}
@@ -1665,6 +1717,12 @@ public class ConnectivityServiceTest {
fn.test((NetworkCapabilities) cbi.arg));
}
+ void expectBlockedStatusCallback(boolean expectBlocked, MockNetworkAgent agent) {
+ CallbackInfo cbi = expectCallback(CallbackState.BLOCKED_STATUS, agent);
+ boolean actualBlocked = (boolean) cbi.arg;
+ assertEquals(expectBlocked, actualBlocked);
+ }
+
void assertNoCallback() {
waitForIdle();
CallbackInfo c = mCallbacks.peek();
@@ -3223,7 +3281,7 @@ public class ConnectivityServiceTest {
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
mWiFiNetworkAgent.connect(false);
- networkCallback.expectAvailableCallbacks(mWiFiNetworkAgent, false, false,
+ networkCallback.expectAvailableCallbacks(mWiFiNetworkAgent, false, false, false,
TEST_CALLBACK_TIMEOUT_MS);
// pass timeout and validate that UNAVAILABLE is not called
@@ -3243,7 +3301,7 @@ public class ConnectivityServiceTest {
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
mWiFiNetworkAgent.connect(false);
- networkCallback.expectAvailableCallbacks(mWiFiNetworkAgent, false, false,
+ networkCallback.expectAvailableCallbacks(mWiFiNetworkAgent, false, false, false,
TEST_CALLBACK_TIMEOUT_MS);
mWiFiNetworkAgent.disconnect();
networkCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
@@ -3802,6 +3860,7 @@ public class ConnectivityServiceTest {
networkCallback.expectCallback(CallbackState.NETWORK_CAPABILITIES, networkAgent);
CallbackInfo cbi = networkCallback.expectCallback(CallbackState.LINK_PROPERTIES,
networkAgent);
+ networkCallback.expectCallback(CallbackState.BLOCKED_STATUS, networkAgent);
networkCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, networkAgent);
networkCallback.assertNoCallback();
checkDirectlyConnectedRoutes(cbi.arg, Arrays.asList(myIpv4Address),
@@ -4010,6 +4069,7 @@ public class ConnectivityServiceTest {
mCellNetworkAgent);
CallbackInfo cbi = cellNetworkCallback.expectCallback(
CallbackState.LINK_PROPERTIES, mCellNetworkAgent);
+ cellNetworkCallback.expectCallback(CallbackState.BLOCKED_STATUS, mCellNetworkAgent);
cellNetworkCallback.assertNoCallback();
assertFalse(((LinkProperties)cbi.arg).isPrivateDnsActive());
assertNull(((LinkProperties)cbi.arg).getPrivateDnsServerName());
@@ -4068,6 +4128,7 @@ public class ConnectivityServiceTest {
mCellNetworkAgent);
CallbackInfo cbi = cellNetworkCallback.expectCallback(
CallbackState.LINK_PROPERTIES, mCellNetworkAgent);
+ cellNetworkCallback.expectCallback(CallbackState.BLOCKED_STATUS, mCellNetworkAgent);
cellNetworkCallback.assertNoCallback();
assertFalse(((LinkProperties)cbi.arg).isPrivateDnsActive());
assertNull(((LinkProperties)cbi.arg).getPrivateDnsServerName());
@@ -4444,6 +4505,101 @@ public class ConnectivityServiceTest {
mMockVpn.disconnect();
}
+ @Test
+ public void testNetworkBlockedStatus() {
+ final TestNetworkCallback cellNetworkCallback = new TestNetworkCallback();
+ final NetworkRequest cellRequest = new NetworkRequest.Builder()
+ .addTransportType(TRANSPORT_CELLULAR)
+ .build();
+ mCm.registerNetworkCallback(cellRequest, cellNetworkCallback);
+
+ mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+ mCellNetworkAgent.connect(true);
+ cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
+
+ mService.setUidRulesChanged(RULE_REJECT_ALL);
+ cellNetworkCallback.expectBlockedStatusCallback(true, mCellNetworkAgent);
+
+ // ConnectivityService should cache it not to invoke the callback again.
+ mService.setUidRulesChanged(RULE_REJECT_METERED);
+ cellNetworkCallback.assertNoCallback();
+
+ mService.setUidRulesChanged(RULE_NONE);
+ cellNetworkCallback.expectBlockedStatusCallback(false, mCellNetworkAgent);
+
+ mService.setUidRulesChanged(RULE_REJECT_METERED);
+ cellNetworkCallback.expectBlockedStatusCallback(true, mCellNetworkAgent);
+
+ // Restrict the network based on UID rule and NOT_METERED capability change.
+ mCellNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED);
+ cellNetworkCallback.expectCapabilitiesWith(NET_CAPABILITY_NOT_METERED, mCellNetworkAgent);
+ cellNetworkCallback.expectBlockedStatusCallback(false, mCellNetworkAgent);
+ mCellNetworkAgent.removeCapability(NET_CAPABILITY_NOT_METERED);
+ cellNetworkCallback.expectCapabilitiesWithout(NET_CAPABILITY_NOT_METERED,
+ mCellNetworkAgent);
+ cellNetworkCallback.expectBlockedStatusCallback(true, mCellNetworkAgent);
+ mService.setUidRulesChanged(RULE_ALLOW_METERED);
+ cellNetworkCallback.expectBlockedStatusCallback(false, mCellNetworkAgent);
+
+ mService.setUidRulesChanged(RULE_NONE);
+ cellNetworkCallback.assertNoCallback();
+
+ // Restrict the network based on BackgroundRestricted.
+ mService.setRestrictBackgroundChanged(true);
+ cellNetworkCallback.expectBlockedStatusCallback(true, mCellNetworkAgent);
+ mService.setRestrictBackgroundChanged(true);
+ cellNetworkCallback.assertNoCallback();
+ mService.setRestrictBackgroundChanged(false);
+ cellNetworkCallback.expectBlockedStatusCallback(false, mCellNetworkAgent);
+ cellNetworkCallback.assertNoCallback();
+
+ mCm.unregisterNetworkCallback(cellNetworkCallback);
+ }
+
+ @Test
+ public void testNetworkBlockedStatusBeforeAndAfterConnect() {
+ final TestNetworkCallback defaultCallback = new TestNetworkCallback();
+ mCm.registerDefaultNetworkCallback(defaultCallback);
+
+ // No Networkcallbacks invoked before any network is active.
+ mService.setUidRulesChanged(RULE_REJECT_ALL);
+ mService.setUidRulesChanged(RULE_NONE);
+ mService.setUidRulesChanged(RULE_REJECT_METERED);
+ defaultCallback.assertNoCallback();
+
+ mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+ mCellNetworkAgent.connect(true);
+ defaultCallback.expectAvailableCallbacksUnvalidatedAndBlocked(mCellNetworkAgent);
+ defaultCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mCellNetworkAgent);
+
+ // Allow to use the network after switching to NOT_METERED network.
+ mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+ mWiFiNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED);
+ mWiFiNetworkAgent.connect(true);
+ defaultCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
+
+ // Switch to METERED network. Restrict the use of the network.
+ mWiFiNetworkAgent.disconnect();
+ defaultCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+ defaultCallback.expectAvailableCallbacksValidatedAndBlocked(mCellNetworkAgent);
+
+ // Network becomes NOT_METERED.
+ mCellNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED);
+ defaultCallback.expectCapabilitiesWith(NET_CAPABILITY_NOT_METERED, mCellNetworkAgent);
+ defaultCallback.expectBlockedStatusCallback(false, mCellNetworkAgent);
+
+ // Verify there's no Networkcallbacks invoked after data saver on/off.
+ mService.setRestrictBackgroundChanged(true);
+ mService.setRestrictBackgroundChanged(false);
+ defaultCallback.assertNoCallback();
+
+ mCellNetworkAgent.disconnect();
+ defaultCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
+ defaultCallback.assertNoCallback();
+
+ mCm.unregisterNetworkCallback(defaultCallback);
+ }
+
/**
* Make simulated InterfaceConfig for Nat464Xlat to query clat lower layer info.
*/
diff --git a/tools/aapt2/Android.mk b/tools/aapt2/Android.mk
index c9987b86cc5c..b165c6bed220 100644
--- a/tools/aapt2/Android.mk
+++ b/tools/aapt2/Android.mk
@@ -2,10 +2,19 @@ LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
+aapt2_results := $(call intermediates-dir-for,PACKAGING,aapt2_run_host_unit_tests)/result.xml
+
# Target for running host unit tests on post/pre-submit.
.PHONY: aapt2_run_host_unit_tests
-aapt2_run_host_unit_tests: PRIVATE_GTEST_OPTIONS := --gtest_output=xml:$(DIST_DIR)/gtest/aapt2_host_unit_tests_result.xml
-aapt2_run_host_unit_tests: $(HOST_OUT_NATIVE_TESTS)/aapt2_tests/aapt2_tests
- -$(HOST_OUT_NATIVE_TESTS)/aapt2_tests/aapt2_tests $(PRIVATE_GTEST_OPTIONS) > /dev/null 2>&1
+aapt2_run_host_unit_tests: $(aapt2_results)
+
+$(call dist-for-goals,aapt2_run_host_unit_tests,$(aapt2_results):gtest/aapt2_host_unit_tests_result.xml)
+
+# Always run the tests again, even if they haven't changed
+$(aapt2_results): .KATI_IMPLICIT_OUTPUTS := $(aapt2_results)-nocache
+$(aapt2_results): $(HOST_OUT_NATIVE_TESTS)/aapt2_tests/aapt2_tests
+ -$(HOST_OUT_NATIVE_TESTS)/aapt2_tests/aapt2_tests --gtest_output=xml:$@ > /dev/null 2>&1
+
+aapt2_results :=
include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tools/aapt2/LoadedApk.cpp b/tools/aapt2/LoadedApk.cpp
index a20b9b76a703..b353ff00a23f 100644
--- a/tools/aapt2/LoadedApk.cpp
+++ b/tools/aapt2/LoadedApk.cpp
@@ -35,6 +35,43 @@ using ::std::unique_ptr;
namespace aapt {
+static ApkFormat DetermineApkFormat(io::IFileCollection* apk) {
+ if (apk->FindFile(kApkResourceTablePath) != nullptr) {
+ return ApkFormat::kBinary;
+ } else if (apk->FindFile(kProtoResourceTablePath) != nullptr) {
+ return ApkFormat::kProto;
+ } else {
+ // If the resource table is not present, attempt to read the manifest.
+ io::IFile* manifest_file = apk->FindFile(kAndroidManifestPath);
+ if (manifest_file == nullptr) {
+ return ApkFormat::kUnknown;
+ }
+
+ // First try in proto format.
+ std::unique_ptr<io::InputStream> manifest_in = manifest_file->OpenInputStream();
+ if (manifest_in != nullptr) {
+ pb::XmlNode pb_node;
+ io::ProtoInputStreamReader proto_reader(manifest_in.get());
+ if (proto_reader.ReadMessage(&pb_node)) {
+ return ApkFormat::kProto;
+ }
+ }
+
+ // If it didn't work, try in binary format.
+ std::unique_ptr<io::IData> manifest_data = manifest_file->OpenAsData();
+ if (manifest_data != nullptr) {
+ std::string error;
+ std::unique_ptr<xml::XmlResource> manifest =
+ xml::Inflate(manifest_data->data(), manifest_data->size(), &error);
+ if (manifest != nullptr) {
+ return ApkFormat::kBinary;
+ }
+ }
+
+ return ApkFormat::kUnknown;
+ }
+}
+
std::unique_ptr<LoadedApk> LoadedApk::LoadApkFromPath(const StringPiece& path, IDiagnostics* diag) {
Source source(path);
std::string error;
@@ -301,41 +338,4 @@ std::unique_ptr<xml::XmlResource> LoadedApk::LoadXml(const std::string& file_pat
return doc;
}
-ApkFormat LoadedApk::DetermineApkFormat(io::IFileCollection* apk) {
- if (apk->FindFile(kApkResourceTablePath) != nullptr) {
- return ApkFormat::kBinary;
- } else if (apk->FindFile(kProtoResourceTablePath) != nullptr) {
- return ApkFormat::kProto;
- } else {
- // If the resource table is not present, attempt to read the manifest.
- io::IFile* manifest_file = apk->FindFile(kAndroidManifestPath);
- if (manifest_file == nullptr) {
- return ApkFormat::kUnknown;
- }
-
- // First try in proto format.
- std::unique_ptr<io::InputStream> manifest_in = manifest_file->OpenInputStream();
- if (manifest_in != nullptr) {
- pb::XmlNode pb_node;
- io::ProtoInputStreamReader proto_reader(manifest_in.get());
- if (!proto_reader.ReadMessage(&pb_node)) {
- return ApkFormat::kProto;
- }
- }
-
- // If it didn't work, try in binary format.
- std::unique_ptr<io::IData> manifest_data = manifest_file->OpenAsData();
- if (manifest_data != nullptr) {
- std::string error;
- std::unique_ptr<xml::XmlResource> manifest =
- xml::Inflate(manifest_data->data(), manifest_data->size(), &error);
- if (manifest != nullptr) {
- return ApkFormat::kBinary;
- }
- }
-
- return ApkFormat::kUnknown;
- }
-}
-
} // namespace aapt
diff --git a/tools/aapt2/LoadedApk.h b/tools/aapt2/LoadedApk.h
index 84c57c14474a..5b6f45ebb38d 100644
--- a/tools/aapt2/LoadedApk.h
+++ b/tools/aapt2/LoadedApk.h
@@ -121,8 +121,6 @@ class LoadedApk {
std::unique_ptr<ResourceTable> table_;
std::unique_ptr<xml::XmlResource> manifest_;
ApkFormat format_;
-
- static ApkFormat DetermineApkFormat(io::IFileCollection* apk);
};
} // 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/hiddenapi/merge_csv.py b/tools/hiddenapi/merge_csv.py
new file mode 100755
index 000000000000..48c07553ffef
--- /dev/null
+++ b/tools/hiddenapi/merge_csv.py
@@ -0,0 +1,40 @@
+#!/usr/bin/env python
+#
+# 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.
+"""
+Merge mutliple CSV files, possibly with different columns, writing to stdout.
+"""
+
+import csv
+import sys
+
+csv_readers = [
+ csv.DictReader(open(csv_file, 'rb'), delimiter=',', quotechar='|')
+ for csv_file in sys.argv[1:]
+]
+
+# Build union of all columns from source files:
+headers = set()
+for reader in csv_readers:
+ headers = headers.union(reader.fieldnames)
+
+# Concatenate all files to output:
+out = csv.DictWriter(sys.stdout, delimiter=',', quotechar='|', fieldnames = sorted(headers))
+out.writeheader()
+for reader in csv_readers:
+ for row in reader:
+ out.writerow(row)
+
+
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());
}