summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apct-tests/perftests/inputmethod/src/android/inputmethod/ImePerfTest.java92
-rw-r--r--apex/appsearch/framework/java/android/app/appsearch/AppSearchManager.java49
-rw-r--r--apex/appsearch/framework/java/android/app/appsearch/AppSearchResult.aidl2
-rw-r--r--apex/appsearch/framework/java/android/app/appsearch/AppSearchSession.java92
-rw-r--r--apex/appsearch/framework/java/android/app/appsearch/GlobalSearchSession.java128
-rw-r--r--apex/appsearch/framework/java/android/app/appsearch/IAppSearchManager.aidl42
-rw-r--r--apex/appsearch/framework/java/android/app/appsearch/SearchResults.java142
-rw-r--r--apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java79
-rw-r--r--apex/jobscheduler/framework/java/android/app/job/JobInfo.java8
-rw-r--r--apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java22
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/controllers/TimeController.java3
-rw-r--r--cmds/sm/src/com/android/commands/sm/Sm.java26
-rw-r--r--cmds/statsd/OWNERS10
-rw-r--r--cmds/statsd/src/OWNERS6
-rw-r--r--cmds/statsd/src/condition/CombinationConditionTracker.h10
-rw-r--r--cmds/statsd/src/condition/ConditionTracker.h5
-rw-r--r--cmds/statsd/src/condition/ConditionWizard.h6
-rw-r--r--cmds/statsd/src/condition/SimpleConditionTracker.h11
-rw-r--r--cmds/statsd/src/metrics/DurationMetricProducer.cpp74
-rw-r--r--cmds/statsd/src/metrics/DurationMetricProducer.h13
-rw-r--r--cmds/statsd/src/metrics/parsing_utils/metrics_manager_util.cpp12
-rw-r--r--cmds/statsd/tests/e2e/ConfigUpdate_e2e_test.cpp297
-rw-r--r--cmds/statsd/tests/metrics/DurationMetricProducer_test.cpp52
-rw-r--r--cmds/statsd/tests/metrics/parsing_utils/metrics_manager_util_test.cpp5
-rw-r--r--cmds/statsd/tests/statsd_test_util.cpp15
-rw-r--r--cmds/statsd/tests/statsd_test_util.h2
-rw-r--r--core/api/current.txt75
-rw-r--r--core/api/system-current.txt190
-rw-r--r--core/api/test-current.txt2
-rw-r--r--core/java/android/annotation/RequiresFeature.java13
-rw-r--r--core/java/android/app/Activity.java6
-rw-r--r--core/java/android/app/ActivityManager.java20
-rw-r--r--core/java/android/app/ActivityOptions.java118
-rw-r--r--core/java/android/app/ActivityTaskManager.java109
-rw-r--r--core/java/android/app/ActivityThread.java15
-rw-r--r--core/java/android/app/ActivityTransitionState.java12
-rw-r--r--core/java/android/app/AppOpsManager.java2
-rw-r--r--core/java/android/app/ExitTransitionCoordinator.java122
-rw-r--r--core/java/android/app/IActivityTaskManager.aidl13
-rw-r--r--core/java/android/app/IApplicationThread.aidl4
-rw-r--r--core/java/android/app/Notification.java148
-rw-r--r--core/java/android/app/SystemServiceRegistry.java3
-rw-r--r--core/java/android/app/TEST_MAPPING48
-rw-r--r--core/java/android/app/TaskInfo.java15
-rw-r--r--core/java/android/app/admin/DevicePolicyManager.java207
-rw-r--r--core/java/android/app/admin/DevicePolicyManagerInternal.java7
-rw-r--r--core/java/android/app/admin/IDevicePolicyManager.aidl2
-rw-r--r--core/java/android/app/admin/SecurityLog.java19
-rw-r--r--core/java/android/app/admin/SecurityLogTags.logtags3
-rw-r--r--core/java/android/app/people/PeopleSpaceTile.java37
-rw-r--r--core/java/android/bluetooth/BluetoothLeAudio.java451
-rw-r--r--core/java/android/bluetooth/BluetoothProfile.java9
-rw-r--r--core/java/android/content/ContentResolver.java3
-rw-r--r--core/java/android/content/TEST_MAPPING52
-rw-r--r--core/java/android/content/pm/CrossProfileApps.java10
-rw-r--r--core/java/android/content/pm/PackageManager.java5
-rw-r--r--core/java/android/hardware/display/DisplayManager.java55
-rw-r--r--core/java/android/hardware/hdmi/HdmiDeviceInfo.java15
-rw-r--r--core/java/android/inputmethodservice/AbstractInputMethodService.java3
-rw-r--r--core/java/android/inputmethodservice/InputMethodService.java54
-rw-r--r--core/java/android/net/CaptivePortal.java16
-rw-r--r--core/java/android/net/ConnectivityManager.java2
-rw-r--r--core/java/android/net/NetworkProvider.java7
-rw-r--r--core/java/android/os/PowerManager.java2
-rw-r--r--core/java/android/os/VibrationEffect.java3
-rw-r--r--core/java/android/os/storage/StorageManager.java15
-rw-r--r--core/java/android/os/storage/StorageManagerInternal.java44
-rw-r--r--core/java/android/os/storage/VolumeInfo.java15
-rw-r--r--core/java/android/provider/DeviceConfig.java16
-rw-r--r--core/java/android/provider/Settings.java24
-rw-r--r--core/java/android/service/autofill/TEST_MAPPING7
-rw-r--r--core/java/android/service/wallpaper/WallpaperService.java9
-rw-r--r--core/java/android/util/DebugUtils.java20
-rw-r--r--core/java/android/util/imetracing/ImeTracing.java9
-rw-r--r--core/java/android/util/imetracing/ImeTracingClientImpl.java10
-rw-r--r--core/java/android/util/imetracing/ImeTracingServerImpl.java6
-rw-r--r--core/java/android/util/imetracing/InputConnectionHelper.java231
-rw-r--r--core/java/android/view/ContentInfo.java358
-rw-r--r--core/java/android/view/Gravity.java31
-rw-r--r--core/java/android/view/IWindowManager.aidl20
-rw-r--r--core/java/android/view/IWindowSession.aidl13
-rw-r--r--core/java/android/view/InsetsController.java14
-rw-r--r--core/java/android/view/OnReceiveContentListener.java343
-rw-r--r--core/java/android/view/TEST_MAPPING18
-rw-r--r--core/java/android/view/View.java12
-rw-r--r--core/java/android/view/ViewRootImpl.java6
-rw-r--r--core/java/android/view/WindowManager.java16
-rw-r--r--core/java/android/view/WindowlessWindowManager.java7
-rw-r--r--core/java/android/view/autofill/AutofillManager.java8
-rw-r--r--core/java/android/view/autofill/TEST_MAPPING7
-rw-r--r--core/java/android/view/inputmethod/BaseInputConnection.java8
-rw-r--r--core/java/android/view/inputmethod/DumpableInputConnection.java32
-rw-r--r--core/java/android/view/inputmethod/InputMethodManager.java58
-rw-r--r--core/java/android/view/inputmethod/InputMethodSubtype.java3
-rw-r--r--core/java/android/webkit/WebViewFactory.java15
-rw-r--r--core/java/android/widget/Editor.java8
-rw-r--r--core/java/android/widget/NumberPicker.java3
-rw-r--r--core/java/android/widget/SelectionActionModeHelper.java29
-rw-r--r--core/java/android/widget/TextView.java23
-rw-r--r--core/java/android/widget/TextViewOnReceiveContentListener.java29
-rw-r--r--core/java/com/android/internal/inputmethod/CallbackUtils.java52
-rw-r--r--core/java/com/android/internal/inputmethod/Completable.java29
-rw-r--r--core/java/com/android/internal/inputmethod/IInputBindResultResultCallback.aidl23
-rw-r--r--core/java/com/android/internal/inputmethod/ResultCallbacks.java29
-rw-r--r--core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java8
-rw-r--r--core/java/com/android/internal/os/BatteryStatsImpl.java170
-rw-r--r--core/java/com/android/internal/util/FastXmlSerializer.java7
-rw-r--r--core/java/com/android/internal/view/IInputConnectionWrapper.java461
-rw-r--r--core/java/com/android/internal/view/IInputMethodManager.aidl6
-rw-r--r--core/java/com/android/internal/view/InputConnectionWrapper.java75
-rw-r--r--core/java/com/android/internal/widget/EditableInputConnection.java41
-rw-r--r--core/java/com/android/internal/widget/LocalImageResolver.java80
-rw-r--r--core/java/com/android/internal/widget/LockPatternUtils.java9
-rw-r--r--core/java/com/android/internal/widget/LockPatternView.java14
-rw-r--r--core/jni/android_media_MicrophoneInfo.cpp4
-rw-r--r--core/proto/OWNERS18
-rw-r--r--core/proto/android/inputmethodservice/inputmethodservice.proto2
-rw-r--r--core/proto/android/view/inputmethod/inputconnection.proto98
-rw-r--r--core/proto/android/view/inputmethod/inputmethodeditortrace.proto3
-rw-r--r--core/proto/android/view/windowlayoutparams.proto2
-rw-r--r--core/res/AndroidManifest.xml33
-rw-r--r--core/res/res/layout/notification_template_header.xml12
-rw-r--r--core/res/res/layout/notification_template_material_base.xml14
-rw-r--r--core/res/res/values-night/colors.xml3
-rw-r--r--core/res/res/values-night/values.xml8
-rw-r--r--core/res/res/values/colors.xml2
-rw-r--r--core/res/res/values/colors_device_defaults.xml8
-rw-r--r--core/res/res/values/config.xml40
-rw-r--r--core/res/res/values/dimens.xml4
-rw-r--r--core/res/res/values/ids.xml6
-rw-r--r--core/res/res/values/strings.xml9
-rw-r--r--core/res/res/values/symbols.xml14
-rw-r--r--core/res/res/values/themes_device_defaults.xml7
-rw-r--r--core/res/res/xml/config_user_types.xml11
-rw-r--r--core/tests/coretests/src/android/app/people/PeopleSpaceTileTest.java97
-rw-r--r--core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java4
-rw-r--r--core/tests/coretests/src/android/widget/NumberPickerTest.java91
-rw-r--r--core/tests/coretests/src/android/widget/TextViewOnReceiveContentTest.java30
-rw-r--r--core/tests/hdmitests/Android.bp1
-rwxr-xr-xcore/tests/hdmitests/src/android/hardware/hdmi/HdmiDeviceInfoTest.java75
-rw-r--r--data/etc/privapp-permissions-platform.xml1
-rw-r--r--data/etc/services.core.protolog.json6
-rw-r--r--graphics/java/android/graphics/Typeface.java7
-rw-r--r--keystore/java/android/security/AppUriAuthenticationPolicy.java15
-rw-r--r--keystore/java/android/security/IKeyChainService.aidl10
-rw-r--r--libs/WindowManager/Shell/Android.bp3
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/animation/FlingAnimationUtils.java3
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPair.java42
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPairLayout.java63
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPairs.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPairsController.java31
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java39
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutOrganizer.java3
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/letterbox/LetterboxTaskListener.java16
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipController.java48
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java2
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTest.kt2
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt2
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenTest.kt2
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/ExitSplitScreenTest.kt2
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/OpenAppToSplitScreenTest.kt6
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenRotateOneLaunchedAppTest.kt95
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenRotateTwoLaunchedAppTest.kt104
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairLayoutTests.java89
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairTests.java5
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairsControllerTests.java5
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairsPoolTests.java5
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/TestAppPairsController.java5
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java13
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/letterbox/LetterboxTaskListenerTest.java14
-rw-r--r--libs/hwui/Android.bp2
-rw-r--r--libs/hwui/DisplayListOps.in1
-rw-r--r--libs/hwui/RecordingCanvas.cpp28
-rw-r--r--libs/hwui/RecordingCanvas.h6
-rw-r--r--libs/hwui/SaveFlags.h36
-rw-r--r--libs/hwui/VectorDrawable.cpp6
-rw-r--r--libs/hwui/canvas/CanvasFrontend.cpp117
-rw-r--r--libs/hwui/canvas/CanvasFrontend.h200
-rw-r--r--libs/hwui/canvas/CanvasOpRecorder.cpp22
-rw-r--r--libs/hwui/canvas/CanvasOpRecorder.h38
-rw-r--r--libs/hwui/hwui/Canvas.h17
-rw-r--r--libs/hwui/tests/unit/CanvasFrontendTests.cpp213
-rw-r--r--libs/hwui/tests/unit/CanvasOpTests.cpp48
-rw-r--r--libs/hwui/tests/unit/CommonPoolTests.cpp4
-rw-r--r--libs/hwui/tests/unit/RenderNodeDrawableTests.cpp10
-rw-r--r--libs/hwui/tests/unit/RenderNodeTests.cpp2
-rw-r--r--media/java/android/media/metrics/IPlaybackMetricsManager.aidl3
-rw-r--r--media/java/android/media/metrics/PlaybackMetricsManager.java19
-rw-r--r--media/java/android/media/metrics/PlaybackSession.java74
-rw-r--r--media/java/android/media/tv/tuner/Tuner.java2
-rwxr-xr-xpackages/PackageInstaller/src/com/android/packageinstaller/InstallInstalling.java2
-rw-r--r--packages/PackageInstaller/src/com/android/packageinstaller/PackageInstalledNotificationUtils.java8
-rw-r--r--packages/PackageInstaller/src/com/android/packageinstaller/UninstallUninstalling.java3
-rw-r--r--packages/PackageInstaller/src/com/android/packageinstaller/wear/PackageInstallerImpl.java3
-rw-r--r--packages/SettingsLib/res/values-af/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-am/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-ar/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-as/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-az/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-b+sr+Latn/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-be/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-bg/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-bn/strings.xml17
-rw-r--r--packages/SettingsLib/res/values-bs/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-ca/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-cs/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-da/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-de/strings.xml12
-rw-r--r--packages/SettingsLib/res/values-el/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-es-rUS/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-es/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-et/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-eu/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-fa/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-fi/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-fr-rCA/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-fr/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-gl/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-gu/strings.xml12
-rw-r--r--packages/SettingsLib/res/values-hi/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-hr/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-hu/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-hy/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-in/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-is/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-it/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-iw/strings.xml12
-rw-r--r--packages/SettingsLib/res/values-ja/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-kk/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-km/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-kn/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-ko/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-ky/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-lo/strings.xml9
-rw-r--r--packages/SettingsLib/res/values-lt/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-lv/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-mk/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-ml/strings.xml12
-rw-r--r--packages/SettingsLib/res/values-mn/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-mr/strings.xml12
-rw-r--r--packages/SettingsLib/res/values-ms/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-my/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-nb/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-ne/strings.xml12
-rw-r--r--packages/SettingsLib/res/values-nl/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-or/strings.xml12
-rw-r--r--packages/SettingsLib/res/values-pa/strings.xml12
-rw-r--r--packages/SettingsLib/res/values-pl/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-ro/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-ru/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-si/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-sk/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-sl/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-sq/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-sr/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-sv/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-sw/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-ta/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-te/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-th/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-tl/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-tr/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-uk/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-ur/strings.xml12
-rw-r--r--packages/SettingsLib/res/values-uz/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-vi/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-zh-rCN/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-zh-rHK/strings.xml7
-rw-r--r--packages/SettingsLib/res/values-zh-rTW/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-zu/strings.xml3
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtilsInternal.java27
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java5
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaDevice.java10
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothEventManagerTest.java83
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/BluetoothMediaDeviceTest.java14
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java11
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/WifiSoftApConfigChangedNotifier.java3
-rw-r--r--packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java5
-rw-r--r--packages/Shell/AndroidManifest.xml1
-rw-r--r--packages/SystemUI/AndroidManifest.xml8
-rw-r--r--packages/SystemUI/OWNERS22
-rw-r--r--packages/SystemUI/res-keyguard/color/notification_background_dimmed_color.xml (renamed from packages/SystemUI/res/color/background_protect_secondary.xml)5
-rw-r--r--packages/SystemUI/res-keyguard/drawable/circle_white.xml19
-rw-r--r--packages/SystemUI/res-keyguard/drawable/kg_emergency_button_background.xml4
-rw-r--r--packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml2
-rw-r--r--packages/SystemUI/res-keyguard/layout/keyguard_password_view.xml6
-rw-r--r--packages/SystemUI/res-keyguard/layout/keyguard_pin_view.xml3
-rw-r--r--packages/SystemUI/res-keyguard/layout/keyguard_sim_pin_view.xml1
-rw-r--r--packages/SystemUI/res-keyguard/layout/keyguard_sim_puk_view.xml1
-rw-r--r--packages/SystemUI/res-keyguard/values/styles.xml35
-rw-r--r--packages/SystemUI/res/color/pin_delete_color.xml2
-rw-r--r--packages/SystemUI/res/color/pin_divider_color.xml2
-rw-r--r--packages/SystemUI/res/color/qs_background_dark.xml2
-rw-r--r--packages/SystemUI/res/drawable/notification_guts_bg.xml2
-rw-r--r--packages/SystemUI/res/drawable/notification_material_bg.xml2
-rw-r--r--packages/SystemUI/res/drawable/notification_material_bg_dim.xml2
-rw-r--r--packages/SystemUI/res/layout/app_ops_info.xml2
-rw-r--r--packages/SystemUI/res/layout/disabled_udfps_view.xml24
-rw-r--r--packages/SystemUI/res/layout/feedback_info.xml2
-rw-r--r--packages/SystemUI/res/layout/global_actions_grid_v2.xml58
-rw-r--r--packages/SystemUI/res/layout/global_actions_lock_view.xml35
-rw-r--r--packages/SystemUI/res/layout/global_actions_view.xml52
-rw-r--r--packages/SystemUI/res/layout/global_screenshot.xml14
-rw-r--r--packages/SystemUI/res/layout/global_screenshot_static.xml19
-rw-r--r--packages/SystemUI/res/layout/notification_conversation_info.xml2
-rw-r--r--packages/SystemUI/res/layout/notification_guts.xml3
-rw-r--r--packages/SystemUI/res/layout/notification_snooze.xml2
-rw-r--r--packages/SystemUI/res/layout/quick_settings_footer.xml10
-rw-r--r--packages/SystemUI/res/layout/quick_settings_footer_dialog_parental_controls.xml4
-rw-r--r--packages/SystemUI/res/layout/status_bar_expanded.xml8
-rw-r--r--packages/SystemUI/res/layout/status_bar_notification_section_header.xml1
-rw-r--r--packages/SystemUI/res/layout/tv_notification_item.xml39
-rw-r--r--packages/SystemUI/res/layout/tv_notification_panel.xml53
-rw-r--r--packages/SystemUI/res/layout/udfps_view.xml15
-rw-r--r--packages/SystemUI/res/values-night/colors.xml11
-rw-r--r--packages/SystemUI/res/values-television/config.xml3
-rw-r--r--packages/SystemUI/res/values/colors.xml9
-rw-r--r--packages/SystemUI/res/values/colors_tv.xml3
-rw-r--r--packages/SystemUI/res/values/dimens_tv.xml (renamed from packages/SystemUI/res/drawable/qs_navbar_scrim.xml)16
-rw-r--r--packages/SystemUI/res/values/strings_tv.xml2
-rw-r--r--packages/SystemUI/res/values/styles.xml9
-rw-r--r--packages/SystemUI/res/values/styles_tv.xml8
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java44
-rw-r--r--packages/SystemUI/src/com/android/keyguard/DisabledUdfpsController.java155
-rw-r--r--packages/SystemUI/src/com/android/keyguard/DisabledUdfpsView.java89
-rw-r--r--packages/SystemUI/src/com/android/keyguard/EmergencyButton.java12
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java9
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java11
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java14
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardMessageArea.java8
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardMessageAreaController.java7
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java21
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java12
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java30
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java6
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java28
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipperController.java9
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java2
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardSimPukViewController.java2
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java10
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java8
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java3
-rw-r--r--packages/SystemUI/src/com/android/keyguard/NumPadKey.java22
-rw-r--r--packages/SystemUI/src/com/android/keyguard/PasswordTextView.java14
-rw-r--r--packages/SystemUI/src/com/android/keyguard/TextInterpolator.kt265
-rw-r--r--packages/SystemUI/src/com/android/systemui/SystemUIFactory.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java18
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/BrightLineFalsingManager.java (renamed from packages/SystemUI/src/com/android/systemui/classifier/brightline/BrightLineFalsingManager.java)62
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/DiagonalClassifier.java (renamed from packages/SystemUI/src/com/android/systemui/classifier/brightline/DiagonalClassifier.java)8
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/DistanceClassifier.java (renamed from packages/SystemUI/src/com/android/systemui/classifier/brightline/DistanceClassifier.java)8
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/DoubleTapClassifier.java (renamed from packages/SystemUI/src/com/android/systemui/classifier/brightline/DoubleTapClassifier.java)14
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/FalsingClassifier.java (renamed from packages/SystemUI/src/com/android/systemui/classifier/brightline/FalsingClassifier.java)6
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/FalsingDataProvider.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/FalsingModule.java53
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/PointerCountClassifier.java (renamed from packages/SystemUI/src/com/android/systemui/classifier/brightline/PointerCountClassifier.java)9
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/ProximityClassifier.java (renamed from packages/SystemUI/src/com/android/systemui/classifier/brightline/ProximityClassifier.java)10
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/SingleTapClassifier.java (renamed from packages/SystemUI/src/com/android/systemui/classifier/brightline/SingleTapClassifier.java)13
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/TimeLimitedMotionEventBuffer.java (renamed from packages/SystemUI/src/com/android/systemui/classifier/brightline/TimeLimitedMotionEventBuffer.java)4
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/TypeClassifier.java (renamed from packages/SystemUI/src/com/android/systemui/classifier/brightline/TypeClassifier.java)7
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/ZigZagClassifier.java (renamed from packages/SystemUI/src/com/android/systemui/classifier/brightline/ZigZagClassifier.java)8
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/GlobalModule.java18
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/qualifiers/TestHarness.java34
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/util/BurnInHelper.kt9
-rw-r--r--packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.java24
-rw-r--r--packages/SystemUI/src/com/android/systemui/people/PeopleSpaceTileView.java16
-rw-r--r--packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java47
-rw-r--r--packages/SystemUI/src/com/android/systemui/people/widget/LaunchConversationActivity.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetProvider.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetRemoteViewsFactory.java32
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java24
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java153
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java148
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java19
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationGroupingUtil.java (renamed from packages/SystemUI/src/com/android/systemui/statusbar/NotificationHeaderUtil.java)226
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/AnimatableProperty.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotifications.kt72
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/InstantAppNotifier.java17
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/MediaNotificationProcessor.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGuts.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageResolver.java18
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java17
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenLockIconController.java41
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java55
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java61
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/tv/notifications/TvNotificationAdapter.java111
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/tv/notifications/TvNotificationHandler.java115
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/tv/notifications/TvNotificationPanel.java (renamed from packages/SystemUI/src/com/android/systemui/statusbar/tv/TvNotificationPanel.java)22
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/tv/notifications/TvNotificationPanelActivity.java110
-rw-r--r--packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayApplier.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/tv/TvSystemUIBinder.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java18
-rw-r--r--packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java6
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java7
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/TextAnimatorTest.kt5
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/TextInterpolatorTest.kt69
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineClassifierTest.java164
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/classifier/DiagonalClassifierTest.java (renamed from packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/DiagonalClassifierTest.java)6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/classifier/DistanceClassifierTest.java (renamed from packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/DistanceClassifierTest.java)6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/classifier/DoubleTapClassifierTest.java (renamed from packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/DoubleTapClassifierTest.java)7
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/classifier/PointerCountClassifierTest.java (renamed from packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/PointerCountClassifierTest.java)6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/classifier/ProximityClassifierTest.java (renamed from packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/ProximityClassifierTest.java)6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/classifier/SingleTapClassifierTest.java (renamed from packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/SingleTapClassifierTest.java)7
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/classifier/TimeLimitedMotionEventBufferTest.java (renamed from packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/TimeLimitedMotionEventBufferTest.java)4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/classifier/TypeClassifierTest.java (renamed from packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/TypeClassifierTest.java)7
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/classifier/ZigZagClassifierTest.java (renamed from packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/ZigZagClassifierTest.java)5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/dock/DockManagerFake.java7
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/people/widget/PeopleSpaceWidgetManagerTest.java5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java26
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NoManSimulator.java6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageResolverTest.java28
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java8
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java17
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java19
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java4
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java9
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java25
-rw-r--r--services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandler.java112
-rw-r--r--services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java18
-rw-r--r--services/accessibility/java/com/android/server/accessibility/magnification/MagnificationGestureHandler.java108
-rw-r--r--services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java92
-rw-r--r--services/autofill/java/com/android/server/autofill/TEST_MAPPING15
-rw-r--r--services/core/Android.bp8
-rw-r--r--services/core/java/com/android/server/ConnectivityService.java106
-rw-r--r--services/core/java/com/android/server/PackageWatchdog.java32
-rw-r--r--services/core/java/com/android/server/SensorPrivacyService.java4
-rw-r--r--services/core/java/com/android/server/StorageManagerService.java240
-rw-r--r--services/core/java/com/android/server/SystemUpdateManagerService.java2
-rw-r--r--services/core/java/com/android/server/TEST_MAPPING4
-rw-r--r--services/core/java/com/android/server/TestNetworkService.java45
-rw-r--r--services/core/java/com/android/server/accounts/AccountManagerBackupHelper.java14
-rw-r--r--services/core/java/com/android/server/adb/AdbDebuggingManager.java8
-rw-r--r--services/core/java/com/android/server/am/ActiveServices.java31
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java28
-rw-r--r--services/core/java/com/android/server/am/SettingsToPropertiesMapper.java2
-rw-r--r--services/core/java/com/android/server/appop/AppOpsService.java110
-rw-r--r--services/core/java/com/android/server/appop/HistoricalRegistry.java76
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java53
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/BiometricUserState.java8
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/FaceUserState.java18
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java30
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintUserState.java23
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java30
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java26
-rw-r--r--services/core/java/com/android/server/connectivity/Vpn.java240
-rw-r--r--services/core/java/com/android/server/content/SyncStorageEngine.java104
-rw-r--r--services/core/java/com/android/server/display/AmbientBrightnessStatsTracker.java10
-rw-r--r--services/core/java/com/android/server/display/BrightnessTracker.java78
-rw-r--r--services/core/java/com/android/server/display/DisplayModeDirector.java668
-rw-r--r--services/core/java/com/android/server/display/PersistentDataStore.java34
-rw-r--r--services/core/java/com/android/server/graphics/fonts/FontManagerInternal.java27
-rw-r--r--services/core/java/com/android/server/graphics/fonts/FontManagerService.java85
-rw-r--r--services/core/java/com/android/server/hdmi/CecMessageBuffer.java103
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiCecConfig.java134
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java5
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiControlService.java75
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiUtils.java12
-rw-r--r--services/core/java/com/android/server/hdmi/SetArcTransmissionStateAction.java6
-rw-r--r--services/core/java/com/android/server/input/ConfigurationProcessor.java14
-rw-r--r--services/core/java/com/android/server/input/InputManagerService.java15
-rw-r--r--services/core/java/com/android/server/input/PersistentDataStore.java10
-rw-r--r--services/core/java/com/android/server/inputmethod/AdditionalSubtypeUtils.java31
-rw-r--r--services/core/java/com/android/server/inputmethod/InputMethodManagerService.java117
-rw-r--r--services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java30
-rw-r--r--services/core/java/com/android/server/integrity/parser/RuleMetadataParser.java5
-rw-r--r--services/core/java/com/android/server/integrity/serializer/RuleMetadataSerializer.java8
-rw-r--r--services/core/java/com/android/server/location/gnss/GnssLocationProvider.java18
-rw-r--r--services/core/java/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotDeserializer.java27
-rw-r--r--services/core/java/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotSchema.java2
-rw-r--r--services/core/java/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotSerializer.java31
-rw-r--r--services/core/java/com/android/server/media/MediaKeyDispatcher.java3
-rw-r--r--services/core/java/com/android/server/media/MediaServerUtils.java19
-rw-r--r--services/core/java/com/android/server/media/MediaSessionRecord.java3
-rw-r--r--services/core/java/com/android/server/media/MediaSessionService.java30
-rw-r--r--services/core/java/com/android/server/media/SessionPolicyProvider.java3
-rw-r--r--services/core/java/com/android/server/media/metrics/PlaybackMetricsManagerService.java15
-rw-r--r--services/core/java/com/android/server/notification/ConditionProviders.java3
-rw-r--r--services/core/java/com/android/server/notification/ManagedServices.java28
-rwxr-xr-xservices/core/java/com/android/server/notification/NotificationManagerService.java66
-rw-r--r--services/core/java/com/android/server/notification/PreferencesHelper.java128
-rw-r--r--services/core/java/com/android/server/notification/SnoozeHelper.java29
-rw-r--r--services/core/java/com/android/server/notification/ZenModeHelper.java6
-rw-r--r--services/core/java/com/android/server/om/OverlayManagerSettings.java24
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java245
-rw-r--r--services/core/java/com/android/server/pm/PackageProperty.java2
-rw-r--r--services/core/java/com/android/server/pm/PreferredComponent.java31
-rw-r--r--services/core/java/com/android/server/pm/PreferredIntentResolver.java21
-rw-r--r--services/core/java/com/android/server/pm/Settings.java137
-rw-r--r--services/core/java/com/android/server/pm/ShareTargetInfo.java9
-rw-r--r--services/core/java/com/android/server/pm/ShortcutLauncher.java14
-rw-r--r--services/core/java/com/android/server/pm/ShortcutPackage.java22
-rw-r--r--services/core/java/com/android/server/pm/ShortcutPackageInfo.java7
-rw-r--r--services/core/java/com/android/server/pm/ShortcutPackageItem.java18
-rw-r--r--services/core/java/com/android/server/pm/ShortcutService.java76
-rw-r--r--services/core/java/com/android/server/pm/ShortcutUser.java9
-rw-r--r--services/core/java/com/android/server/pm/UserManagerService.java124
-rw-r--r--services/core/java/com/android/server/pm/UserRestrictionsUtils.java18
-rw-r--r--services/core/java/com/android/server/pm/UserTypeDetails.java3
-rw-r--r--services/core/java/com/android/server/pm/UserTypeFactory.java159
-rw-r--r--services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java16
-rw-r--r--services/core/java/com/android/server/pm/permission/PermissionManagerService.java436
-rw-r--r--services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java52
-rw-r--r--services/core/java/com/android/server/power/batterysaver/BatterySaverController.java5
-rw-r--r--services/core/java/com/android/server/power/batterysaver/BatterySaverLocationPlugin.java65
-rw-r--r--services/core/java/com/android/server/powerstats/PowerStatsDataStorage.java24
-rw-r--r--services/core/java/com/android/server/role/RoleUserState.java12
-rw-r--r--services/core/java/com/android/server/storage/CacheQuotaStrategy.java23
-rw-r--r--services/core/java/com/android/server/timedetector/TimeDetectorStrategyCallbackImpl.java39
-rw-r--r--services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java14
-rw-r--r--services/core/java/com/android/server/timezone/PackageStatusStorage.java10
-rw-r--r--services/core/java/com/android/server/tv/PersistentDataStore.java11
-rw-r--r--services/core/java/com/android/server/tv/tunerresourcemanager/UseCasePriorityHints.java13
-rw-r--r--services/core/java/com/android/server/uri/UriGrantsManagerService.java22
-rw-r--r--services/core/java/com/android/server/utils/DeviceConfigInterface.java (renamed from services/core/java/com/android/server/wm/utils/DeviceConfigInterface.java)13
-rw-r--r--services/core/java/com/android/server/utils/Snappable.java35
-rw-r--r--services/core/java/com/android/server/utils/Snapshots.java133
-rw-r--r--services/core/java/com/android/server/utils/WatchableImpl.java33
-rw-r--r--services/core/java/com/android/server/utils/WatchedArrayMap.java43
-rw-r--r--services/core/java/com/android/server/utils/WatchedSparseArray.java42
-rw-r--r--services/core/java/com/android/server/utils/WatchedSparseBooleanArray.java47
-rw-r--r--services/core/java/com/android/server/utils/eventlog/LocalEventLog.java3
-rw-r--r--services/core/java/com/android/server/wallpaper/WallpaperManagerService.java77
-rw-r--r--services/core/java/com/android/server/wm/ActivityMetricsLogger.java14
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java283
-rw-r--r--services/core/java/com/android/server/wm/ActivityStarter.java53
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskManagerService.java75
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskSupervisor.java119
-rw-r--r--services/core/java/com/android/server/wm/AppWarnings.java2
-rw-r--r--services/core/java/com/android/server/wm/CompatModePackages.java16
-rw-r--r--services/core/java/com/android/server/wm/ConfigurationContainer.java8
-rw-r--r--services/core/java/com/android/server/wm/DisplayArea.java6
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java131
-rw-r--r--services/core/java/com/android/server/wm/DisplayPolicy.java82
-rw-r--r--services/core/java/com/android/server/wm/DisplayWindowSettingsProvider.java285
-rw-r--r--services/core/java/com/android/server/wm/HighRefreshRateDenylist.java2
-rw-r--r--services/core/java/com/android/server/wm/ImpressionAttestationController.java86
-rw-r--r--services/core/java/com/android/server/wm/InputMonitor.java4
-rw-r--r--services/core/java/com/android/server/wm/InsetsPolicy.java4
-rw-r--r--services/core/java/com/android/server/wm/InsetsStateController.java5
-rw-r--r--services/core/java/com/android/server/wm/KeyguardController.java6
-rw-r--r--services/core/java/com/android/server/wm/LaunchParamsController.java2
-rw-r--r--services/core/java/com/android/server/wm/LaunchParamsPersister.java43
-rw-r--r--services/core/java/com/android/server/wm/LockTaskController.java6
-rw-r--r--services/core/java/com/android/server/wm/RecentTasks.java6
-rw-r--r--services/core/java/com/android/server/wm/RecentsAnimation.java50
-rw-r--r--services/core/java/com/android/server/wm/RecentsAnimationController.java2
-rw-r--r--services/core/java/com/android/server/wm/ResetTargetTaskHelper.java4
-rw-r--r--services/core/java/com/android/server/wm/RootWindowContainer.java293
-rw-r--r--services/core/java/com/android/server/wm/RunningTasks.java2
-rw-r--r--services/core/java/com/android/server/wm/Session.java13
-rw-r--r--services/core/java/com/android/server/wm/Task.java139
-rw-r--r--services/core/java/com/android/server/wm/TaskChangeNotificationController.java2
-rw-r--r--services/core/java/com/android/server/wm/TaskDisplayArea.java451
-rw-r--r--services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java4
-rw-r--r--services/core/java/com/android/server/wm/TaskOrganizerController.java6
-rw-r--r--services/core/java/com/android/server/wm/TaskPersister.java34
-rw-r--r--services/core/java/com/android/server/wm/WallpaperController.java3
-rw-r--r--services/core/java/com/android/server/wm/WindowContainer.java20
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerConstants.java2
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java104
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java12
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java361
-rw-r--r--services/java/com/android/server/SystemServer.java11
-rw-r--r--services/people/java/com/android/server/people/PeopleService.java9
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/appop/AppOpsUpgradeTest.java4
-rw-r--r--services/tests/servicestests/Android.bp3
-rw-r--r--services/tests/servicestests/res/xml/usertypes_test_full.xml3
-rw-r--r--services/tests/servicestests/res/xml/usertypes_test_profile.xml5
-rw-r--r--services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java30
-rw-r--r--services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandlerTest.java7
-rw-r--r--services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java33
-rw-r--r--services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationGestureHandlerTest.java4
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java30
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java94
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/FactoryResetProtectionPolicyTest.java8
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/SystemUpdatePolicyTest.java6
-rw-r--r--services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java417
-rw-r--r--services/tests/servicestests/src/com/android/server/hdmi/HdmiCecConfigTest.java111
-rw-r--r--services/tests/servicestests/src/com/android/server/om/OverlayManagerSettingsTests.java6
-rw-r--r--services/tests/servicestests/src/com/android/server/people/PeopleServiceTest.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/PackageInstallerSessionTest.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/PackageSignaturesTest.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java6
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserInfoTest.java88
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserTypeTest.java47
-rw-r--r--services/tests/servicestests/src/com/android/server/search/SearchablesTest.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/storage/CacheQuotaStrategyTest.java6
-rw-r--r--services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java74
-rw-r--r--services/tests/servicestests/src/com/android/server/utils/WatchableTester.java87
-rw-r--r--services/tests/servicestests/src/com/android/server/utils/WatcherTest.java375
-rw-r--r--services/tests/servicestests/utils/com/android/server/testutils/FakeDeviceConfigInterface.java (renamed from services/tests/wmtests/src/com/android/server/wm/utils/FakeDeviceConfigInterface.java)16
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java34
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java18
-rwxr-xr-xservices/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java57
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java34
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java20
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java6
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java52
-rw-r--r--services/tests/wmtests/AndroidManifest.xml2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java70
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java41
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java107
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityStartControllerTests.java8
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java32
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ConfigurationContainerTests.java24
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayAreaGroupTest.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayAreaPolicyTests.java10
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayAreaTest.java8
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java17
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java3
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTestsBase.java8
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsProviderTests.java81
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/HighRefreshRateDenylistTest.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java6
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java6
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java28
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java24
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java98
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ScreenDecorWindowTests.java382
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java4
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java3
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java34
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java4
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java20
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java8
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowManagerConstantsTest.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowManagerSettingsTests.java75
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java8
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java32
-rw-r--r--services/usb/java/com/android/server/usb/UsbDeviceManager.java6
-rw-r--r--telephony/java/android/telephony/CallForwardingInfo.java2
-rw-r--r--telephony/java/android/telephony/CarrierConfigManager.java50
-rw-r--r--telephony/java/android/telephony/TelephonyManager.java3
-rw-r--r--telephony/java/android/telephony/ims/DelegateMessageCallback.java2
-rw-r--r--telephony/java/android/telephony/ims/DelegateRegistrationState.java54
-rw-r--r--telephony/java/android/telephony/ims/DelegateRequest.java6
-rw-r--r--telephony/java/android/telephony/ims/DelegateStateCallback.java15
-rw-r--r--telephony/java/android/telephony/ims/FeatureTagState.java10
-rw-r--r--telephony/java/android/telephony/ims/ImsCallProfile.java76
-rw-r--r--telephony/java/android/telephony/ims/ImsExternalCallState.java6
-rw-r--r--telephony/java/android/telephony/ims/ImsSsData.java6
-rw-r--r--telephony/java/android/telephony/ims/RcsContactUceCapability.java13
-rw-r--r--telephony/java/android/telephony/ims/SipDelegateConnection.java5
-rw-r--r--telephony/java/android/telephony/ims/SipDelegateImsConfiguration.java55
-rw-r--r--telephony/java/android/telephony/ims/SipDelegateManager.java24
-rw-r--r--telephony/java/android/telephony/ims/SipMessage.java26
-rw-r--r--telephony/java/android/telephony/ims/aidl/ISipDelegate.aidl2
-rw-r--r--telephony/java/android/telephony/ims/aidl/ISubscribeResponseCallback.aidl2
-rw-r--r--telephony/java/android/telephony/ims/aidl/RcsSubscribeResponseAidlWrapper.java4
-rw-r--r--telephony/java/android/telephony/ims/aidl/SipDelegateAidlWrapper.java11
-rw-r--r--telephony/java/android/telephony/ims/aidl/SipDelegateConnectionAidlWrapper.java2
-rw-r--r--telephony/java/android/telephony/ims/stub/DelegateConnectionMessageCallback.java4
-rw-r--r--telephony/java/android/telephony/ims/stub/DelegateConnectionStateCallback.java2
-rw-r--r--telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java3
-rw-r--r--telephony/java/android/telephony/ims/stub/RcsCapabilityExchangeImplBase.java2
-rw-r--r--telephony/java/android/telephony/ims/stub/SipDelegate.java4
-rw-r--r--telephony/java/android/telephony/ims/stub/SipTransportImplBase.java9
-rw-r--r--telephony/java/com/android/internal/telephony/ITelephony.aidl5
-rw-r--r--tests/BootImageProfileTest/TEST_MAPPING7
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt2
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt2
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt3
-rw-r--r--tests/RollbackTest/RollbackTest/AndroidManifest.xml2
-rw-r--r--tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java5
-rw-r--r--tests/StagedInstallTest/app/AndroidManifest.xml2
-rw-r--r--tests/net/common/java/android/net/OemNetworkPreferencesTest.java8
-rw-r--r--tests/net/java/com/android/server/ConnectivityServiceTest.java164
-rw-r--r--tests/net/java/com/android/server/connectivity/VpnTest.java136
-rw-r--r--tools/aapt2/cmd/Link.h5
-rw-r--r--tools/aapt2/link/ManifestFixer.cpp10
-rw-r--r--tools/aapt2/link/ManifestFixer.h4
-rw-r--r--tools/aapt2/link/ManifestFixer_test.cpp60
-rw-r--r--tools/codegen/src/com/android/codegen/ClassPrinter.kt1
-rw-r--r--tools/codegen/src/com/android/codegen/SharedConstants.kt2
-rw-r--r--tools/processors/intdef_mappings/src/android/processor/IntDefProcessor.kt13
-rw-r--r--wifi/Android.bp2
-rw-r--r--wifi/aidl-export/android/net/wifi/CoexUnsafeChannel.aidl19
-rw-r--r--wifi/api/current.txt1
-rw-r--r--wifi/api/system-current.txt34
-rw-r--r--wifi/java/android/net/wifi/CoexUnsafeChannel.java176
-rw-r--r--wifi/java/android/net/wifi/EasyConnectStatusCallback.java19
-rw-r--r--wifi/java/android/net/wifi/ICoexCallback.aidl (renamed from services/wifi/java/android/net/wifi/WifiApiServiceInfo.aidl)13
-rw-r--r--wifi/java/android/net/wifi/IDppCallback.aidl6
-rw-r--r--wifi/java/android/net/wifi/IWifiManager.aidl15
-rw-r--r--wifi/java/android/net/wifi/WifiManager.java372
-rw-r--r--wifi/tests/Android.bp3
-rw-r--r--wifi/tests/src/android/net/wifi/CoexUnsafeChannelTest.java97
-rw-r--r--wifi/tests/src/android/net/wifi/EasyConnectStatusCallbackTest.java6
-rw-r--r--wifi/tests/src/android/net/wifi/WifiManagerTest.java147
713 files changed, 16755 insertions, 7889 deletions
diff --git a/apct-tests/perftests/inputmethod/src/android/inputmethod/ImePerfTest.java b/apct-tests/perftests/inputmethod/src/android/inputmethod/ImePerfTest.java
index 303c667351d1..2b7af2f0a11e 100644
--- a/apct-tests/perftests/inputmethod/src/android/inputmethod/ImePerfTest.java
+++ b/apct-tests/perftests/inputmethod/src/android/inputmethod/ImePerfTest.java
@@ -23,11 +23,14 @@ import static android.view.WindowInsetsAnimation.Callback.DISPATCH_MODE_STOP;
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+import static org.junit.Assert.assertTrue;
+
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.inputmethodservice.InputMethodService;
import android.os.ParcelFileDescriptor;
+import android.os.Process;
import android.os.SystemClock;
import android.perftests.utils.ManualBenchmarkState;
import android.perftests.utils.ManualBenchmarkState.ManualBenchmarkTest;
@@ -88,7 +91,7 @@ public class ImePerfTest extends ImePerfTestBase
"ISC.onPostLayout"
};
- /** IMF show methods to log in trace. */
+ /** IMF show methods to log in trace. */
private String[] mShowMethods = {
"IC.showRequestFromIme",
"IC.showRequestFromApi",
@@ -99,7 +102,23 @@ public class ImePerfTest extends ImePerfTestBase
"IMMS.showSoftInput",
"IMS.showSoftInput",
"IMS.startInput",
- "WMS.showImePostLayout"
+ "WMS.showImePostLayout",
+ "IMS.updateFullscreenMode",
+ "IMS.onComputeInsets",
+ "IMS.showWindow"
+ };
+
+ /** IMF show methods to log in trace. */
+ private String[] mShowMethodsCold = {
+ "IMS.bindInput",
+ "IMS.initializeInternal",
+ "IMS.restartInput",
+ "IMS.onCreate",
+ "IMS.initSoftInputWindow",
+ "IMS.resetStateForNewConfiguration",
+ "IMMS.onServiceConnected",
+ "IMMS.sessionCreated",
+ "IMMS.startInputOrWindowGainedFocus"
};
/** IMF hide lifecycle methods to log in trace. */
@@ -163,6 +182,7 @@ public class ImePerfTest extends ImePerfTestBase
public static class BaselineIme extends InputMethodService {
public static final int HEIGHT_DP = 100;
+ private static int sPid;
@Override
public View onCreateInputView() {
@@ -173,9 +193,14 @@ public class ImePerfTest extends ImePerfTestBase
view.setPadding(0, 0, 0, 0);
view.addView(inner, new FrameLayout.LayoutParams(MATCH_PARENT, height));
inner.setBackgroundColor(0xff01fe10); // green
+ sPid = Process.myPid();
return view;
}
+ static int getPid() {
+ return sPid;
+ }
+
static ComponentName getName(Context context) {
return new ComponentName(context, BaselineIme.class);
}
@@ -188,8 +213,8 @@ public class ImePerfTest extends ImePerfTestBase
flags = StatsReport.FLAG_ITERATION | StatsReport.FLAG_MEAN
| StatsReport.FLAG_MIN | StatsReport.FLAG_MAX
| StatsReport.FLAG_COEFFICIENT_VAR))
- public void testShowIme() throws Throwable {
- testShowOrHideIme(true /* show */);
+ public void testShowImeWarm() throws Throwable {
+ testShowOrHideImeWarm(true /* show */);
}
@Test
@@ -200,10 +225,65 @@ public class ImePerfTest extends ImePerfTestBase
| StatsReport.FLAG_MIN | StatsReport.FLAG_MAX
| StatsReport.FLAG_COEFFICIENT_VAR))
public void testHideIme() throws Throwable {
- testShowOrHideIme(false /* show */);
+ testShowOrHideImeWarm(false /* show */);
+ }
+
+ @Test
+ @ManualBenchmarkTest(
+ targetTestDurationNs = 10 * TIME_1_S_IN_NS,
+ statsReport = @StatsReport(
+ flags = StatsReport.FLAG_ITERATION | StatsReport.FLAG_MEAN
+ | StatsReport.FLAG_MIN | StatsReport.FLAG_MAX
+ | StatsReport.FLAG_COEFFICIENT_VAR))
+ public void testShowImeCold() throws Throwable {
+ mTraceMethods = new TraceMarkParser(
+ buildArray(mCommonMethods, mShowMethods, mShowMethodsCold));
+
+ final ManualBenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ state.setCustomizedIterations(getProfilingIterations(), this);
+ if (state.isWarmingUp()) {
+ // we don't need to warmup for cold start.
+ return;
+ }
+
+ long measuredTimeNs = 0;
+ while (state.keepRunning(measuredTimeNs)) {
+ killBaselineIme();
+ try (ImeSession imeSession = new ImeSession(BaselineIme.getName(
+ getInstrumentation().getContext()))) {
+ final AtomicReference<CountDownLatch> latchStart = new AtomicReference<>();
+ final Activity activity = getActivityWithFocus();
+
+ setImeListener(activity, latchStart, null /* latchEnd */);
+ latchStart.set(new CountDownLatch(1));
+
+ if (!mIsTraceStarted) {
+ startAsyncAtrace();
+ }
+
+ final WindowInsetsController controller =
+ activity.getWindow().getDecorView().getWindowInsetsController();
+ AtomicLong startTime = new AtomicLong();
+ activity.runOnUiThread(() -> {
+ startTime.set(SystemClock.elapsedRealtimeNanos());
+ controller.show(WindowInsets.Type.ime());
+ });
+
+ measuredTimeNs = waitForAnimationStart(latchStart, startTime);
+ mActivityRule.finishActivity();
+ }
+ }
+ stopAsyncAtrace();
+ addResultToState(state);
+ }
+
+ private void killBaselineIme() {
+ assertTrue("PID of test and IME can't be same",
+ Process.myPid() != BaselineIme.getPid());
+ Process.killProcess(BaselineIme.getPid());
}
- private void testShowOrHideIme(final boolean show) throws Throwable {
+ private void testShowOrHideImeWarm(final boolean show) throws Throwable {
mTraceMethods = new TraceMarkParser(buildArray(
mCommonMethods, show ? mShowMethods : mHideMethods));
final ManualBenchmarkState state = mPerfStatusReporter.getBenchmarkState();
diff --git a/apex/appsearch/framework/java/android/app/appsearch/AppSearchManager.java b/apex/appsearch/framework/java/android/app/appsearch/AppSearchManager.java
index e57359fbf50e..5fd45eadbda9 100644
--- a/apex/appsearch/framework/java/android/app/appsearch/AppSearchManager.java
+++ b/apex/appsearch/framework/java/android/app/appsearch/AppSearchManager.java
@@ -141,6 +141,25 @@ public class AppSearchManager {
}
/**
+ * Creates a new {@link GlobalSearchSession}.
+ *
+ * <p>This process requires an AppSearch native indexing file system for each user. If it's not
+ * created for this user, the initialization process will create one under user's directory.
+ *
+ * @param executor Executor on which to invoke the callback.
+ * @param callback The {@link AppSearchResult}&lt;{@link GlobalSearchSession}&gt; of
+ * performing this operation. Or a {@link AppSearchResult} with failure
+ * reason code and error information.
+ */
+ public void createGlobalSearchSession(
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull Consumer<AppSearchResult<GlobalSearchSession>> callback) {
+ Objects.requireNonNull(executor);
+ Objects.requireNonNull(callback);
+ GlobalSearchSession.createGlobalSearchSession(mService, executor, callback);
+ }
+
+ /**
* Sets the schema being used by documents provided to the {@link #putDocuments} method.
*
* <p>The schema provided here is compared to the stored copy of the schema previously supplied
@@ -383,22 +402,26 @@ public class AppSearchManager {
@NonNull String queryExpression, @NonNull SearchSpec searchSpec) {
// TODO(b/146386470): Transmit the result documents as a RemoteStream instead of sending
// them in one big list.
- AndroidFuture<AppSearchResult> searchResultsFuture = new AndroidFuture<>();
+ AndroidFuture<AppSearchResult> future = new AndroidFuture<>();
try {
- mService.query(DEFAULT_DATABASE_NAME, queryExpression,
- searchSpec.getBundle(), searchResultsFuture);
+ mService.query(DEFAULT_DATABASE_NAME, queryExpression, searchSpec.getBundle(),
+ new IAppSearchResultCallback.Stub() {
+ public void onResult(AppSearchResult result) {
+ future.complete(result);
+ }
+ });
+ AppSearchResult<Bundle> bundleResult = getFutureOrThrow(future);
+ if (!bundleResult.isSuccess()) {
+ return AppSearchResult.newFailedResult(bundleResult.getResultCode(),
+ bundleResult.getErrorMessage());
+ }
+ SearchResultPage searchResultPage = new SearchResultPage(bundleResult.getResultValue());
+ return AppSearchResult.newSuccessfulResult(searchResultPage.getResults());
} catch (RemoteException e) {
- searchResultsFuture.completeExceptionally(e);
- }
-
- // Translate the Bundle into a searchResultPage.
- AppSearchResult<Bundle> bundleResult = getFutureOrThrow(searchResultsFuture);
- if (!bundleResult.isSuccess()) {
- return AppSearchResult.newFailedResult(bundleResult.getResultCode(),
- bundleResult.getErrorMessage());
+ throw e.rethrowFromSystemServer();
+ } catch (Throwable t) {
+ return AppSearchResult.throwableToFailedResult(t);
}
- SearchResultPage searchResultPage = new SearchResultPage(bundleResult.getResultValue());
- return AppSearchResult.newSuccessfulResult(searchResultPage.getResults());
}
/**
diff --git a/apex/appsearch/framework/java/android/app/appsearch/AppSearchResult.aidl b/apex/appsearch/framework/java/android/app/appsearch/AppSearchResult.aidl
index f0b29964b895..37ce990b97c4 100644
--- a/apex/appsearch/framework/java/android/app/appsearch/AppSearchResult.aidl
+++ b/apex/appsearch/framework/java/android/app/appsearch/AppSearchResult.aidl
@@ -16,4 +16,4 @@
package android.app.appsearch;
/** {@hide} */
-parcelable AppSearchResult; \ No newline at end of file
+parcelable AppSearchResult<ValueType>; \ No newline at end of file
diff --git a/apex/appsearch/framework/java/android/app/appsearch/AppSearchSession.java b/apex/appsearch/framework/java/android/app/appsearch/AppSearchSession.java
index 531436ecaf0c..9c7ccea4c43b 100644
--- a/apex/appsearch/framework/java/android/app/appsearch/AppSearchSession.java
+++ b/apex/appsearch/framework/java/android/app/appsearch/AppSearchSession.java
@@ -270,6 +270,61 @@ public final class AppSearchSession {
}
/**
+ * Searches a document based on a given query string.
+ *
+ * <p>Currently we support following features in the raw query format:
+ * <ul>
+ * <li>AND
+ * <p>AND joins (e.g. “match documents that have both the terms ‘dog’ and
+ * ‘cat’”).
+ * Example: hello world matches documents that have both ‘hello’ and ‘world’
+ * <li>OR
+ * <p>OR joins (e.g. “match documents that have either the term ‘dog’ or
+ * ‘cat’”).
+ * Example: dog OR puppy
+ * <li>Exclusion
+ * <p>Exclude a term (e.g. “match documents that do
+ * not have the term ‘dog’”).
+ * Example: -dog excludes the term ‘dog’
+ * <li>Grouping terms
+ * <p>Allow for conceptual grouping of subqueries to enable hierarchical structures (e.g.
+ * “match documents that have either ‘dog’ or ‘puppy’, and either ‘cat’ or ‘kitten’”).
+ * Example: (dog puppy) (cat kitten) two one group containing two terms.
+ * <li>Property restricts
+ * <p> Specifies which properties of a document to specifically match terms in (e.g.
+ * “match documents where the ‘subject’ property contains ‘important’”).
+ * Example: subject:important matches documents with the term ‘important’ in the
+ * ‘subject’ property
+ * <li>Schema type restricts
+ * <p>This is similar to property restricts, but allows for restricts on top-level document
+ * fields, such as schema_type. Clients should be able to limit their query to documents of
+ * a certain schema_type (e.g. “match documents that are of the ‘Email’ schema_type”).
+ * Example: { schema_type_filters: “Email”, “Video”,query: “dog” } will match documents
+ * that contain the query term ‘dog’ and are of either the ‘Email’ schema type or the
+ * ‘Video’ schema type.
+ * </ul>
+ *
+ * <p> This method is lightweight. The heavy work will be done in
+ * {@link SearchResults#getNextPage}.
+ *
+ * @param queryExpression Query String to search.
+ * @param searchSpec Spec for setting filters, raw query etc.
+ * @param executor Executor on which to invoke the callback of the following request
+ * {@link SearchResults#getNextPage}.
+ * @return The search result of performing this operation.
+ */
+ @NonNull
+ public SearchResults query(
+ @NonNull String queryExpression,
+ @NonNull SearchSpec searchSpec,
+ @NonNull @CallbackExecutor Executor executor) {
+ Objects.requireNonNull(queryExpression);
+ Objects.requireNonNull(searchSpec);
+ Objects.requireNonNull(executor);
+ return new SearchResults(mService, mDatabaseName, queryExpression, searchSpec, executor);
+ }
+
+ /**
* Removes {@link GenericDocument}s from the index by URI.
*
* @param request Request containing URIs to be removed.
@@ -307,6 +362,39 @@ public final class AppSearchSession {
}
}
- // TODO(b/162450968) port query() and SearchResults.java to platform.
- // TODO(b/162450968) port removeByQuery() to platform.
+ /**
+ * Removes {@link GenericDocument}s from the index by Query. Documents will be removed if they
+ * match the {@code queryExpression} in given namespaces and schemaTypes which is set via
+ * {@link SearchSpec.Builder#addNamespace} and {@link SearchSpec.Builder#addSchema}.
+ *
+ * <p> An empty {@code queryExpression} matches all documents.
+ *
+ * <p> An empty set of namespaces or schemaTypes matches all namespaces or schemaTypes in
+ * the current database.
+ *
+ * @param queryExpression Query String to search.
+ * @param searchSpec Defines what and how to remove
+ * @param executor Executor on which to invoke the callback.
+ * @param callback Callback to receive errors resulting from removing the documents. If the
+ * operation succeeds, the callback will be invoked with {@code null}.
+ */
+ public void removeByQuery(@NonNull String queryExpression,
+ @NonNull SearchSpec searchSpec,
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull Consumer<AppSearchResult<Void>> callback) {
+ Objects.requireNonNull(queryExpression);
+ Objects.requireNonNull(searchSpec);
+ Objects.requireNonNull(executor);
+ Objects.requireNonNull(callback);
+ try {
+ mService.removeByQuery(mDatabaseName, queryExpression, searchSpec.getBundle(),
+ new IAppSearchResultCallback.Stub() {
+ public void onResult(AppSearchResult result) {
+ executor.execute(() -> callback.accept(result));
+ }
+ });
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
}
diff --git a/apex/appsearch/framework/java/android/app/appsearch/GlobalSearchSession.java b/apex/appsearch/framework/java/android/app/appsearch/GlobalSearchSession.java
new file mode 100644
index 000000000000..d2aa8eab4708
--- /dev/null
+++ b/apex/appsearch/framework/java/android/app/appsearch/GlobalSearchSession.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.appsearch;
+
+
+import android.annotation.CallbackExecutor;
+import android.annotation.NonNull;
+import android.os.RemoteException;
+
+import java.util.Objects;
+import java.util.concurrent.Executor;
+import java.util.function.Consumer;
+
+/**
+ * This class provides global access to the centralized AppSearch index maintained by the system.
+ *
+ * <p>Apps can retrieve indexed documents through the query API.
+ * @hide
+ */
+public class GlobalSearchSession {
+
+ private final IAppSearchManager mService;
+
+ static void createGlobalSearchSession(
+ @NonNull IAppSearchManager service,
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull Consumer<AppSearchResult<GlobalSearchSession>> callback) {
+ GlobalSearchSession globalSearchSession = new GlobalSearchSession(service);
+ globalSearchSession.initialize(executor, callback);
+ }
+
+ // NOTE: No instance of this class should be created or returned except via initialize().
+ // Once the callback.accept has been called here, the class is ready to use.
+ private void initialize(
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull Consumer<AppSearchResult<GlobalSearchSession>> callback) {
+ try {
+ mService.initialize(new IAppSearchResultCallback.Stub() {
+ public void onResult(AppSearchResult result) {
+ executor.execute(() -> {
+ if (result.isSuccess()) {
+ callback.accept(
+ AppSearchResult.newSuccessfulResult(GlobalSearchSession.this));
+ } else {
+ callback.accept(result);
+ }
+ });
+ }
+ });
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ private GlobalSearchSession(@NonNull IAppSearchManager service) {
+ mService = service;
+ }
+
+ /**
+ * Searches across all documents in the storage based on a given query string.
+ *
+ * <p>Currently we support following features in the raw query format:
+ * <ul>
+ * <li>AND
+ * <p>AND joins (e.g. “match documents that have both the terms ‘dog’ and
+ * ‘cat’”).
+ * Example: hello world matches documents that have both ‘hello’ and ‘world’
+ * <li>OR
+ * <p>OR joins (e.g. “match documents that have either the term ‘dog’ or
+ * ‘cat’”).
+ * Example: dog OR puppy
+ * <li>Exclusion
+ * <p>Exclude a term (e.g. “match documents that do
+ * not have the term ‘dog’”).
+ * Example: -dog excludes the term ‘dog’
+ * <li>Grouping terms
+ * <p>Allow for conceptual grouping of subqueries to enable hierarchical structures (e.g.
+ * “match documents that have either ‘dog’ or ‘puppy’, and either ‘cat’ or ‘kitten’”).
+ * Example: (dog puppy) (cat kitten) two one group containing two terms.
+ * <li>Property restricts
+ * <p> Specifies which properties of a document to specifically match terms in (e.g.
+ * “match documents where the ‘subject’ property contains ‘important’”).
+ * Example: subject:important matches documents with the term ‘important’ in the
+ * ‘subject’ property
+ * <li>Schema type restricts
+ * <p>This is similar to property restricts, but allows for restricts on top-level document
+ * fields, such as schema_type. Clients should be able to limit their query to documents of
+ * a certain schema_type (e.g. “match documents that are of the ‘Email’ schema_type”).
+ * Example: { schema_type_filters: “Email”, “Video”,query: “dog” } will match documents
+ * that contain the query term ‘dog’ and are of either the ‘Email’ schema type or the
+ * ‘Video’ schema type.
+ * </ul>
+ *
+ * <p> This method is lightweight. The heavy work will be done in
+ * {@link SearchResults#getNextPage}.
+ *
+ * @param queryExpression Query String to search.
+ * @param searchSpec Spec for setting filters, raw query etc.
+ * @param executor Executor on which to invoke the callback of the following request
+ * {@link SearchResults#getNextPage}.
+ * @return The search result of performing this operation.
+ */
+ @NonNull
+ public SearchResults globalQuery(
+ @NonNull String queryExpression,
+ @NonNull SearchSpec searchSpec,
+ @NonNull @CallbackExecutor Executor executor) {
+ Objects.requireNonNull(queryExpression);
+ Objects.requireNonNull(searchSpec);
+ Objects.requireNonNull(executor);
+ return new SearchResults(mService, /*databaseName=*/null, queryExpression,
+ searchSpec, executor);
+ }
+}
diff --git a/apex/appsearch/framework/java/android/app/appsearch/IAppSearchManager.aidl b/apex/appsearch/framework/java/android/app/appsearch/IAppSearchManager.aidl
index 4a981022da73..22e00f2cdfdc 100644
--- a/apex/appsearch/framework/java/android/app/appsearch/IAppSearchManager.aidl
+++ b/apex/appsearch/framework/java/android/app/appsearch/IAppSearchManager.aidl
@@ -85,13 +85,46 @@ interface IAppSearchManager {
* @param databaseName The databaseName this query for.
* @param queryExpression String to search for
* @param searchSpecBundle SearchSpec bundle
- * @param callback {@link AndroidFuture}&lt;{@link AppSearchResult}&lt;{@link SearchResults}&gt;&gt;
+ * @param callback {@link AppSearchResult}&lt;{@link Bundle}&gt; of performing this
+ * operation.
*/
void query(
in String databaseName,
in String queryExpression,
in Bundle searchSpecBundle,
- in AndroidFuture<AppSearchResult> callback);
+ in IAppSearchResultCallback callback);
+
+ /**
+ * Executes a global query, i.e. over all permitted databases, against the AppSearch index and
+ * returns results.
+ *
+ * @param queryExpression String to search for
+ * @param searchSpecBundle SearchSpec bundle
+ * @param callback {@link AppSearchResult}&lt;{@link Bundle}&gt; of performing this
+ * operation.
+ */
+ void globalQuery(
+ in String queryExpression,
+ in Bundle searchSpecBundle,
+ in IAppSearchResultCallback callback);
+
+ /**
+ * Fetches the next page of results of a previously executed query. Results can be empty if
+ * next-page token is invalid or all pages have been returned.
+ *
+ * @param nextPageToken The token of pre-loaded results of previously executed query.
+ * @param callback {@link AppSearchResult}&lt;{@link Bundle}&gt; of performing this
+ * operation.
+ */
+ void getNextPage(in long nextPageToken, in IAppSearchResultCallback callback);
+
+ /**
+ * Invalidates the next-page token so that no more results of the related query can be returned.
+ *
+ * @param nextPageToken The token of pre-loaded results of previously executed query to be
+ * Invalidated.
+ */
+ void invalidateNextPageToken(in long nextPageToken);
/**
* Removes documents by URI.
@@ -119,13 +152,14 @@ interface IAppSearchManager {
* @param databaseName The databaseName this query for.
* @param queryExpression String to search for
* @param searchSpecBundle SearchSpec bundle
- * @param callback {@link AndroidFuture}&lt;{@link AppSearchResult}&lt;{@link SearchResults}&gt;&gt;
+ * @param callback {@link IAppSearchResultCallback#onResult} will be called with an
+ * {@link AppSearchResult}&lt;{@link Void}&gt;.
*/
void removeByQuery(
in String databaseName,
in String queryExpression,
in Bundle searchSpecBundle,
- in AndroidFuture<AppSearchResult> callback);
+ in IAppSearchResultCallback callback);
/**
* Creates and initializes AppSearchImpl for the calling app.
diff --git a/apex/appsearch/framework/java/android/app/appsearch/SearchResults.java b/apex/appsearch/framework/java/android/app/appsearch/SearchResults.java
index 9f376250f1a6..8548d209c787 100644
--- a/apex/appsearch/framework/java/android/app/appsearch/SearchResults.java
+++ b/apex/appsearch/framework/java/android/app/appsearch/SearchResults.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * Copyright 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,63 +16,123 @@
package android.app.appsearch;
+import android.annotation.CallbackExecutor;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.os.Bundle;
-import android.os.Parcel;
-import android.os.Parcelable;
+import android.os.RemoteException;
+import android.util.Log;
-import java.util.ArrayList;
+import com.android.internal.util.Preconditions;
+
+import java.io.Closeable;
import java.util.List;
+import java.util.concurrent.Executor;
+import java.util.function.Consumer;
/**
- * Structure for transmitting a page of search results across binder.
+ * SearchResults are a returned object from a query API.
+ *
+ * <p>Each {@link SearchResult} contains a document and may contain other fields like snippets
+ * based on request.
+ *
+ * <p>Should close this object after finish fetching results.
+ *
+ * <p>This class is not thread safe.
* @hide
*/
-public final class SearchResults implements Parcelable {
- final List<SearchResult> mResults;
- final long mNextPageToken;
+public class SearchResults implements Closeable {
+ private static final String TAG = "SearchResults";
+
+ private final IAppSearchManager mService;
+
+ @Nullable
+ private final String mDatabaseName;
+
+ private final String mQueryExpression;
+
+ private final SearchSpec mSearchSpec;
+
+ private final Executor mExecutor;
- public SearchResults(@NonNull List<SearchResult> results, long nextPageToken) {
- mResults = results;
- mNextPageToken = nextPageToken;
+ private long mNextPageToken;
+
+ private boolean mIsFirstLoad = true;
+
+ SearchResults(@NonNull IAppSearchManager service,
+ @Nullable String databaseName,
+ @NonNull String queryExpression,
+ @NonNull SearchSpec searchSpec,
+ @NonNull @CallbackExecutor Executor executor) {
+ mService = Preconditions.checkNotNull(service);
+ mExecutor = Preconditions.checkNotNull(executor);
+ mDatabaseName = databaseName;
+ mQueryExpression = Preconditions.checkNotNull(queryExpression);
+ mSearchSpec = Preconditions.checkNotNull(searchSpec);
}
- private SearchResults(@NonNull Parcel in) {
- List<Bundle> resultBundles = in.readArrayList(/*loader=*/ null);
- mResults = new ArrayList<>(resultBundles.size());
- for (int i = 0; i < resultBundles.size(); i++) {
- SearchResult searchResult = new SearchResult(resultBundles.get(i));
- mResults.add(searchResult);
+ /**
+ * Gets a whole page of {@link SearchResult}s.
+ *
+ * <p>Re-call this method to get next page of {@link SearchResult}, until it returns an
+ * empty list.
+ *
+ * <p>The page size is set by {@link SearchSpec.Builder#setNumPerPage}.
+ *
+ * @param callback Callback to receive the pending result of performing this operation.
+ */
+ public void getNextPage(@NonNull Consumer<AppSearchResult<List<SearchResult>>> callback) {
+ try {
+ if (mIsFirstLoad) {
+ mIsFirstLoad = false;
+ if (mDatabaseName == null) {
+ mService.globalQuery(mQueryExpression, mSearchSpec.getBundle(),
+ wrapCallback(callback));
+ } else {
+ mService.query(mDatabaseName, mQueryExpression, mSearchSpec.getBundle(),
+ wrapCallback(callback));
+ }
+ } else {
+ mService.getNextPage(mNextPageToken, wrapCallback(callback));
+ }
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
- mNextPageToken = in.readLong();
}
- @Override
- public void writeToParcel(@NonNull Parcel dest, int flags) {
- List<Bundle> resultBundles = new ArrayList<>(mResults.size());
- for (int i = 0; i < mResults.size(); i++) {
- resultBundles.add(mResults.get(i).getBundle());
+ private void invokeCallback(AppSearchResult result,
+ @NonNull Consumer<AppSearchResult<List<SearchResult>>> callback) {
+ if (result.isSuccess()) {
+ try {
+ SearchResultPage searchResultPage =
+ new SearchResultPage((Bundle) result.getResultValue());
+ mNextPageToken = searchResultPage.getNextPageToken();
+ callback.accept(AppSearchResult.newSuccessfulResult(
+ searchResultPage.getResults()));
+ } catch (Throwable t) {
+ callback.accept(AppSearchResult.throwableToFailedResult(t));
+ }
+ } else {
+ callback.accept(result);
}
- dest.writeList(resultBundles);
- dest.writeLong(mNextPageToken);
}
-
@Override
- public int describeContents() {
- return 0;
+ public void close() {
+ mExecutor.execute(() -> {
+ try {
+ mService.invalidateNextPageToken(mNextPageToken);
+ } catch (RemoteException e) {
+ Log.d(TAG, "Unable to close the SearchResults", e);
+ }
+ });
}
- public static final Creator<SearchResults> CREATOR = new Creator<SearchResults>() {
- @NonNull
- @Override
- public SearchResults createFromParcel(@NonNull Parcel in) {
- return new SearchResults(in);
- }
-
- @NonNull
- @Override
- public SearchResults[] newArray(int size) {
- return new SearchResults[size];
- }
- };
+ private IAppSearchResultCallback wrapCallback(
+ @NonNull Consumer<AppSearchResult<List<SearchResult>>> callback) {
+ return new IAppSearchResultCallback.Stub() {
+ public void onResult(AppSearchResult result) {
+ mExecutor.execute(() -> invokeCallback(result, callback));
+ }
+ };
+ }
}
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java
index 8269799d5a0d..d5146dd75c3b 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java
@@ -36,7 +36,6 @@ import android.os.UserHandle;
import android.util.ArraySet;
import android.util.Log;
-import com.android.internal.infra.AndroidFuture;
import com.android.internal.util.Preconditions;
import com.android.server.SystemService;
import com.android.server.appsearch.external.localstorage.AppSearchImpl;
@@ -69,6 +68,7 @@ public class AppSearchManagerService extends SystemService {
@NonNull IAppSearchResultCallback callback) {
Preconditions.checkNotNull(databaseName);
Preconditions.checkNotNull(schemaBundles);
+ Preconditions.checkNotNull(callback);
int callingUid = Binder.getCallingUidOrThrow();
int callingUserId = UserHandle.getUserId(callingUid);
final long callingIdentity = Binder.clearCallingIdentity();
@@ -158,13 +158,12 @@ public class AppSearchManagerService extends SystemService {
}
// TODO(sidchhabra): Do this in a threadpool.
- // TODO(b/162450968) handle pagination after getNextPage and SearchResults is ready.
@Override
public void query(
@NonNull String databaseName,
@NonNull String queryExpression,
@NonNull Bundle searchSpecBundle,
- @NonNull AndroidFuture<AppSearchResult> callback) {
+ @NonNull IAppSearchResultCallback callback) {
Preconditions.checkNotNull(databaseName);
Preconditions.checkNotNull(queryExpression);
Preconditions.checkNotNull(searchSpecBundle);
@@ -179,10 +178,70 @@ public class AppSearchManagerService extends SystemService {
databaseName,
queryExpression,
new SearchSpec(searchSpecBundle));
- callback.complete(
+ invokeCallbackOnResult(callback,
+ AppSearchResult.newSuccessfulResult(searchResultPage.getBundle()));
+ } catch (Throwable t) {
+ invokeCallbackOnError(callback, t);
+ } finally {
+ Binder.restoreCallingIdentity(callingIdentity);
+ }
+ }
+
+ public void globalQuery(
+ @NonNull String queryExpression,
+ @NonNull Bundle searchSpecBundle,
+ @NonNull IAppSearchResultCallback callback) {
+ Preconditions.checkNotNull(queryExpression);
+ Preconditions.checkNotNull(searchSpecBundle);
+ Preconditions.checkNotNull(callback);
+ int callingUid = Binder.getCallingUidOrThrow();
+ int callingUserId = UserHandle.getUserId(callingUid);
+ final long callingIdentity = Binder.clearCallingIdentity();
+ try {
+ AppSearchImpl impl = ImplInstanceManager.getInstance(getContext(), callingUserId);
+ SearchResultPage searchResultPage = impl.globalQuery(
+ queryExpression,
+ new SearchSpec(searchSpecBundle));
+ invokeCallbackOnResult(callback,
+ AppSearchResult.newSuccessfulResult(searchResultPage.getBundle()));
+ } catch (Throwable t) {
+ invokeCallbackOnError(callback, t);
+ } finally {
+ Binder.restoreCallingIdentity(callingIdentity);
+ }
+ }
+
+ @Override
+ public void getNextPage(long nextPageToken,
+ @NonNull IAppSearchResultCallback callback) {
+ Preconditions.checkNotNull(callback);
+ int callingUid = Binder.getCallingUidOrThrow();
+ int callingUserId = UserHandle.getUserId(callingUid);
+ final long callingIdentity = Binder.clearCallingIdentity();
+ // TODO(b/162450968) check nextPageToken is being advanced by the same uid as originally
+ // opened it
+ try {
+ AppSearchImpl impl = ImplInstanceManager.getInstance(getContext(), callingUserId);
+ SearchResultPage searchResultPage = impl.getNextPage(nextPageToken);
+ invokeCallbackOnResult(callback,
AppSearchResult.newSuccessfulResult(searchResultPage.getBundle()));
} catch (Throwable t) {
- callback.complete(throwableToFailedResult(t));
+ invokeCallbackOnError(callback, t);
+ } finally {
+ Binder.restoreCallingIdentity(callingIdentity);
+ }
+ }
+
+ @Override
+ public void invalidateNextPageToken(long nextPageToken) {
+ int callingUid = Binder.getCallingUidOrThrow();
+ int callingUserId = UserHandle.getUserId(callingUid);
+ final long callingIdentity = Binder.clearCallingIdentity();
+ try {
+ AppSearchImpl impl = ImplInstanceManager.getInstance(getContext(), callingUserId);
+ impl.invalidateNextPageToken(nextPageToken);
+ } catch (Throwable t) {
+ Log.d(TAG, "Unable to invalidate the query page token", t);
} finally {
Binder.restoreCallingIdentity(callingIdentity);
}
@@ -225,7 +284,7 @@ public class AppSearchManagerService extends SystemService {
@NonNull String databaseName,
@NonNull String queryExpression,
@NonNull Bundle searchSpecBundle,
- @NonNull AndroidFuture<AppSearchResult> callback) {
+ @NonNull IAppSearchResultCallback callback) {
Preconditions.checkNotNull(databaseName);
Preconditions.checkNotNull(queryExpression);
Preconditions.checkNotNull(searchSpecBundle);
@@ -236,10 +295,11 @@ public class AppSearchManagerService extends SystemService {
try {
AppSearchImpl impl = ImplInstanceManager.getInstance(getContext(), callingUserId);
databaseName = rewriteDatabaseNameWithUid(databaseName, callingUid);
- impl.removeByQuery(databaseName, queryExpression, new SearchSpec(searchSpecBundle));
- callback.complete(AppSearchResult.newSuccessfulResult(/*result= */null));
+ impl.removeByQuery(databaseName, queryExpression,
+ new SearchSpec(searchSpecBundle));
+ invokeCallbackOnResult(callback, AppSearchResult.newSuccessfulResult(null));
} catch (Throwable t) {
- callback.complete(throwableToFailedResult(t));
+ invokeCallbackOnError(callback, t);
} finally {
Binder.restoreCallingIdentity(callingIdentity);
}
@@ -247,6 +307,7 @@ public class AppSearchManagerService extends SystemService {
@Override
public void initialize(@NonNull IAppSearchResultCallback callback) {
+ Preconditions.checkNotNull(callback);
int callingUid = Binder.getCallingUidOrThrow();
int callingUserId = UserHandle.getUserId(callingUid);
final long callingIdentity = Binder.clearCallingIdentity();
diff --git a/apex/jobscheduler/framework/java/android/app/job/JobInfo.java b/apex/jobscheduler/framework/java/android/app/job/JobInfo.java
index 2c8a5589ca51..3597c27224bb 100644
--- a/apex/jobscheduler/framework/java/android/app/job/JobInfo.java
+++ b/apex/jobscheduler/framework/java/android/app/job/JobInfo.java
@@ -462,11 +462,11 @@ public class JobInfo implements Parcelable {
public @NetworkType int getNetworkType() {
if (networkRequest == null) {
return NETWORK_TYPE_NONE;
- } else if (networkRequest.networkCapabilities.hasCapability(NET_CAPABILITY_NOT_METERED)) {
+ } else if (networkRequest.hasCapability(NET_CAPABILITY_NOT_METERED)) {
return NETWORK_TYPE_UNMETERED;
- } else if (networkRequest.networkCapabilities.hasCapability(NET_CAPABILITY_NOT_ROAMING)) {
+ } else if (networkRequest.hasCapability(NET_CAPABILITY_NOT_ROAMING)) {
return NETWORK_TYPE_NOT_ROAMING;
- } else if (networkRequest.networkCapabilities.hasTransport(TRANSPORT_CELLULAR)) {
+ } else if (networkRequest.hasTransport(TRANSPORT_CELLULAR)) {
return NETWORK_TYPE_CELLULAR;
} else {
return NETWORK_TYPE_ANY;
@@ -1558,7 +1558,7 @@ public class JobInfo implements Parcelable {
if (isPersisted) {
// We can't serialize network specifiers
if (networkRequest != null
- && networkRequest.networkCapabilities.getNetworkSpecifier() != null) {
+ && networkRequest.getNetworkSpecifier() != null) {
throw new IllegalArgumentException(
"Network specifiers aren't supported for persistent jobs");
}
diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
index d4ea7af06ed1..20c77da53f2c 100644
--- a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
@@ -417,6 +417,9 @@ public class AlarmManagerService extends SystemService {
@VisibleForTesting
static final String KEY_LAZY_BATCHING = "lazy_batching";
+ private static final String KEY_TIME_TICK_ALLOWED_WHILE_IDLE =
+ "time_tick_allowed_while_idle";
+
private static final long DEFAULT_MIN_FUTURITY = 5 * 1000;
private static final long DEFAULT_MIN_INTERVAL = 60 * 1000;
private static final long DEFAULT_MAX_INTERVAL = 365 * DateUtils.DAY_IN_MILLIS;
@@ -440,6 +443,7 @@ public class AlarmManagerService extends SystemService {
private static final long DEFAULT_APP_STANDBY_RESTRICTED_WINDOW = MILLIS_IN_DAY;
private static final boolean DEFAULT_LAZY_BATCHING = true;
+ private static final boolean DEFAULT_TIME_TICK_ALLOWED_WHILE_IDLE = true;
// Minimum futurity of a new alarm
public long MIN_FUTURITY = DEFAULT_MIN_FUTURITY;
@@ -470,6 +474,7 @@ public class AlarmManagerService extends SystemService {
public long APP_STANDBY_RESTRICTED_WINDOW = DEFAULT_APP_STANDBY_RESTRICTED_WINDOW;
public boolean LAZY_BATCHING = DEFAULT_LAZY_BATCHING;
+ public boolean TIME_TICK_ALLOWED_WHILE_IDLE = DEFAULT_TIME_TICK_ALLOWED_WHILE_IDLE;
private long mLastAllowWhileIdleWhitelistDuration = -1;
@@ -557,6 +562,11 @@ public class AlarmManagerService extends SystemService {
migrateAlarmsToNewStoreLocked();
}
break;
+ case KEY_TIME_TICK_ALLOWED_WHILE_IDLE:
+ TIME_TICK_ALLOWED_WHILE_IDLE = properties.getBoolean(
+ KEY_TIME_TICK_ALLOWED_WHILE_IDLE,
+ DEFAULT_TIME_TICK_ALLOWED_WHILE_IDLE);
+ break;
default:
if (name.startsWith(KEY_PREFIX_STANDBY_QUOTA) && !standbyQuotaUpdated) {
// The quotas need to be updated in order, so we can't just rely
@@ -690,6 +700,9 @@ public class AlarmManagerService extends SystemService {
pw.print(KEY_LAZY_BATCHING, LAZY_BATCHING);
pw.println();
+ pw.print(KEY_TIME_TICK_ALLOWED_WHILE_IDLE, TIME_TICK_ALLOWED_WHILE_IDLE);
+ pw.println();
+
pw.decreaseIndent();
}
@@ -3756,9 +3769,14 @@ public class AlarmManagerService extends SystemService {
final long tickEventDelay = nextTime - currentTime;
final WorkSource workSource = null; // Let system take blame for time tick events.
+
+ int flags = AlarmManager.FLAG_STANDALONE;
+ flags |= mConstants.TIME_TICK_ALLOWED_WHILE_IDLE ? FLAG_ALLOW_WHILE_IDLE_UNRESTRICTED
+ : 0;
+
setImpl(ELAPSED_REALTIME, mInjector.getElapsedRealtime() + tickEventDelay, 0,
- 0, null, mTimeTickTrigger, TIME_TICK_TAG, AlarmManager.FLAG_STANDALONE,
- workSource, null, Process.myUid(), "android");
+ 0, null, mTimeTickTrigger, TIME_TICK_TAG, flags, workSource, null,
+ Process.myUid(), "android");
// Finally, remember when we set the tick alarm
synchronized (mLock) {
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/TimeController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/TimeController.java
index 56b97f2e5757..2b5aab83463b 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/TimeController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/TimeController.java
@@ -282,12 +282,13 @@ public final class TimeController extends StateController {
String nextDelayPackageName = null;
boolean ready = false;
Iterator<JobStatus> it = mTrackedJobs.iterator();
+ final long nowElapsedMillis = sElapsedRealtimeClock.millis();
while (it.hasNext()) {
final JobStatus job = it.next();
if (!job.hasTimingDelayConstraint()) {
continue;
}
- if (evaluateTimingDelayConstraint(job, sElapsedRealtimeClock.millis())) {
+ if (evaluateTimingDelayConstraint(job, nowElapsedMillis)) {
if (canStopTrackingJobLocked(job)) {
it.remove();
}
diff --git a/cmds/sm/src/com/android/commands/sm/Sm.java b/cmds/sm/src/com/android/commands/sm/Sm.java
index c2ee6dcd13b2..ef1e413a3112 100644
--- a/cmds/sm/src/com/android/commands/sm/Sm.java
+++ b/cmds/sm/src/com/android/commands/sm/Sm.java
@@ -101,8 +101,6 @@ public final class Sm {
runFstrim();
} else if ("set-virtual-disk".equals(op)) {
runSetVirtualDisk();
- } else if ("set-isolated-storage".equals(op)) {
- runIsolatedStorage();
} else if ("start-checkpoint".equals(op)) {
runStartCheckpoint();
} else if ("supports-checkpoint".equals(op)) {
@@ -286,28 +284,6 @@ public final class Sm {
StorageManager.DEBUG_VIRTUAL_DISK);
}
- public void runIsolatedStorage() throws RemoteException {
- final int value;
- final int mask = StorageManager.DEBUG_ISOLATED_STORAGE_FORCE_ON
- | StorageManager.DEBUG_ISOLATED_STORAGE_FORCE_OFF;
- switch (nextArg()) {
- case "on":
- case "true":
- value = StorageManager.DEBUG_ISOLATED_STORAGE_FORCE_ON;
- break;
- case "off":
- value = StorageManager.DEBUG_ISOLATED_STORAGE_FORCE_OFF;
- break;
- case "default":
- case "false":
- value = 0;
- break;
- default:
- return;
- }
- mSm.setDebugFlags(value, mask);
- }
-
public void runIdleMaint() throws RemoteException {
final boolean im_run = "run".equals(nextArg());
if (im_run) {
@@ -367,8 +343,6 @@ public final class Sm {
System.err.println("");
System.err.println(" sm set-emulate-fbe [true|false]");
System.err.println("");
- System.err.println(" sm set-isolated-storage [on|off|default]");
- System.err.println("");
System.err.println(" sm start-checkpoint <num-retries>");
System.err.println("");
System.err.println(" sm supports-checkpoint");
diff --git a/cmds/statsd/OWNERS b/cmds/statsd/OWNERS
index a61babf32e58..4e4e11988b62 100644
--- a/cmds/statsd/OWNERS
+++ b/cmds/statsd/OWNERS
@@ -1,9 +1 @@
-jeffreyhuang@google.com
-joeo@google.com
-jtnguyen@google.com
-muhammadq@google.com
-ruchirr@google.com
-singhtejinder@google.com
-tsaichristine@google.com
-yaochen@google.com
-yro@google.com
+baligh@google.com
diff --git a/cmds/statsd/src/OWNERS b/cmds/statsd/src/OWNERS
deleted file mode 100644
index 0f3ddf7388d9..000000000000
--- a/cmds/statsd/src/OWNERS
+++ /dev/null
@@ -1,6 +0,0 @@
-# Temporary OWNERS Block to assist with migration
-# bug: 167962588
-per-file *atoms.proto = set noparent
-per-file *atom_field_options.proto = set noparent
-per-file *atoms.proto = baligh@google.com, yro@google.com, singhtejinder@google.com, jeffreyhuang@google.com
-per-file *atom_field_options.proto = baligh@google.com, yro@google.com, singhtejinder@google.com, jeffreyhuang@google.com
diff --git a/cmds/statsd/src/condition/CombinationConditionTracker.h b/cmds/statsd/src/condition/CombinationConditionTracker.h
index 672d61c82268..d355146c13ef 100644
--- a/cmds/statsd/src/condition/CombinationConditionTracker.h
+++ b/cmds/statsd/src/condition/CombinationConditionTracker.h
@@ -85,16 +85,14 @@ public:
const std::vector<sp<ConditionTracker>>& allConditions,
const vector<Matcher>& dimensions) const override;
- void getTrueSlicedDimensions(
- const std::vector<sp<ConditionTracker>>& allConditions,
- std::set<HashableDimensionKey>* dimensions) const override {
+ const std::map<HashableDimensionKey, int>* getSlicedDimensionMap(
+ const std::vector<sp<ConditionTracker>>& allConditions) const override {
if (mSlicedChildren.size() == 1) {
- return allConditions[mSlicedChildren.front()]->getTrueSlicedDimensions(
- allConditions, dimensions);
+ return allConditions[mSlicedChildren.front()]->getSlicedDimensionMap(allConditions);
}
+ return nullptr;
}
-
private:
LogicalOperation mLogicalOperation;
diff --git a/cmds/statsd/src/condition/ConditionTracker.h b/cmds/statsd/src/condition/ConditionTracker.h
index 5a6b8cf334eb..7af022a5677a 100644
--- a/cmds/statsd/src/condition/ConditionTracker.h
+++ b/cmds/statsd/src/condition/ConditionTracker.h
@@ -135,9 +135,8 @@ public:
return mProtoHash;
}
- virtual void getTrueSlicedDimensions(
- const std::vector<sp<ConditionTracker>>& allConditions,
- std::set<HashableDimensionKey>* dimensions) const = 0;
+ virtual const std::map<HashableDimensionKey, int>* getSlicedDimensionMap(
+ const std::vector<sp<ConditionTracker>>& allConditions) const = 0;
virtual bool IsChangedDimensionTrackable() const = 0;
diff --git a/cmds/statsd/src/condition/ConditionWizard.h b/cmds/statsd/src/condition/ConditionWizard.h
index 892647910d9f..43db94cfa47d 100644
--- a/cmds/statsd/src/condition/ConditionWizard.h
+++ b/cmds/statsd/src/condition/ConditionWizard.h
@@ -53,9 +53,9 @@ public:
ConditionState getUnSlicedPartConditionState(const int index) {
return mAllConditions[index]->getUnSlicedPartConditionState();
}
- void getTrueSlicedDimensions(const int index,
- std::set<HashableDimensionKey>* trueDimensions) const {
- return mAllConditions[index]->getTrueSlicedDimensions(mAllConditions, trueDimensions);
+
+ const std::map<HashableDimensionKey, int>* getSlicedDimensionMap(const int index) const {
+ return mAllConditions[index]->getSlicedDimensionMap(mAllConditions);
}
private:
diff --git a/cmds/statsd/src/condition/SimpleConditionTracker.h b/cmds/statsd/src/condition/SimpleConditionTracker.h
index 7a8b40108448..2fbc8a7b4ea8 100644
--- a/cmds/statsd/src/condition/SimpleConditionTracker.h
+++ b/cmds/statsd/src/condition/SimpleConditionTracker.h
@@ -74,14 +74,9 @@ public:
}
}
- void getTrueSlicedDimensions(
- const std::vector<sp<ConditionTracker>>& allConditions,
- std::set<HashableDimensionKey>* dimensions) const override {
- for (const auto& itr : mSlicedConditionState) {
- if (itr.second > 0) {
- dimensions->insert(itr.first);
- }
- }
+ const std::map<HashableDimensionKey, int>* getSlicedDimensionMap(
+ const std::vector<sp<ConditionTracker>>& allConditions) const override {
+ return &mSlicedConditionState;
}
bool IsChangedDimensionTrackable() const override { return true; }
diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.cpp b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
index 8869241ab8aa..bbaa20f232a9 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
@@ -67,8 +67,8 @@ const int FIELD_ID_END_BUCKET_ELAPSED_MILLIS = 6;
DurationMetricProducer::DurationMetricProducer(
const ConfigKey& key, const DurationMetric& metric, const int conditionIndex,
- const vector<ConditionState>& initialConditionCache, const int startIndex,
- const int stopIndex, const int stopAllIndex, const bool nesting,
+ const vector<ConditionState>& initialConditionCache, const int whatIndex,
+ const int startIndex, const int stopIndex, const int stopAllIndex, const bool nesting,
const sp<ConditionWizard>& wizard, const uint64_t protoHash,
const FieldMatcher& internalDimensions, const int64_t timeBaseNs, const int64_t startTimeNs,
const unordered_map<int, shared_ptr<Activation>>& eventActivationMap,
@@ -140,6 +140,8 @@ DurationMetricProducer::DurationMetricProducer(
mCurrentBucketStartTimeNs = startTimeNs;
VLOG("metric %lld created. bucket size %lld start_time: %lld", (long long)metric.id(),
(long long)mBucketSizeNs, (long long)mTimeBaseNs);
+
+ initTrueDimensions(whatIndex, startTimeNs);
}
DurationMetricProducer::~DurationMetricProducer() {
@@ -224,6 +226,23 @@ bool DurationMetricProducer::onConfigUpdatedLocked(
return true;
}
+void DurationMetricProducer::initTrueDimensions(const int whatIndex, const int64_t startTimeNs) {
+ std::lock_guard<std::mutex> lock(mMutex);
+ // Currently whatIndex will only be -1 in tests. In the future, we might want to avoid creating
+ // a ConditionTracker if the condition is only used in the "what" of a duration metric. In that
+ // scenario, -1 can also be passed.
+ if (whatIndex == -1) {
+ return;
+ }
+ const map<HashableDimensionKey, int>* slicedWhatMap = mWizard->getSlicedDimensionMap(whatIndex);
+ for (const auto& [internalDimKey, count] : *slicedWhatMap) {
+ for (int i = 0; i < count; i++) {
+ // Fake start events.
+ handleMatchedLogEventValuesLocked(mStartIndex, internalDimKey.getValues(), startTimeNs);
+ }
+ }
+}
+
sp<AnomalyTracker> DurationMetricProducer::addAnomalyTracker(
const Alert &alert, const sp<AlarmMonitor>& anomalyAlarmMonitor) {
std::lock_guard<std::mutex> lock(mMutex);
@@ -330,14 +349,14 @@ void DurationMetricProducer::onSlicedConditionMayChangeLocked_opt1(bool conditio
// state based on the new unsliced condition state.
if (dimensionsChangedToTrue == nullptr || dimensionsChangedToFalse == nullptr ||
(dimensionsChangedToTrue->empty() && dimensionsChangedToFalse->empty())) {
- std::set<HashableDimensionKey> trueConditionDimensions;
- mWizard->getTrueSlicedDimensions(mConditionTrackerIndex, &trueConditionDimensions);
+ const map<HashableDimensionKey, int>* slicedConditionMap =
+ mWizard->getSlicedDimensionMap(mConditionTrackerIndex);
for (auto& whatIt : mCurrentSlicedDurationTrackerMap) {
HashableDimensionKey linkedConditionDimensionKey;
getDimensionForCondition(whatIt.first.getValues(), mMetric2ConditionLinks[0],
&linkedConditionDimensionKey);
- if (trueConditionDimensions.find(linkedConditionDimensionKey) !=
- trueConditionDimensions.end()) {
+ const auto& slicedConditionIt = slicedConditionMap->find(linkedConditionDimensionKey);
+ if (slicedConditionIt != slicedConditionMap->end() && slicedConditionIt->second > 0) {
whatIt.second->onConditionChanged(currentUnSlicedPartCondition, eventTime);
}
}
@@ -595,8 +614,9 @@ bool DurationMetricProducer::hitGuardRailLocked(const MetricDimensionKey& newKey
}
void DurationMetricProducer::handleStartEvent(const MetricDimensionKey& eventKey,
- const ConditionKey& conditionKeys,
- bool condition, const LogEvent& event) {
+ const ConditionKey& conditionKeys, bool condition,
+ const int64_t eventTimeNs,
+ const vector<FieldValue>& eventValues) {
const auto& whatKey = eventKey.getDimensionKeyInWhat();
auto whatIt = mCurrentSlicedDurationTrackerMap.find(whatKey);
if (whatIt == mCurrentSlicedDurationTrackerMap.end()) {
@@ -608,20 +628,17 @@ void DurationMetricProducer::handleStartEvent(const MetricDimensionKey& eventKey
auto it = mCurrentSlicedDurationTrackerMap.find(whatKey);
if (mUseWhatDimensionAsInternalDimension) {
- it->second->noteStart(whatKey, condition, event.GetElapsedTimestampNs(), conditionKeys);
+ it->second->noteStart(whatKey, condition, eventTimeNs, conditionKeys);
return;
}
if (mInternalDimensions.empty()) {
- it->second->noteStart(DEFAULT_DIMENSION_KEY, condition, event.GetElapsedTimestampNs(),
- conditionKeys);
+ it->second->noteStart(DEFAULT_DIMENSION_KEY, condition, eventTimeNs, conditionKeys);
} else {
HashableDimensionKey dimensionKey = DEFAULT_DIMENSION_KEY;
- filterValues(mInternalDimensions, event.getValues(), &dimensionKey);
- it->second->noteStart(dimensionKey, condition, event.GetElapsedTimestampNs(),
- conditionKeys);
+ filterValues(mInternalDimensions, eventValues, &dimensionKey);
+ it->second->noteStart(dimensionKey, condition, eventTimeNs, conditionKeys);
}
-
}
void DurationMetricProducer::onMatchedLogEventInternalLocked(
@@ -633,26 +650,32 @@ void DurationMetricProducer::onMatchedLogEventInternalLocked(
void DurationMetricProducer::onMatchedLogEventLocked(const size_t matcherIndex,
const LogEvent& event) {
- int64_t eventTimeNs = event.GetElapsedTimestampNs();
+ handleMatchedLogEventValuesLocked(matcherIndex, event.getValues(),
+ event.GetElapsedTimestampNs());
+}
+
+void DurationMetricProducer::handleMatchedLogEventValuesLocked(const size_t matcherIndex,
+ const vector<FieldValue>& values,
+ const int64_t eventTimeNs) {
if (eventTimeNs < mTimeBaseNs) {
return;
}
if (mIsActive) {
- flushIfNeededLocked(event.GetElapsedTimestampNs());
+ flushIfNeededLocked(eventTimeNs);
}
// Handles Stopall events.
if ((int)matcherIndex == mStopAllIndex) {
for (auto& whatIt : mCurrentSlicedDurationTrackerMap) {
- whatIt.second->noteStopAll(event.GetElapsedTimestampNs());
+ whatIt.second->noteStopAll(eventTimeNs);
}
return;
}
HashableDimensionKey dimensionInWhat = DEFAULT_DIMENSION_KEY;
if (!mDimensionsInWhat.empty()) {
- filterValues(mDimensionsInWhat, event.getValues(), &dimensionInWhat);
+ filterValues(mDimensionsInWhat, values, &dimensionInWhat);
}
// Stores atom id to primary key pairs for each state atom that the metric is
@@ -663,8 +686,7 @@ void DurationMetricProducer::onMatchedLogEventLocked(const size_t matcherIndex,
// field values from the log event. These values will form a primary key
// that will be used to query StateTracker for the correct state value.
for (const auto& stateLink : mMetric2StateLinks) {
- getDimensionForState(event.getValues(), stateLink,
- &statePrimaryKeys[stateLink.stateAtomId]);
+ getDimensionForState(values, stateLink, &statePrimaryKeys[stateLink.stateAtomId]);
}
// For each sliced state, query StateTracker for the state value using
@@ -695,19 +717,19 @@ void DurationMetricProducer::onMatchedLogEventLocked(const size_t matcherIndex,
if (mUseWhatDimensionAsInternalDimension) {
auto whatIt = mCurrentSlicedDurationTrackerMap.find(dimensionInWhat);
if (whatIt != mCurrentSlicedDurationTrackerMap.end()) {
- whatIt->second->noteStop(dimensionInWhat, event.GetElapsedTimestampNs(), false);
+ whatIt->second->noteStop(dimensionInWhat, eventTimeNs, false);
}
return;
}
HashableDimensionKey internalDimensionKey = DEFAULT_DIMENSION_KEY;
if (!mInternalDimensions.empty()) {
- filterValues(mInternalDimensions, event.getValues(), &internalDimensionKey);
+ filterValues(mInternalDimensions, values, &internalDimensionKey);
}
auto whatIt = mCurrentSlicedDurationTrackerMap.find(dimensionInWhat);
if (whatIt != mCurrentSlicedDurationTrackerMap.end()) {
- whatIt->second->noteStop(internalDimensionKey, event.GetElapsedTimestampNs(), false);
+ whatIt->second->noteStop(internalDimensionKey, eventTimeNs, false);
}
return;
}
@@ -716,7 +738,7 @@ void DurationMetricProducer::onMatchedLogEventLocked(const size_t matcherIndex,
ConditionKey conditionKey;
if (mConditionSliced) {
for (const auto& link : mMetric2ConditionLinks) {
- getDimensionForCondition(event.getValues(), link, &conditionKey[link.conditionId]);
+ getDimensionForCondition(values, link, &conditionKey[link.conditionId]);
}
auto conditionState =
@@ -731,7 +753,7 @@ void DurationMetricProducer::onMatchedLogEventLocked(const size_t matcherIndex,
condition = condition && mIsActive;
handleStartEvent(MetricDimensionKey(dimensionInWhat, stateValuesKey), conditionKey, condition,
- event);
+ eventTimeNs, values);
}
size_t DurationMetricProducer::byteSizeLocked() const {
diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.h b/cmds/statsd/src/metrics/DurationMetricProducer.h
index 5feb09fc1c98..9fb586f7262f 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.h
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.h
@@ -40,8 +40,8 @@ class DurationMetricProducer : public MetricProducer {
public:
DurationMetricProducer(
const ConfigKey& key, const DurationMetric& durationMetric, const int conditionIndex,
- const vector<ConditionState>& initialConditionCache, const int startIndex,
- const int stopIndex, const int stopAllIndex, const bool nesting,
+ const vector<ConditionState>& initialConditionCache, const int whatIndex,
+ const int startIndex, const int stopIndex, const int stopAllIndex, const bool nesting,
const sp<ConditionWizard>& wizard, const uint64_t protoHash,
const FieldMatcher& internalDimensions, const int64_t timeBaseNs,
const int64_t startTimeNs,
@@ -74,8 +74,15 @@ protected:
const std::map<int, HashableDimensionKey>& statePrimaryKeys) override;
private:
+ // Initializes true dimensions of the 'what' predicate. Only to be called during initialization.
+ void initTrueDimensions(const int whatIndex, const int64_t startTimeNs);
+
+ void handleMatchedLogEventValuesLocked(const size_t matcherIndex,
+ const std::vector<FieldValue>& values,
+ const int64_t eventTimeNs);
void handleStartEvent(const MetricDimensionKey& eventKey, const ConditionKey& conditionKeys,
- bool condition, const LogEvent& event);
+ bool condition, const int64_t eventTimeNs,
+ const vector<FieldValue>& eventValues);
void onDumpReportLocked(const int64_t dumpTimeNs,
const bool include_current_partial_bucket,
diff --git a/cmds/statsd/src/metrics/parsing_utils/metrics_manager_util.cpp b/cmds/statsd/src/metrics/parsing_utils/metrics_manager_util.cpp
index 4474df4346cf..ff7938cc7243 100644
--- a/cmds/statsd/src/metrics/parsing_utils/metrics_manager_util.cpp
+++ b/cmds/statsd/src/metrics/parsing_utils/metrics_manager_util.cpp
@@ -450,7 +450,8 @@ optional<sp<MetricProducer>> createDurationMetricProducerAndUpdateMetadata(
return nullopt;
}
- const Predicate& durationWhat = config.predicate(what_it->second);
+ const int whatIndex = what_it->second;
+ const Predicate& durationWhat = config.predicate(whatIndex);
if (durationWhat.contents_case() != Predicate::ContentsCase::kSimplePredicate) {
ALOGE("DurationMetric's \"what\" must be a simple condition");
return nullopt;
@@ -536,10 +537,11 @@ optional<sp<MetricProducer>> createDurationMetricProducerAndUpdateMetadata(
return nullopt;
}
- return {new DurationMetricProducer(
- key, metric, conditionIndex, initialConditionCache, startIndex, stopIndex, stopAllIndex,
- nesting, wizard, metricHash, internalDimensions, timeBaseNs, currentTimeNs,
- eventActivationMap, eventDeactivationMap, slicedStateAtoms, stateGroupMap)};
+ return {new DurationMetricProducer(key, metric, conditionIndex, initialConditionCache,
+ whatIndex, startIndex, stopIndex, stopAllIndex, nesting,
+ wizard, metricHash, internalDimensions, timeBaseNs,
+ currentTimeNs, eventActivationMap, eventDeactivationMap,
+ slicedStateAtoms, stateGroupMap)};
}
optional<sp<MetricProducer>> createEventMetricProducerAndUpdateMetadata(
diff --git a/cmds/statsd/tests/e2e/ConfigUpdate_e2e_test.cpp b/cmds/statsd/tests/e2e/ConfigUpdate_e2e_test.cpp
index e01a0b63a0ca..22c4f5de2537 100644
--- a/cmds/statsd/tests/e2e/ConfigUpdate_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/ConfigUpdate_e2e_test.cpp
@@ -14,8 +14,6 @@
#include <gtest/gtest.h>
-#include <thread> // std::this_thread::sleep_for
-
#include "android-base/stringprintf.h"
#include "src/StatsLogProcessor.h"
#include "src/storage/StorageManager.h"
@@ -28,6 +26,7 @@ namespace statsd {
#ifdef __ANDROID__
#define STATS_DATA_DIR "/data/misc/stats-data"
using android::base::StringPrintf;
+using namespace std;
namespace {
@@ -298,6 +297,300 @@ TEST_P(ConfigUpdateE2eTest, TestConfigTtl) {
&buffer);
}
+TEST(ConfigUpdateE2eTest, TestNewDurationExistingWhat) {
+ StatsdConfig config;
+ config.add_allowed_log_source("AID_ROOT");
+ *config.add_atom_matcher() = CreateAcquireWakelockAtomMatcher();
+ *config.add_atom_matcher() = CreateReleaseWakelockAtomMatcher();
+
+ Predicate holdingWakelockPredicate = CreateHoldingWakelockPredicate();
+ *config.add_predicate() = holdingWakelockPredicate;
+
+ ConfigKey key(123, 987);
+ uint64_t bucketStartTimeNs = 10000000000; // 0:10
+ uint64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(FIVE_MINUTES) * 1000000LL;
+ sp<StatsLogProcessor> processor =
+ CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, key);
+
+ int app1Uid = 123;
+ vector<int> attributionUids1 = {app1Uid};
+ vector<string> attributionTags1 = {"App1"};
+ // Create a wakelock acquire, causing the condition to be true.
+ unique_ptr<LogEvent> event = CreateAcquireWakelockEvent(bucketStartTimeNs + 10 * NS_PER_SEC,
+ attributionUids1, attributionTags1,
+ "wl1"); // 0:10
+ processor->OnLogEvent(event.get());
+
+ // Add metric.
+ DurationMetric* durationMetric = config.add_duration_metric();
+ durationMetric->set_id(StringToId("WakelockDuration"));
+ durationMetric->set_what(holdingWakelockPredicate.id());
+ durationMetric->set_aggregation_type(DurationMetric::SUM);
+ durationMetric->set_bucket(FIVE_MINUTES);
+
+ uint64_t updateTimeNs = bucketStartTimeNs + 60 * NS_PER_SEC; // 1:00
+ processor->OnConfigUpdated(updateTimeNs, key, config, /*modular*/ true);
+
+ event = CreateReleaseWakelockEvent(bucketStartTimeNs + 80 * NS_PER_SEC, attributionUids1,
+ attributionTags1,
+ "wl1"); // 1:20
+ processor->OnLogEvent(event.get());
+ uint64_t dumpTimeNs = bucketStartTimeNs + 90 * NS_PER_SEC; // 1:30
+ ConfigMetricsReportList reports;
+ vector<uint8_t> buffer;
+ processor->onDumpReport(key, dumpTimeNs, true, true, ADB_DUMP, FAST, &buffer);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ backfillDimensionPath(&reports);
+ backfillStringInReport(&reports);
+ backfillStartEndTimestamp(&reports);
+ ASSERT_EQ(reports.reports_size(), 1);
+ ASSERT_EQ(reports.reports(0).metrics_size(), 1);
+ EXPECT_TRUE(reports.reports(0).metrics(0).has_duration_metrics());
+
+ StatsLogReport::DurationMetricDataWrapper metricData;
+ sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).duration_metrics(), &metricData);
+ ASSERT_EQ(metricData.data_size(), 1);
+ DurationMetricData data = metricData.data(0);
+ ASSERT_EQ(data.bucket_info_size(), 1);
+
+ DurationBucketInfo bucketInfo = data.bucket_info(0);
+ EXPECT_EQ(bucketInfo.start_bucket_elapsed_nanos(), updateTimeNs);
+ EXPECT_EQ(bucketInfo.end_bucket_elapsed_nanos(), dumpTimeNs);
+ EXPECT_EQ(bucketInfo.duration_nanos(), 20 * NS_PER_SEC);
+}
+
+TEST(ConfigUpdateE2eTest, TestNewDurationExistingWhatSlicedCondition) {
+ StatsdConfig config;
+ config.add_allowed_log_source("AID_ROOT");
+ *config.add_atom_matcher() = CreateAcquireWakelockAtomMatcher();
+ *config.add_atom_matcher() = CreateReleaseWakelockAtomMatcher();
+ *config.add_atom_matcher() = CreateMoveToBackgroundAtomMatcher();
+ *config.add_atom_matcher() = CreateMoveToForegroundAtomMatcher();
+
+ Predicate holdingWakelockPredicate = CreateHoldingWakelockPredicate();
+ // The predicate is dimensioning by first attribution node by uid.
+ *holdingWakelockPredicate.mutable_simple_predicate()->mutable_dimensions() =
+ CreateAttributionUidDimensions(util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
+ *config.add_predicate() = holdingWakelockPredicate;
+
+ Predicate isInBackgroundPredicate = CreateIsInBackgroundPredicate();
+ *isInBackgroundPredicate.mutable_simple_predicate()->mutable_dimensions() =
+ CreateDimensions(util::ACTIVITY_FOREGROUND_STATE_CHANGED, {1 /*uid*/});
+ *config.add_predicate() = isInBackgroundPredicate;
+
+ ConfigKey key(123, 987);
+ uint64_t bucketStartTimeNs = 10000000000; // 0:10
+ uint64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(FIVE_MINUTES) * 1000000LL;
+ sp<StatsLogProcessor> processor =
+ CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, key);
+
+ int app1Uid = 123, app2Uid = 456;
+ vector<int> attributionUids1 = {app1Uid};
+ vector<string> attributionTags1 = {"App1"};
+ vector<int> attributionUids2 = {app2Uid};
+ vector<string> attributionTags2 = {"App2"};
+ unique_ptr<LogEvent> event = CreateAcquireWakelockEvent(bucketStartTimeNs + 10 * NS_PER_SEC,
+ attributionUids1, attributionTags1,
+ "wl1"); // 0:10
+ processor->OnLogEvent(event.get());
+ event = CreateMoveToBackgroundEvent(bucketStartTimeNs + 22 * NS_PER_SEC, app1Uid); // 0:22
+ processor->OnLogEvent(event.get());
+ event = CreateAcquireWakelockEvent(bucketStartTimeNs + 35 * NS_PER_SEC, attributionUids2,
+ attributionTags2,
+ "wl1"); // 0:35
+ processor->OnLogEvent(event.get());
+
+ // Add metric.
+ DurationMetric* durationMetric = config.add_duration_metric();
+ durationMetric->set_id(StringToId("WakelockDuration"));
+ durationMetric->set_what(holdingWakelockPredicate.id());
+ durationMetric->set_condition(isInBackgroundPredicate.id());
+ durationMetric->set_aggregation_type(DurationMetric::SUM);
+ // The metric is dimensioning by first attribution node and only by uid.
+ *durationMetric->mutable_dimensions_in_what() =
+ CreateAttributionUidDimensions(util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
+ durationMetric->set_bucket(FIVE_MINUTES);
+ // Links between wakelock state atom and condition of app is in background.
+ auto links = durationMetric->add_links();
+ links->set_condition(isInBackgroundPredicate.id());
+ *links->mutable_fields_in_what() =
+ CreateAttributionUidDimensions(util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
+ *links->mutable_fields_in_condition() =
+ CreateDimensions(util::ACTIVITY_FOREGROUND_STATE_CHANGED, {1 /*uid*/});
+
+ uint64_t updateTimeNs = bucketStartTimeNs + 60 * NS_PER_SEC; // 1:00
+ processor->OnConfigUpdated(updateTimeNs, key, config, /*modular*/ true);
+
+ event = CreateMoveToBackgroundEvent(bucketStartTimeNs + 73 * NS_PER_SEC, app2Uid); // 1:13
+ processor->OnLogEvent(event.get());
+ event = CreateReleaseWakelockEvent(bucketStartTimeNs + 84 * NS_PER_SEC, attributionUids1,
+ attributionTags1, "wl1"); // 1:24
+ processor->OnLogEvent(event.get());
+
+ uint64_t dumpTimeNs = bucketStartTimeNs + 90 * NS_PER_SEC; // 1:30
+ ConfigMetricsReportList reports;
+ vector<uint8_t> buffer;
+ processor->onDumpReport(key, dumpTimeNs, true, true, ADB_DUMP, FAST, &buffer);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ backfillDimensionPath(&reports);
+ backfillStringInReport(&reports);
+ backfillStartEndTimestamp(&reports);
+ ASSERT_EQ(reports.reports_size(), 1);
+ ASSERT_EQ(reports.reports(0).metrics_size(), 1);
+ EXPECT_TRUE(reports.reports(0).metrics(0).has_duration_metrics());
+
+ StatsLogReport::DurationMetricDataWrapper metricData;
+ sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).duration_metrics(), &metricData);
+ ASSERT_EQ(metricData.data_size(), 2);
+
+ DurationMetricData data = metricData.data(0);
+ ValidateAttributionUidDimension(data.dimensions_in_what(), util::WAKELOCK_STATE_CHANGED,
+ app1Uid);
+ ASSERT_EQ(data.bucket_info_size(), 1);
+ DurationBucketInfo bucketInfo = data.bucket_info(0);
+ EXPECT_EQ(bucketInfo.duration_nanos(), 24 * NS_PER_SEC);
+
+ data = metricData.data(1);
+ ValidateAttributionUidDimension(data.dimensions_in_what(), util::WAKELOCK_STATE_CHANGED,
+ app2Uid);
+ ASSERT_EQ(data.bucket_info_size(), 1);
+ bucketInfo = data.bucket_info(0);
+ EXPECT_EQ(bucketInfo.duration_nanos(), 17 * NS_PER_SEC);
+}
+
+TEST(ConfigUpdateE2eTest, TestNewDurationExistingWhatSlicedState) {
+ StatsdConfig config;
+ config.add_allowed_log_source("AID_ROOT");
+ *config.add_atom_matcher() = CreateAcquireWakelockAtomMatcher();
+ *config.add_atom_matcher() = CreateReleaseWakelockAtomMatcher();
+
+ Predicate holdingWakelockPredicate = CreateHoldingWakelockPredicate();
+ // The predicate is dimensioning by first attribution node by uid.
+ *holdingWakelockPredicate.mutable_simple_predicate()->mutable_dimensions() =
+ CreateAttributionUidDimensions(util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
+ *config.add_predicate() = holdingWakelockPredicate;
+
+ auto uidProcessState = CreateUidProcessState();
+ *config.add_state() = uidProcessState;
+
+ // Count metric. We don't care about this one. Only use it so the StateTracker gets persisted.
+ CountMetric* countMetric = config.add_count_metric();
+ countMetric->set_id(StringToId("Tmp"));
+ countMetric->set_what(config.atom_matcher(0).id());
+ countMetric->add_slice_by_state(uidProcessState.id());
+ // The metric is dimensioning by first attribution node and only by uid.
+ *countMetric->mutable_dimensions_in_what() =
+ CreateAttributionUidDimensions(util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
+ countMetric->set_bucket(FIVE_MINUTES);
+ auto stateLink = countMetric->add_state_link();
+ stateLink->set_state_atom_id(util::UID_PROCESS_STATE_CHANGED);
+ *stateLink->mutable_fields_in_what() =
+ CreateAttributionUidDimensions(util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
+ *stateLink->mutable_fields_in_state() =
+ CreateDimensions(util::UID_PROCESS_STATE_CHANGED, {1 /*uid*/});
+ config.add_no_report_metric(countMetric->id());
+
+ ConfigKey key(123, 987);
+ uint64_t bucketStartTimeNs = 10000000000; // 0:10
+ uint64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(FIVE_MINUTES) * 1000000LL;
+ sp<StatsLogProcessor> processor =
+ CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, key);
+
+ int app1Uid = 123, app2Uid = 456;
+ vector<int> attributionUids1 = {app1Uid};
+ vector<string> attributionTags1 = {"App1"};
+ vector<int> attributionUids2 = {app2Uid};
+ vector<string> attributionTags2 = {"App2"};
+ unique_ptr<LogEvent> event = CreateUidProcessStateChangedEvent(
+ bucketStartTimeNs + 10 * NS_PER_SEC, app1Uid,
+ android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND); // 0:10
+ processor->OnLogEvent(event.get());
+ event = CreateAcquireWakelockEvent(bucketStartTimeNs + 22 * NS_PER_SEC, attributionUids1,
+ attributionTags1,
+ "wl1"); // 0:22
+ processor->OnLogEvent(event.get());
+ event = CreateUidProcessStateChangedEvent(
+ bucketStartTimeNs + 30 * NS_PER_SEC, app2Uid,
+ android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND); // 0:30
+ processor->OnLogEvent(event.get());
+
+ // Add metric.
+ DurationMetric* durationMetric = config.add_duration_metric();
+ durationMetric->set_id(StringToId("WakelockDuration"));
+ durationMetric->set_what(holdingWakelockPredicate.id());
+ durationMetric->add_slice_by_state(uidProcessState.id());
+ durationMetric->set_aggregation_type(DurationMetric::SUM);
+ // The metric is dimensioning by first attribution node and only by uid.
+ *durationMetric->mutable_dimensions_in_what() =
+ CreateAttributionUidDimensions(util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
+ durationMetric->set_bucket(FIVE_MINUTES);
+ // Links between wakelock state atom and condition of app is in background.
+ stateLink = durationMetric->add_state_link();
+ stateLink->set_state_atom_id(util::UID_PROCESS_STATE_CHANGED);
+ *stateLink->mutable_fields_in_what() =
+ CreateAttributionUidDimensions(util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
+ *stateLink->mutable_fields_in_state() =
+ CreateDimensions(util::UID_PROCESS_STATE_CHANGED, {1 /*uid*/});
+
+ uint64_t updateTimeNs = bucketStartTimeNs + 60 * NS_PER_SEC; // 1:00
+ processor->OnConfigUpdated(updateTimeNs, key, config, /*modular*/ true);
+
+ event = CreateAcquireWakelockEvent(bucketStartTimeNs + 72 * NS_PER_SEC, attributionUids2,
+ attributionTags2,
+ "wl1"); // 1:13
+ processor->OnLogEvent(event.get());
+ event = CreateUidProcessStateChangedEvent(
+ bucketStartTimeNs + 75 * NS_PER_SEC, app1Uid,
+ android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_BACKGROUND); // 1:15
+ processor->OnLogEvent(event.get());
+ event = CreateReleaseWakelockEvent(bucketStartTimeNs + 84 * NS_PER_SEC, attributionUids1,
+ attributionTags1, "wl1"); // 1:24
+ processor->OnLogEvent(event.get());
+
+ uint64_t dumpTimeNs = bucketStartTimeNs + 90 * NS_PER_SEC; // 1:30
+ ConfigMetricsReportList reports;
+ vector<uint8_t> buffer;
+ processor->onDumpReport(key, dumpTimeNs, true, true, ADB_DUMP, FAST, &buffer);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ backfillDimensionPath(&reports);
+ backfillStringInReport(&reports);
+ backfillStartEndTimestamp(&reports);
+ ASSERT_EQ(reports.reports_size(), 1);
+ ASSERT_EQ(reports.reports(0).metrics_size(), 1);
+ EXPECT_TRUE(reports.reports(0).metrics(0).has_duration_metrics());
+
+ StatsLogReport::DurationMetricDataWrapper metricData;
+ sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).duration_metrics(), &metricData);
+ ASSERT_EQ(metricData.data_size(), 3);
+
+ DurationMetricData data = metricData.data(0);
+ ValidateAttributionUidDimension(data.dimensions_in_what(), util::WAKELOCK_STATE_CHANGED,
+ app1Uid);
+ ValidateStateValue(data.slice_by_state(), util::UID_PROCESS_STATE_CHANGED,
+ android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND);
+ ASSERT_EQ(data.bucket_info_size(), 1);
+ DurationBucketInfo bucketInfo = data.bucket_info(0);
+ EXPECT_EQ(bucketInfo.duration_nanos(), 15 * NS_PER_SEC);
+
+ data = metricData.data(1);
+ ValidateAttributionUidDimension(data.dimensions_in_what(), util::WAKELOCK_STATE_CHANGED,
+ app1Uid);
+ ValidateStateValue(data.slice_by_state(), util::UID_PROCESS_STATE_CHANGED,
+ android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_BACKGROUND);
+ ASSERT_EQ(data.bucket_info_size(), 1);
+ bucketInfo = data.bucket_info(0);
+ EXPECT_EQ(bucketInfo.duration_nanos(), 9 * NS_PER_SEC);
+
+ data = metricData.data(2);
+ ValidateAttributionUidDimension(data.dimensions_in_what(), util::WAKELOCK_STATE_CHANGED,
+ app2Uid);
+ ValidateStateValue(data.slice_by_state(), util::UID_PROCESS_STATE_CHANGED,
+ android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND);
+ ASSERT_EQ(data.bucket_info_size(), 1);
+ bucketInfo = data.bucket_info(0);
+ EXPECT_EQ(bucketInfo.duration_nanos(), 18 * NS_PER_SEC);
+}
+
#else
GTEST_LOG_(INFO) << "This test does nothing.\n";
#endif
diff --git a/cmds/statsd/tests/metrics/DurationMetricProducer_test.cpp b/cmds/statsd/tests/metrics/DurationMetricProducer_test.cpp
index d1f89775ed6a..bb2ede4ddc2b 100644
--- a/cmds/statsd/tests/metrics/DurationMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/DurationMetricProducer_test.cpp
@@ -73,9 +73,9 @@ TEST(DurationMetricTrackerTest, TestFirstBucket) {
FieldMatcher dimensions;
DurationMetricProducer durationProducer(
- kConfigKey, metric, -1 /*no condition*/, {}, 1 /* start index */, 2 /* stop index */,
- 3 /* stop_all index */, false /*nesting*/, wizard, protoHash, dimensions, 5,
- 600 * NS_PER_SEC + NS_PER_SEC / 2);
+ kConfigKey, metric, -1 /*no condition*/, {}, -1 /*what index not needed*/,
+ 1 /* start index */, 2 /* stop index */, 3 /* stop_all index */, false /*nesting*/,
+ wizard, protoHash, dimensions, 5, 600 * NS_PER_SEC + NS_PER_SEC / 2);
EXPECT_EQ(600500000000, durationProducer.mCurrentBucketStartTimeNs);
EXPECT_EQ(10, durationProducer.mCurrentBucketNum);
@@ -101,9 +101,9 @@ TEST(DurationMetricTrackerTest, TestNoCondition) {
FieldMatcher dimensions;
DurationMetricProducer durationProducer(
- kConfigKey, metric, -1 /*no condition*/, {}, 1 /* start index */, 2 /* stop index */,
- 3 /* stop_all index */, false /*nesting*/, wizard, protoHash, dimensions,
- bucketStartTimeNs, bucketStartTimeNs);
+ kConfigKey, metric, -1 /*no condition*/, {}, -1 /*what index not needed*/,
+ 1 /* start index */, 2 /* stop index */, 3 /* stop_all index */, false /*nesting*/,
+ wizard, protoHash, dimensions, bucketStartTimeNs, bucketStartTimeNs);
durationProducer.onMatchedLogEvent(1 /* start index*/, event1);
durationProducer.onMatchedLogEvent(2 /* stop index*/, event2);
@@ -145,8 +145,9 @@ TEST(DurationMetricTrackerTest, TestNonSlicedCondition) {
DurationMetricProducer durationProducer(
kConfigKey, metric, 0 /* condition index */, {ConditionState::kUnknown},
- 1 /* start index */, 2 /* stop index */, 3 /* stop_all index */, false /*nesting*/,
- wizard, protoHash, dimensions, bucketStartTimeNs, bucketStartTimeNs);
+ -1 /*what index not needed*/, 1 /* start index */, 2 /* stop index */,
+ 3 /* stop_all index */, false /*nesting*/, wizard, protoHash, dimensions,
+ bucketStartTimeNs, bucketStartTimeNs);
durationProducer.mCondition = ConditionState::kFalse;
EXPECT_FALSE(durationProducer.mCondition);
@@ -195,8 +196,9 @@ TEST(DurationMetricTrackerTest, TestNonSlicedConditionUnknownState) {
DurationMetricProducer durationProducer(
kConfigKey, metric, 0 /* condition index */, {ConditionState::kUnknown},
- 1 /* start index */, 2 /* stop index */, 3 /* stop_all index */, false /*nesting*/,
- wizard, protoHash, dimensions, bucketStartTimeNs, bucketStartTimeNs);
+ -1 /*what index not needed*/, 1 /* start index */, 2 /* stop index */,
+ 3 /* stop_all index */, false /*nesting*/, wizard, protoHash, dimensions,
+ bucketStartTimeNs, bucketStartTimeNs);
EXPECT_EQ(ConditionState::kUnknown, durationProducer.mCondition);
EXPECT_FALSE(durationProducer.isConditionSliced());
@@ -240,9 +242,9 @@ TEST_P(DurationMetricProducerTest_PartialBucket, TestSumDuration) {
FieldMatcher dimensions;
DurationMetricProducer durationProducer(
- kConfigKey, metric, -1 /* no condition */, {}, 1 /* start index */, 2 /* stop index */,
- 3 /* stop_all index */, false /*nesting*/, wizard, protoHash, dimensions,
- bucketStartTimeNs, bucketStartTimeNs);
+ kConfigKey, metric, -1 /* no condition */, {}, -1 /*what index not needed*/,
+ 1 /* start index */, 2 /* stop index */, 3 /* stop_all index */, false /*nesting*/,
+ wizard, protoHash, dimensions, bucketStartTimeNs, bucketStartTimeNs);
int64_t startTimeNs = bucketStartTimeNs + 1 * NS_PER_SEC;
LogEvent event1(/*uid=*/0, /*pid=*/0);
@@ -303,9 +305,9 @@ TEST_P(DurationMetricProducerTest_PartialBucket, TestSumDurationWithSplitInFollo
FieldMatcher dimensions;
DurationMetricProducer durationProducer(
- kConfigKey, metric, -1 /* no condition */, {}, 1 /* start index */, 2 /* stop index */,
- 3 /* stop_all index */, false /*nesting*/, wizard, protoHash, dimensions,
- bucketStartTimeNs, bucketStartTimeNs);
+ kConfigKey, metric, -1 /* no condition */, {}, -1 /*what index not needed*/,
+ 1 /* start index */, 2 /* stop index */, 3 /* stop_all index */, false /*nesting*/,
+ wizard, protoHash, dimensions, bucketStartTimeNs, bucketStartTimeNs);
int64_t startTimeNs = bucketStartTimeNs + 1 * NS_PER_SEC;
LogEvent event1(/*uid=*/0, /*pid=*/0);
@@ -367,9 +369,9 @@ TEST_P(DurationMetricProducerTest_PartialBucket, TestSumDurationAnomaly) {
FieldMatcher dimensions;
DurationMetricProducer durationProducer(
- kConfigKey, metric, -1 /* no condition */, {}, 1 /* start index */, 2 /* stop index */,
- 3 /* stop_all index */, false /*nesting*/, wizard, protoHash, dimensions,
- bucketStartTimeNs, bucketStartTimeNs);
+ kConfigKey, metric, -1 /* no condition */, {}, -1 /*what index not needed*/,
+ 1 /* start index */, 2 /* stop index */, 3 /* stop_all index */, false /*nesting*/,
+ wizard, protoHash, dimensions, bucketStartTimeNs, bucketStartTimeNs);
sp<AnomalyTracker> anomalyTracker = durationProducer.addAnomalyTracker(alert, alarmMonitor);
EXPECT_TRUE(anomalyTracker != nullptr);
@@ -413,9 +415,9 @@ TEST_P(DurationMetricProducerTest_PartialBucket, TestMaxDuration) {
FieldMatcher dimensions;
DurationMetricProducer durationProducer(
- kConfigKey, metric, -1 /* no condition */, {}, 1 /* start index */, 2 /* stop index */,
- 3 /* stop_all index */, false /*nesting*/, wizard, protoHash, dimensions,
- bucketStartTimeNs, bucketStartTimeNs);
+ kConfigKey, metric, -1 /* no condition */, {}, -1 /*what index not needed*/,
+ 1 /* start index */, 2 /* stop index */, 3 /* stop_all index */, false /*nesting*/,
+ wizard, protoHash, dimensions, bucketStartTimeNs, bucketStartTimeNs);
int64_t startTimeNs = bucketStartTimeNs + 1;
LogEvent event1(/*uid=*/0, /*pid=*/0);
@@ -467,9 +469,9 @@ TEST_P(DurationMetricProducerTest_PartialBucket, TestMaxDurationWithSplitInNextB
FieldMatcher dimensions;
DurationMetricProducer durationProducer(
- kConfigKey, metric, -1 /* no condition */, {}, 1 /* start index */, 2 /* stop index */,
- 3 /* stop_all index */, false /*nesting*/, wizard, protoHash, dimensions,
- bucketStartTimeNs, bucketStartTimeNs);
+ kConfigKey, metric, -1 /* no condition */, {}, -1 /*what index not needed*/,
+ 1 /* start index */, 2 /* stop index */, 3 /* stop_all index */, false /*nesting*/,
+ wizard, protoHash, dimensions, bucketStartTimeNs, bucketStartTimeNs);
int64_t startTimeNs = bucketStartTimeNs + 1;
LogEvent event1(/*uid=*/0, /*pid=*/0);
diff --git a/cmds/statsd/tests/metrics/parsing_utils/metrics_manager_util_test.cpp b/cmds/statsd/tests/metrics/parsing_utils/metrics_manager_util_test.cpp
index 9e2350b33018..88df2ff0caa8 100644
--- a/cmds/statsd/tests/metrics/parsing_utils/metrics_manager_util_test.cpp
+++ b/cmds/statsd/tests/metrics/parsing_utils/metrics_manager_util_test.cpp
@@ -875,8 +875,9 @@ TEST(MetricsManagerTest, TestCreateAnomalyTrackerDurationTooLong) {
FieldMatcher dimensions;
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
vector<sp<MetricProducer>> metricProducers({new DurationMetricProducer(
- kConfigKey, metric, -1 /*no condition*/, {}, 1 /* start index */, 2 /* stop index */,
- 3 /* stop_all index */, false /*nesting*/, wizard, 0x0123456789, dimensions, 0, 0)});
+ kConfigKey, metric, -1 /*no condition*/, {}, -1 /* what index not needed*/,
+ 1 /* start index */, 2 /* stop index */, 3 /* stop_all index */, false /*nesting*/,
+ wizard, 0x0123456789, dimensions, 0, 0)});
sp<AlarmMonitor> anomalyAlarmMonitor;
EXPECT_EQ(createAnomalyTracker(alert, anomalyAlarmMonitor, {{1, 0}}, metricProducers), nullopt);
}
diff --git a/cmds/statsd/tests/statsd_test_util.cpp b/cmds/statsd/tests/statsd_test_util.cpp
index 1761d5d9e1fa..153b696808dc 100644
--- a/cmds/statsd/tests/statsd_test_util.cpp
+++ b/cmds/statsd/tests/statsd_test_util.cpp
@@ -1091,6 +1091,21 @@ void ValidateAttributionUidAndTagDimension(
.value_tuple().dimensions_value(1).value_str(), tag);
}
+void ValidateStateValue(const google::protobuf::RepeatedPtrField<StateValue>& stateValues,
+ int atomId, int64_t value) {
+ ASSERT_EQ(stateValues.size(), 1);
+ ASSERT_EQ(stateValues[0].atom_id(), atomId);
+ switch (stateValues[0].contents_case()) {
+ case StateValue::ContentsCase::kValue:
+ EXPECT_EQ(stateValues[0].value(), (int32_t)value);
+ break;
+ case StateValue::ContentsCase::kGroupId:
+ EXPECT_EQ(stateValues[0].group_id(), value);
+ break;
+ default:
+ FAIL() << "State value should have either a value or a group id";
+ }
+}
bool EqualsTo(const DimensionsValue& s1, const DimensionsValue& s2) {
if (s1.field() != s2.field()) {
return false;
diff --git a/cmds/statsd/tests/statsd_test_util.h b/cmds/statsd/tests/statsd_test_util.h
index 1220019e2353..c51491244fd8 100644
--- a/cmds/statsd/tests/statsd_test_util.h
+++ b/cmds/statsd/tests/statsd_test_util.h
@@ -347,6 +347,8 @@ void ValidateAttributionUidAndTagDimension(
const DimensionsValue& value, int atomId, int uid, const std::string& tag);
void ValidateAttributionUidAndTagDimension(
const DimensionsValue& value, int node_idx, int atomId, int uid, const std::string& tag);
+void ValidateStateValue(const google::protobuf::RepeatedPtrField<StateValue>& stateValues,
+ int atomId, int64_t value);
struct DimensionsPair {
DimensionsPair(DimensionsValue m1, google::protobuf::RepeatedPtrField<StateValue> m2)
diff --git a/core/api/current.txt b/core/api/current.txt
index e302b25873b4..00acae1b1025 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -6968,6 +6968,7 @@ package android.app.admin {
method public boolean grantKeyPairToApp(@Nullable android.content.ComponentName, @NonNull String, @NonNull String);
method public boolean hasCaCertInstalled(@Nullable android.content.ComponentName, byte[]);
method public boolean hasGrantedPolicy(@NonNull android.content.ComponentName, int);
+ method public boolean hasKeyPair(@NonNull String);
method public boolean hasLockdownAdminConfiguredNetworks(@NonNull android.content.ComponentName);
method public boolean installCaCert(@Nullable android.content.ComponentName, byte[]);
method public boolean installExistingPackage(@NonNull android.content.ComponentName, String);
@@ -7343,6 +7344,7 @@ package android.app.admin {
field public static final int TAG_MEDIA_UNMOUNT = 210014; // 0x3345e
field public static final int TAG_OS_SHUTDOWN = 210010; // 0x3345a
field public static final int TAG_OS_STARTUP = 210009; // 0x33459
+ field public static final int TAG_PASSWORD_COMPLEXITY_REQUIRED = 210035; // 0x33473
field public static final int TAG_PASSWORD_COMPLEXITY_SET = 210017; // 0x33461
field public static final int TAG_PASSWORD_EXPIRATION_SET = 210016; // 0x33460
field public static final int TAG_PASSWORD_HISTORY_LENGTH_SET = 210018; // 0x33462
@@ -9096,6 +9098,15 @@ package android.bluetooth {
field @NonNull public static final android.os.Parcelable.Creator<android.bluetooth.BluetoothHidDeviceAppSdpSettings> CREATOR;
}
+ public final class BluetoothLeAudio implements java.lang.AutoCloseable android.bluetooth.BluetoothProfile {
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public void close();
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) protected void finalize();
+ method @NonNull public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public int getConnectionState(@NonNull android.bluetooth.BluetoothDevice);
+ method @NonNull public java.util.List<android.bluetooth.BluetoothDevice> getDevicesMatchingConnectionStates(@NonNull int[]);
+ field public static final String ACTION_LE_AUDIO_CONNECTION_STATE_CHANGED = "android.bluetooth.action.LE_AUDIO_CONNECTION_STATE_CHANGED";
+ }
+
public final class BluetoothManager {
method public android.bluetooth.BluetoothAdapter getAdapter();
method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices(int);
@@ -45126,6 +45137,7 @@ package android.telephony {
field public static final int DATA_CYCLE_THRESHOLD_DISABLED = -2; // 0xfffffffe
field public static final int DATA_CYCLE_USE_PLATFORM_DEFAULT = -1; // 0xffffffff
field public static final String ENABLE_EAP_METHOD_PREFIX_BOOL = "enable_eap_method_prefix_bool";
+ field public static final String EXTRA_REBROADCAST_ON_UNLOCK = "android.telephony.extra.REBROADCAST_ON_UNLOCK";
field public static final String EXTRA_SLOT_INDEX = "android.telephony.extra.SLOT_INDEX";
field public static final String EXTRA_SUBSCRIPTION_INDEX = "android.telephony.extra.SUBSCRIPTION_INDEX";
field public static final String IMSI_KEY_AVAILABILITY_INT = "imsi_key_availability_int";
@@ -45153,6 +45165,7 @@ package android.telephony {
field public static final String KEY_CALL_BARRING_SUPPORTS_DEACTIVATE_ALL_BOOL = "call_barring_supports_deactivate_all_bool";
field public static final String KEY_CALL_BARRING_SUPPORTS_PASSWORD_CHANGE_BOOL = "call_barring_supports_password_change_bool";
field public static final String KEY_CALL_BARRING_VISIBILITY_BOOL = "call_barring_visibility_bool";
+ field public static final String KEY_CALL_COMPOSER_PICTURE_SERVER_URL_STRING = "call_composer_picture_server_url_string";
field public static final String KEY_CALL_FORWARDING_BLOCKS_WHILE_ROAMING_STRING_ARRAY = "call_forwarding_blocks_while_roaming_string_array";
field public static final String KEY_CALL_REDIRECTION_SERVICE_COMPONENT_NAME_STRING = "call_redirection_service_component_name_string";
field public static final String KEY_CARRIER_ALLOW_DEFLECT_IMS_CALL_BOOL = "carrier_allow_deflect_ims_call_bool";
@@ -45342,6 +45355,7 @@ package android.telephony {
field public static final String KEY_SIMPLIFIED_NETWORK_SETTINGS_BOOL = "simplified_network_settings_bool";
field public static final String KEY_SIM_NETWORK_UNLOCK_ALLOW_DISMISS_BOOL = "sim_network_unlock_allow_dismiss_bool";
field public static final String KEY_SMS_REQUIRES_DESTINATION_NUMBER_CONVERSION_BOOL = "sms_requires_destination_number_conversion_bool";
+ field public static final String KEY_SUPPORTS_CALL_COMPOSER_BOOL = "supports_call_composer_bool";
field public static final String KEY_SUPPORT_3GPP_CALL_FORWARDING_WHILE_ROAMING_BOOL = "support_3gpp_call_forwarding_while_roaming_bool";
field public static final String KEY_SUPPORT_ADD_CONFERENCE_PARTICIPANTS_BOOL = "support_add_conference_participants_bool";
field public static final String KEY_SUPPORT_ADHOC_CONFERENCE_CALLS_BOOL = "support_adhoc_conference_calls_bool";
@@ -45400,6 +45414,7 @@ package android.telephony {
}
public static final class CarrierConfigManager.Ims {
+ field public static final String KEY_ENABLE_PRESENCE_PUBLISH_BOOL = "ims.enable_presence_publish_bool";
field public static final String KEY_IMS_SINGLE_REGISTRATION_REQUIRED_BOOL = "ims.ims_single_registration_required_bool";
field public static final String KEY_PREFIX = "ims.";
field public static final String KEY_WIFI_OFF_DEFERRING_TIME_MILLIS_INT = "ims.wifi_off_deferring_time_millis_int";
@@ -50849,6 +50864,33 @@ package android.view {
method public void onActionViewExpanded();
}
+ public final class ContentInfo {
+ method @NonNull public android.content.ClipData getClip();
+ method @Nullable public android.os.Bundle getExtras();
+ method public int getFlags();
+ method @Nullable public android.net.Uri getLinkUri();
+ method public int getSource();
+ method @NonNull public java.util.Map<java.lang.Boolean,android.view.ContentInfo> partition(@NonNull java.util.function.Predicate<android.content.ClipData.Item>);
+ field public static final int FLAG_CONVERT_TO_PLAIN_TEXT = 1; // 0x1
+ field public static final int SOURCE_APP = 0; // 0x0
+ field public static final int SOURCE_AUTOFILL = 4; // 0x4
+ field public static final int SOURCE_CLIPBOARD = 1; // 0x1
+ field public static final int SOURCE_DRAG_AND_DROP = 3; // 0x3
+ field public static final int SOURCE_INPUT_METHOD = 2; // 0x2
+ field public static final int SOURCE_PROCESS_TEXT = 5; // 0x5
+ }
+
+ public static final class ContentInfo.Builder {
+ ctor public ContentInfo.Builder(@NonNull android.view.ContentInfo);
+ ctor public ContentInfo.Builder(@NonNull android.content.ClipData, int);
+ method @NonNull public android.view.ContentInfo build();
+ method @NonNull public android.view.ContentInfo.Builder setClip(@NonNull android.content.ClipData);
+ method @NonNull public android.view.ContentInfo.Builder setExtras(@Nullable android.os.Bundle);
+ method @NonNull public android.view.ContentInfo.Builder setFlags(int);
+ method @NonNull public android.view.ContentInfo.Builder setLinkUri(@Nullable android.net.Uri);
+ method @NonNull public android.view.ContentInfo.Builder setSource(int);
+ }
+
public interface ContextMenu extends android.view.Menu {
method public void clearHeader();
method public android.view.ContextMenu setHeaderIcon(@DrawableRes int);
@@ -52064,34 +52106,7 @@ package android.view {
}
public interface OnReceiveContentListener {
- method @Nullable public android.view.OnReceiveContentListener.Payload onReceiveContent(@NonNull android.view.View, @NonNull android.view.OnReceiveContentListener.Payload);
- }
-
- public static final class OnReceiveContentListener.Payload {
- method @NonNull public android.content.ClipData getClip();
- method @Nullable public android.os.Bundle getExtras();
- method public int getFlags();
- method @Nullable public android.net.Uri getLinkUri();
- method public int getSource();
- method @NonNull public java.util.Map<java.lang.Boolean,android.view.OnReceiveContentListener.Payload> partition(@NonNull java.util.function.Predicate<android.content.ClipData.Item>);
- field public static final int FLAG_CONVERT_TO_PLAIN_TEXT = 1; // 0x1
- field public static final int SOURCE_APP = 0; // 0x0
- field public static final int SOURCE_AUTOFILL = 4; // 0x4
- field public static final int SOURCE_CLIPBOARD = 1; // 0x1
- field public static final int SOURCE_DRAG_AND_DROP = 3; // 0x3
- field public static final int SOURCE_INPUT_METHOD = 2; // 0x2
- field public static final int SOURCE_PROCESS_TEXT = 5; // 0x5
- }
-
- public static final class OnReceiveContentListener.Payload.Builder {
- ctor public OnReceiveContentListener.Payload.Builder(@NonNull android.view.OnReceiveContentListener.Payload);
- ctor public OnReceiveContentListener.Payload.Builder(@NonNull android.content.ClipData, int);
- method @NonNull public android.view.OnReceiveContentListener.Payload build();
- method @NonNull public android.view.OnReceiveContentListener.Payload.Builder setClip(@NonNull android.content.ClipData);
- method @NonNull public android.view.OnReceiveContentListener.Payload.Builder setExtras(@Nullable android.os.Bundle);
- method @NonNull public android.view.OnReceiveContentListener.Payload.Builder setFlags(int);
- method @NonNull public android.view.OnReceiveContentListener.Payload.Builder setLinkUri(@Nullable android.net.Uri);
- method @NonNull public android.view.OnReceiveContentListener.Payload.Builder setSource(int);
+ method @Nullable public android.view.ContentInfo onReceiveContent(@NonNull android.view.View, @NonNull android.view.ContentInfo);
}
public abstract class OrientationEventListener {
@@ -52842,7 +52857,7 @@ package android.view {
method public void onProvideContentCaptureStructure(@NonNull android.view.ViewStructure, int);
method public void onProvideStructure(android.view.ViewStructure);
method public void onProvideVirtualStructure(android.view.ViewStructure);
- method @Nullable public android.view.OnReceiveContentListener.Payload onReceiveContent(@NonNull android.view.OnReceiveContentListener.Payload);
+ method @Nullable public android.view.ContentInfo onReceiveContent(@NonNull android.view.ContentInfo);
method public android.view.PointerIcon onResolvePointerIcon(android.view.MotionEvent, int);
method @CallSuper protected void onRestoreInstanceState(android.os.Parcelable);
method public void onRtlPropertiesChanged(int);
@@ -52868,7 +52883,7 @@ package android.view {
method public boolean performHapticFeedback(int, int);
method public boolean performLongClick();
method public boolean performLongClick(float, float);
- method @Nullable public android.view.OnReceiveContentListener.Payload performReceiveContent(@NonNull android.view.OnReceiveContentListener.Payload);
+ method @Nullable public android.view.ContentInfo performReceiveContent(@NonNull android.view.ContentInfo);
method public void playSoundEffect(int);
method public boolean post(Runnable);
method public boolean postDelayed(Runnable, long);
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 99179ec89cbc..a5f2b6ac3af8 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -248,7 +248,9 @@ package android {
field public static final String USE_RESERVED_DISK = "android.permission.USE_RESERVED_DISK";
field public static final String WHITELIST_AUTO_REVOKE_PERMISSIONS = "android.permission.WHITELIST_AUTO_REVOKE_PERMISSIONS";
field public static final String WHITELIST_RESTRICTED_PERMISSIONS = "android.permission.WHITELIST_RESTRICTED_PERMISSIONS";
+ field public static final String WIFI_ACCESS_COEX_UNSAFE_CHANNELS = "android.permission.WIFI_ACCESS_COEX_UNSAFE_CHANNELS";
field public static final String WIFI_SET_DEVICE_MOBILITY_STATE = "android.permission.WIFI_SET_DEVICE_MOBILITY_STATE";
+ field public static final String WIFI_UPDATE_COEX_UNSAFE_CHANNELS = "android.permission.WIFI_UPDATE_COEX_UNSAFE_CHANNELS";
field public static final String WIFI_UPDATE_USABILITY_STATS_SCORE = "android.permission.WIFI_UPDATE_USABILITY_STATS_SCORE";
field public static final String WRITE_DEVICE_CONFIG = "android.permission.WRITE_DEVICE_CONFIG";
field public static final String WRITE_DREAM_STATE = "android.permission.WRITE_DREAM_STATE";
@@ -6504,6 +6506,7 @@ package android.net {
field @Deprecated public static final int TETHER_ERROR_NO_ERROR = 0; // 0x0
field @Deprecated public static final int TETHER_ERROR_PROVISION_FAILED = 11; // 0xb
field public static final int TYPE_NONE = -1; // 0xffffffff
+ field @Deprecated public static final int TYPE_PROXY = 16; // 0x10
field @Deprecated public static final int TYPE_WIFI_P2P = 13; // 0xd
}
@@ -8420,6 +8423,8 @@ package android.provider {
field public static final String NAMESPACE_RUNTIME_NATIVE = "runtime_native";
field public static final String NAMESPACE_RUNTIME_NATIVE_BOOT = "runtime_native_boot";
field public static final String NAMESPACE_SCHEDULER = "scheduler";
+ field public static final String NAMESPACE_STATSD_NATIVE = "statsd_native";
+ field public static final String NAMESPACE_STATSD_NATIVE_BOOT = "statsd_native_boot";
field @Deprecated public static final String NAMESPACE_STORAGE = "storage";
field public static final String NAMESPACE_STORAGE_NATIVE_BOOT = "storage_native_boot";
field public static final String NAMESPACE_SYSTEMUI = "systemui";
@@ -10827,6 +10832,7 @@ package android.telephony {
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isEmergencyAssistanceEnabled();
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) @WorkerThread public boolean isIccLockEnabled();
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isIdle();
+ method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isInEmergencySmsMode();
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isLteCdmaEvdoGsmWcdmaEnabled();
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isMobileDataPolicyEnabled(int);
method public boolean isNrDualConnectivityEnabled();
@@ -11432,6 +11438,61 @@ package android.telephony.ims {
field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ims.AudioCodecAttributes> CREATOR;
}
+ public interface DelegateMessageCallback {
+ method public void onMessageReceived(@NonNull android.telephony.ims.SipMessage);
+ method public void onMessageSendFailure(@NonNull String, int);
+ method public void onMessageSent(@NonNull String);
+ }
+
+ public final class DelegateRegistrationState implements android.os.Parcelable {
+ method public int describeContents();
+ method @NonNull public java.util.Set<android.telephony.ims.FeatureTagState> getDeregisteredFeatureTags();
+ method @NonNull public java.util.Set<android.telephony.ims.FeatureTagState> getDeregisteringFeatureTags();
+ method @NonNull public java.util.Set<java.lang.String> getRegisteredFeatureTags();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ims.DelegateRegistrationState> CREATOR;
+ field public static final int DEREGISTERED_REASON_NOT_PROVISIONED = 1; // 0x1
+ field public static final int DEREGISTERED_REASON_NOT_REGISTERED = 2; // 0x2
+ field public static final int DEREGISTERED_REASON_UNKNOWN = 0; // 0x0
+ field public static final int DEREGISTERING_REASON_DESTROY_PENDING = 6; // 0x6
+ field public static final int DEREGISTERING_REASON_FEATURE_TAGS_CHANGING = 5; // 0x5
+ field public static final int DEREGISTERING_REASON_PDN_CHANGE = 3; // 0x3
+ field public static final int DEREGISTERING_REASON_PROVISIONING_CHANGE = 4; // 0x4
+ }
+
+ public static final class DelegateRegistrationState.Builder {
+ ctor public DelegateRegistrationState.Builder();
+ method @NonNull public android.telephony.ims.DelegateRegistrationState.Builder addDeregisteredFeatureTag(@NonNull String, int);
+ method @NonNull public android.telephony.ims.DelegateRegistrationState.Builder addDeregisteringFeatureTag(@NonNull String, int);
+ method @NonNull public android.telephony.ims.DelegateRegistrationState.Builder addRegisteredFeatureTag(@NonNull String);
+ method @NonNull public android.telephony.ims.DelegateRegistrationState.Builder addRegisteredFeatureTags(@NonNull java.util.Set<java.lang.String>);
+ method @NonNull public android.telephony.ims.DelegateRegistrationState build();
+ }
+
+ public final class DelegateRequest implements android.os.Parcelable {
+ ctor public DelegateRequest(@NonNull java.util.Set<java.lang.String>);
+ method public int describeContents();
+ method @NonNull public java.util.Set<java.lang.String> getFeatureTags();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ims.DelegateRequest> CREATOR;
+ }
+
+ public interface DelegateStateCallback {
+ method public void onCreated(@NonNull android.telephony.ims.stub.SipDelegate, @Nullable java.util.Set<android.telephony.ims.FeatureTagState>);
+ method public void onDestroyed(int);
+ method public void onFeatureTagRegistrationChanged(@NonNull android.telephony.ims.DelegateRegistrationState);
+ method public void onImsConfigurationChanged(@NonNull android.telephony.ims.SipDelegateImsConfiguration);
+ }
+
+ public final class FeatureTagState implements android.os.Parcelable {
+ ctor public FeatureTagState(@NonNull String, int);
+ method public int describeContents();
+ method @NonNull public String getFeatureTag();
+ method public int getState();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ims.FeatureTagState> CREATOR;
+ }
+
public final class ImsCallForwardInfo implements android.os.Parcelable {
ctor public ImsCallForwardInfo(int, int, int, int, @NonNull String, int);
method public int describeContents();
@@ -11468,6 +11529,7 @@ package android.telephony.ims {
method public boolean getCallExtraBoolean(String, boolean);
method public int getCallExtraInt(String);
method public int getCallExtraInt(String, int);
+ method @Nullable public <T extends android.os.Parcelable> T getCallExtraParcelable(@Nullable String);
method public android.os.Bundle getCallExtras();
method public int getCallType();
method public static int getCallTypeFromVideoState(int);
@@ -11490,6 +11552,7 @@ package android.telephony.ims {
method public void setCallExtra(String, String);
method public void setCallExtraBoolean(String, boolean);
method public void setCallExtraInt(String, int);
+ method public void setCallExtraParcelable(@NonNull String, @NonNull android.os.Parcelable);
method public void setCallRestrictCause(int);
method public void setCallerNumberVerificationStatus(int);
method public void setEmergencyCallRouting(int);
@@ -11524,6 +11587,7 @@ package android.telephony.ims {
field public static final String EXTRA_CALL_DISCONNECT_CAUSE = "android.telephony.ims.extra.CALL_DISCONNECT_CAUSE";
field public static final String EXTRA_CALL_NETWORK_TYPE = "android.telephony.ims.extra.CALL_NETWORK_TYPE";
field @Deprecated public static final String EXTRA_CALL_RAT_TYPE = "CallRadioTech";
+ field public static final String EXTRA_CALL_SUBJECT = "android.telephony.ims.extra.CALL_SUBJECT";
field public static final String EXTRA_CHILD_NUMBER = "ChildNum";
field public static final String EXTRA_CNA = "cna";
field public static final String EXTRA_CNAP = "cnap";
@@ -11533,8 +11597,11 @@ package android.telephony.ims {
field public static final String EXTRA_EMERGENCY_CALL = "e_call";
field public static final String EXTRA_FORWARDED_NUMBER = "android.telephony.ims.extra.FORWARDED_NUMBER";
field public static final String EXTRA_IS_CALL_PULL = "CallPull";
+ field public static final String EXTRA_LOCATION = "android.telephony.ims.extra.LOCATION";
field public static final String EXTRA_OI = "oi";
field public static final String EXTRA_OIR = "oir";
+ field public static final String EXTRA_PICTURE_URL = "android.telephony.ims.extra.PICTURE_URL";
+ field public static final String EXTRA_PRIORITY = "android.telephony.ims.extra.PRIORITY";
field public static final String EXTRA_REMOTE_URI = "remote_uri";
field public static final String EXTRA_USSD = "ussd";
field public static final int OIR_DEFAULT = 0; // 0x0
@@ -11542,6 +11609,8 @@ package android.telephony.ims {
field public static final int OIR_PRESENTATION_PAYPHONE = 4; // 0x4
field public static final int OIR_PRESENTATION_RESTRICTED = 1; // 0x1
field public static final int OIR_PRESENTATION_UNKNOWN = 3; // 0x3
+ field public static final int PRIORITY_NORMAL = 0; // 0x0
+ field public static final int PRIORITY_URGENT = 1; // 0x1
field public static final int SERVICE_TYPE_EMERGENCY = 2; // 0x2
field public static final int SERVICE_TYPE_NONE = 0; // 0x0
field public static final int SERVICE_TYPE_NORMAL = 1; // 0x1
@@ -11952,8 +12021,107 @@ package android.telephony.ims {
field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ims.RtpHeaderExtensionType> CREATOR;
}
+ public interface SipDelegateConnection {
+ method public void notifyMessageReceiveError(@NonNull String, int);
+ method public void notifyMessageReceived(@NonNull String);
+ method public void sendMessage(@NonNull android.telephony.ims.SipMessage, long);
+ }
+
+ public final class SipDelegateImsConfiguration implements android.os.Parcelable {
+ method public boolean containsKey(@NonNull String);
+ method @NonNull public android.os.PersistableBundle copyBundle();
+ method public int describeContents();
+ method public boolean getBoolean(@NonNull String, boolean);
+ method public int getInt(@NonNull String, int);
+ method @Nullable public String getString(@NonNull String);
+ method public long getVersion();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ims.SipDelegateImsConfiguration> CREATOR;
+ field public static final String IPTYPE_IPV4 = "IPV4";
+ field public static final String IPTYPE_IPV6 = "IPV6";
+ field public static final String KEY_SIP_CONFIG_AUTHENTICATION_HEADER_STRING = "sip_config_auhentication_header_string";
+ field public static final String KEY_SIP_CONFIG_AUTHENTICATION_NONCE_STRING = "sip_config_authentication_nonce_string";
+ field public static final String KEY_SIP_CONFIG_HOME_DOMAIN_STRING = "sip_config_home_domain_string";
+ field public static final String KEY_SIP_CONFIG_IMEI_STRING = "sip_config_imei_string";
+ field public static final String KEY_SIP_CONFIG_IPTYPE_STRING = "sip_config_iptype_string";
+ field public static final String KEY_SIP_CONFIG_IS_COMPACT_FORM_ENABLED_BOOL = "sip_config_is_compact_form_enabled_bool";
+ field public static final String KEY_SIP_CONFIG_IS_GRUU_ENABLED_BOOL = "sip_config_is_gruu_enabled_bool";
+ field public static final String KEY_SIP_CONFIG_IS_IPSEC_ENABLED_BOOL = "sip_config_is_ipsec_enabled_bool";
+ field public static final String KEY_SIP_CONFIG_IS_KEEPALIVE_ENABLED_BOOL = "sip_config_is_keepalive_enabled_bool";
+ field public static final String KEY_SIP_CONFIG_IS_NAT_ENABLED_BOOL = "sip_config_is_nat_enabled_bool";
+ field public static final String KEY_SIP_CONFIG_MAX_PAYLOAD_SIZE_ON_UDP_INT = "sip_config_udp_max_payload_size_int";
+ field public static final String KEY_SIP_CONFIG_PATH_HEADER_STRING = "sip_config_path_header_string";
+ field public static final String KEY_SIP_CONFIG_P_ACCESS_NETWORK_INFO_HEADER_STRING = "sip_config_p_access_network_info_header_string";
+ field public static final String KEY_SIP_CONFIG_P_ASSOCIATED_URI_HEADER_STRING = "sip_config_p_associated_uri_header_string";
+ field public static final String KEY_SIP_CONFIG_P_LAST_ACCESS_NETWORK_INFO_HEADER_STRING = "sip_config_p_last_access_network_info_header_string";
+ field public static final String KEY_SIP_CONFIG_SECURITY_VERIFY_HEADER_STRING = "sip_config_security_verify_header_string";
+ field public static final String KEY_SIP_CONFIG_SERVER_DEFAULT_IPADDRESS_STRING = "sip_config_server_default_ipaddress_string";
+ field public static final String KEY_SIP_CONFIG_SERVER_DEFAULT_PORT_INT = "sip_config_server_default_port_int";
+ field public static final String KEY_SIP_CONFIG_SERVER_IPSEC_CLIENT_PORT_INT = "sip_config_server_ipsec_client_port_int";
+ field public static final String KEY_SIP_CONFIG_SERVER_IPSEC_OLD_CLIENT_PORT_INT = "sip_config_server_ipsec_old_client_port_int";
+ field public static final String KEY_SIP_CONFIG_SERVER_IPSEC_SERVER_PORT_INT = "sip_config_server_ipsec_server_port_int";
+ field public static final String KEY_SIP_CONFIG_SERVICE_ROUTE_HEADER_STRING = "sip_config_service_route_header_string";
+ field public static final String KEY_SIP_CONFIG_TRANSPORT_TYPE_STRING = "sip_config_protocol_type_string";
+ field public static final String KEY_SIP_CONFIG_UE_DEFAULT_IPADDRESS_STRING = "sip_config_ue_default_ipaddress_string";
+ field public static final String KEY_SIP_CONFIG_UE_DEFAULT_PORT_INT = "sip_config_ue_default_port_int";
+ field public static final String KEY_SIP_CONFIG_UE_IPSEC_CLIENT_PORT_INT = "sip_config_ue_ipsec_client_port_int";
+ field public static final String KEY_SIP_CONFIG_UE_IPSEC_OLD_CLIENT_PORT_INT = "sip_config_ue_ipsec_old_client_port_int";
+ field public static final String KEY_SIP_CONFIG_UE_IPSEC_SERVER_PORT_INT = "sip_config_ue_ipsec_server_port_int";
+ field public static final String KEY_SIP_CONFIG_UE_PRIVATE_USER_ID_STRING = "sip_config_ue_private_user_id_string";
+ field public static final String KEY_SIP_CONFIG_UE_PUBLIC_GRUU_STRING = "sip_config_ue_public_gruu_string";
+ field public static final String KEY_SIP_CONFIG_UE_PUBLIC_IPADDRESS_WITH_NAT_STRING = "sip_config_ue_public_ipaddress_with_nat_string";
+ field public static final String KEY_SIP_CONFIG_UE_PUBLIC_PORT_WITH_NAT_INT = "sip_config_ue_public_port_with_nat_int";
+ field public static final String KEY_SIP_CONFIG_UE_PUBLIC_USER_ID_STRING = "sip_config_ue_public_user_id_string";
+ field public static final String KEY_SIP_CONFIG_URI_USER_PART_STRING = "sip_config_uri_user_part_string";
+ field public static final String SIP_TRANSPORT_TCP = "TCP";
+ field public static final String SIP_TRANSPORT_UDP = "UDP";
+ }
+
+ public static final class SipDelegateImsConfiguration.Builder {
+ ctor public SipDelegateImsConfiguration.Builder(int);
+ ctor public SipDelegateImsConfiguration.Builder(@NonNull android.telephony.ims.SipDelegateImsConfiguration);
+ method @NonNull public android.telephony.ims.SipDelegateImsConfiguration.Builder addBoolean(@NonNull String, boolean);
+ method @NonNull public android.telephony.ims.SipDelegateImsConfiguration.Builder addInt(@NonNull String, int);
+ method @NonNull public android.telephony.ims.SipDelegateImsConfiguration.Builder addString(@NonNull String, @NonNull String);
+ method @NonNull public android.telephony.ims.SipDelegateImsConfiguration build();
+ }
+
public class SipDelegateManager {
+ method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void createSipDelegate(@NonNull android.telephony.ims.DelegateRequest, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.stub.DelegateConnectionStateCallback, @NonNull android.telephony.ims.stub.DelegateConnectionMessageCallback) throws android.telephony.ims.ImsException;
+ method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void destroySipDelegate(@NonNull android.telephony.ims.SipDelegateConnection, int);
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isSupported() throws android.telephony.ims.ImsException;
+ field public static final int DENIED_REASON_INVALID = 4; // 0x4
+ field public static final int DENIED_REASON_IN_USE_BY_ANOTHER_DELEGATE = 1; // 0x1
+ field public static final int DENIED_REASON_NOT_ALLOWED = 2; // 0x2
+ field public static final int DENIED_REASON_SINGLE_REGISTRATION_NOT_ALLOWED = 3; // 0x3
+ field public static final int DENIED_REASON_UNKNOWN = 0; // 0x0
+ field public static final int MESSAGE_FAILURE_REASON_DELEGATE_CLOSED = 2; // 0x2
+ field public static final int MESSAGE_FAILURE_REASON_DELEGATE_DEAD = 1; // 0x1
+ field public static final int MESSAGE_FAILURE_REASON_INTERNAL_DELEGATE_STATE_TRANSITION = 11; // 0xb
+ field public static final int MESSAGE_FAILURE_REASON_INVALID_BODY_CONTENT = 5; // 0x5
+ field public static final int MESSAGE_FAILURE_REASON_INVALID_FEATURE_TAG = 6; // 0x6
+ field public static final int MESSAGE_FAILURE_REASON_INVALID_HEADER_FIELDS = 4; // 0x4
+ field public static final int MESSAGE_FAILURE_REASON_INVALID_START_LINE = 3; // 0x3
+ field public static final int MESSAGE_FAILURE_REASON_NETWORK_NOT_AVAILABLE = 8; // 0x8
+ field public static final int MESSAGE_FAILURE_REASON_NOT_REGISTERED = 9; // 0x9
+ field public static final int MESSAGE_FAILURE_REASON_STALE_IMS_CONFIGURATION = 10; // 0xa
+ field public static final int MESSAGE_FAILURE_REASON_TAG_NOT_ENABLED_FOR_DELEGATE = 7; // 0x7
+ field public static final int MESSAGE_FAILURE_REASON_UNKNOWN = 0; // 0x0
+ field public static final int SIP_DELEGATE_DESTROY_REASON_REQUESTED_BY_APP = 2; // 0x2
+ field public static final int SIP_DELEGATE_DESTROY_REASON_SERVICE_DEAD = 1; // 0x1
+ field public static final int SIP_DELEGATE_DESTROY_REASON_SUBSCRIPTION_TORN_DOWN = 4; // 0x4
+ field public static final int SIP_DELEGATE_DESTROY_REASON_UNKNOWN = 0; // 0x0
+ field public static final int SIP_DELEGATE_DESTROY_REASON_USER_DISABLED_RCS = 3; // 0x3
+ }
+
+ public final class SipMessage implements android.os.Parcelable {
+ ctor public SipMessage(@NonNull String, @NonNull String, @NonNull byte[]);
+ method public int describeContents();
+ method @NonNull public byte[] getContent();
+ method @NonNull public String getHeaderSection();
+ method @NonNull public String getStartLine();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ims.SipMessage> CREATOR;
}
}
@@ -12047,6 +12215,19 @@ package android.telephony.ims.feature {
package android.telephony.ims.stub {
+ public interface DelegateConnectionMessageCallback {
+ method public void onMessageReceived(@NonNull android.telephony.ims.SipMessage);
+ method public void onMessageSendFailure(@NonNull String, int);
+ method public void onMessageSent(@NonNull String);
+ }
+
+ public interface DelegateConnectionStateCallback {
+ method public void onCreated(@NonNull android.telephony.ims.SipDelegateConnection);
+ method public void onDestroyed(int);
+ method public void onFeatureTagStatusChanged(@NonNull android.telephony.ims.DelegateRegistrationState, @NonNull java.util.Set<android.telephony.ims.FeatureTagState>);
+ method public void onImsConfigurationChanged(@NonNull android.telephony.ims.SipDelegateImsConfiguration);
+ }
+
public class ImsCallSessionImplBase implements java.lang.AutoCloseable {
ctor public ImsCallSessionImplBase();
method public void accept(int, android.telephony.ims.ImsStreamMediaProfile);
@@ -12207,8 +12388,17 @@ package android.telephony.ims.stub {
method public int updateColr(int);
}
+ public interface SipDelegate {
+ method public void closeDialog(@NonNull String);
+ method public void notifyMessageReceiveError(@NonNull String, int);
+ method public void notifyMessageReceived(@NonNull String);
+ method public void sendMessage(@NonNull android.telephony.ims.SipMessage, long);
+ }
+
public class SipTransportImplBase {
ctor public SipTransportImplBase(@NonNull java.util.concurrent.Executor);
+ method public void createSipDelegate(int, @NonNull android.telephony.ims.DelegateRequest, @NonNull android.telephony.ims.DelegateStateCallback, @NonNull android.telephony.ims.DelegateMessageCallback);
+ method public void destroySipDelegate(@NonNull android.telephony.ims.stub.SipDelegate, int);
}
}
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 5434bcca0575..e392ed7b6e2d 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -7,6 +7,7 @@ package android {
field public static final String APPROVE_INCIDENT_REPORTS = "android.permission.APPROVE_INCIDENT_REPORTS";
field public static final String BIND_CELL_BROADCAST_SERVICE = "android.permission.BIND_CELL_BROADCAST_SERVICE";
field public static final String BRIGHTNESS_SLIDER_USAGE = "android.permission.BRIGHTNESS_SLIDER_USAGE";
+ field public static final String BROADCAST_CLOSE_SYSTEM_DIALOGS = "android.permission.BROADCAST_CLOSE_SYSTEM_DIALOGS";
field public static final String CHANGE_APP_IDLE_STATE = "android.permission.CHANGE_APP_IDLE_STATE";
field public static final String CLEAR_APP_USER_DATA = "android.permission.CLEAR_APP_USER_DATA";
field public static final String CONFIGURE_DISPLAY_BRIGHTNESS = "android.permission.CONFIGURE_DISPLAY_BRIGHTNESS";
@@ -1499,7 +1500,6 @@ package android.provider {
field public static final String HIDDEN_API_BLACKLIST_EXEMPTIONS = "hidden_api_blacklist_exemptions";
field public static final String HIDDEN_API_POLICY = "hidden_api_policy";
field public static final String HIDE_ERROR_DIALOGS = "hide_error_dialogs";
- field public static final String LOCATION_GLOBAL_KILL_SWITCH = "location_global_kill_switch";
field public static final String LOCATION_IGNORE_SETTINGS_PACKAGE_WHITELIST = "location_ignore_settings_package_whitelist";
field public static final String LOW_POWER_MODE = "low_power";
field public static final String LOW_POWER_MODE_STICKY = "low_power_sticky";
diff --git a/core/java/android/annotation/RequiresFeature.java b/core/java/android/annotation/RequiresFeature.java
index fc93f03d76cf..08861d42be39 100644
--- a/core/java/android/annotation/RequiresFeature.java
+++ b/core/java/android/annotation/RequiresFeature.java
@@ -30,7 +30,6 @@ import java.lang.annotation.Target;
* Denotes that the annotated element requires one or more device features. This
* is used to auto-generate documentation.
*
- * @see PackageManager#hasSystemFeature(String)
* @hide
*/
@Retention(SOURCE)
@@ -38,8 +37,16 @@ import java.lang.annotation.Target;
public @interface RequiresFeature {
/**
* The name of the device feature that is required.
- *
- * @see PackageManager#hasSystemFeature(String)
*/
String value();
+
+ /**
+ * Defines the name of the method that should be called to check whether the feature is
+ * available, using the same signature format as javadoc. The feature checking method can have
+ * multiple parameters, but the feature name parameter must be of type String and must also be
+ * the first String-type parameter.
+ * <p>
+ * By default, the enforcement is {@link PackageManager#hasSystemFeature(String)}.
+ */
+ String enforcement() default("android.content.pm.PackageManager#hasSystemFeature");
}
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index fc95718cf0e4..5ee5597e1984 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -2590,7 +2590,7 @@ public class Activity extends ContextThemeWrapper
protected void onStop() {
if (DEBUG_LIFECYCLE) Slog.v(TAG, "onStop " + this);
if (mActionBar != null) mActionBar.setShowHideAnimationEnabled(false);
- mActivityTransitionState.onStop();
+ mActivityTransitionState.onStop(this);
dispatchActivityStopped();
mTranslucentCallback = null;
mCalled = true;
@@ -5189,8 +5189,8 @@ public class Activity extends ContextThemeWrapper
* result callbacks including {@link #onRequestPermissionsResult(int, String[], int[])}.
* </p>
* <p>
- * The <a href="https://github.com/googlesamples/android-RuntimePermissions">
- * RuntimePermissions</a> sample app demonstrates how to use this method to
+ * The <a href="https://github.com/android/permissions-samples">
+ * RuntimePermissions</a> sample apps demonstrate how to use this method to
* request permissions at run time.
* </p>
*
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 5537edb8b957..e3048dff1bda 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -1854,16 +1854,12 @@ public class ActivityManager {
* the recent tasks.
*/
@Deprecated
- public List<RecentTaskInfo> getRecentTasks(int maxNum, int flags)
- throws SecurityException {
- try {
- if (maxNum < 0) {
- throw new IllegalArgumentException("The requested number of tasks should be >= 0");
- }
- return getTaskService().getRecentTasks(maxNum, flags, mContext.getUserId()).getList();
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
+ public List<RecentTaskInfo> getRecentTasks(int maxNum, int flags) throws SecurityException {
+ if (maxNum < 0) {
+ throw new IllegalArgumentException("The requested number of tasks should be >= 0");
}
+ return ActivityTaskManager.getInstance().getRecentTasks(
+ maxNum, flags, mContext.getUserId());
}
/**
@@ -2084,11 +2080,7 @@ public class ActivityManager {
@Deprecated
public List<RunningTaskInfo> getRunningTasks(int maxNum)
throws SecurityException {
- try {
- return getTaskService().getTasks(maxNum);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+ return ActivityTaskManager.getInstance().getTasks(maxNum);
}
/**
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index ef146b118c33..0b0781e917e3 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -27,6 +27,8 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.TestApi;
+import android.app.ExitTransitionCoordinator.ActivityExitTransitionCallbacks;
+import android.app.ExitTransitionCoordinator.ExitTransitionCallbacks;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.ComponentName;
import android.content.Context;
@@ -44,8 +46,6 @@ import android.os.Parcelable;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.UserHandle;
-import android.transition.Transition;
-import android.transition.TransitionListenerAdapter;
import android.transition.TransitionManager;
import android.util.Pair;
import android.util.Slog;
@@ -806,8 +806,11 @@ public class ActivityOptions {
public static ActivityOptions makeSceneTransitionAnimation(Activity activity,
Pair<View, String>... sharedElements) {
ActivityOptions opts = new ActivityOptions();
- makeSceneTransitionAnimation(activity, activity.getWindow(), opts,
- activity.mExitTransitionListener, sharedElements);
+ ExitTransitionCoordinator exit = makeSceneTransitionAnimation(
+ new ActivityExitTransitionCallbacks(activity), activity.mExitTransitionListener,
+ activity.getWindow(), opts, sharedElements);
+ opts.mExitCoordinatorIndex =
+ activity.mActivityTransitionState.addExitTransitionCoordinator(exit);
return opts;
}
@@ -823,25 +826,19 @@ public class ActivityOptions {
* @hide
*/
@SafeVarargs
- public static ActivityOptions startSharedElementAnimation(Window window,
+ public static Pair<ActivityOptions, ExitTransitionCoordinator> startSharedElementAnimation(
+ Window window, ExitTransitionCallbacks exitCallbacks, SharedElementCallback callback,
Pair<View, String>... sharedElements) {
ActivityOptions opts = new ActivityOptions();
- final View decorView = window.getDecorView();
- if (decorView == null) {
- return opts;
- }
- final ExitTransitionCoordinator exit =
- makeSceneTransitionAnimation(null, window, opts, null, sharedElements);
- if (exit != null) {
- HideWindowListener listener = new HideWindowListener(window, exit);
- exit.setHideSharedElementsCallback(listener);
- exit.startExit();
- }
- return opts;
+ ExitTransitionCoordinator exit = makeSceneTransitionAnimation(
+ exitCallbacks, callback, window, opts, sharedElements);
+ opts.mExitCoordinatorIndex = -1;
+ return Pair.create(opts, exit);
}
/**
- * This method should be called when the {@link #startSharedElementAnimation(Window, Pair[])}
+ * This method should be called when the
+ * {@link #startSharedElementAnimation(Window, ExitTransitionCallbacks, Pair[])}
* animation must be stopped and the Views reset. This can happen if there was an error
* from startActivity or a springboard activity and the animation should stop and reset.
*
@@ -864,9 +861,9 @@ public class ActivityOptions {
}
}
- static ExitTransitionCoordinator makeSceneTransitionAnimation(Activity activity, Window window,
- ActivityOptions opts, SharedElementCallback callback,
- Pair<View, String>[] sharedElements) {
+ static ExitTransitionCoordinator makeSceneTransitionAnimation(
+ ExitTransitionCallbacks exitCallbacks, SharedElementCallback callback, Window window,
+ ActivityOptions opts, Pair<View, String>[] sharedElements) {
if (!window.hasFeature(Window.FEATURE_ACTIVITY_TRANSITIONS)) {
opts.mAnimationType = ANIM_DEFAULT;
return null;
@@ -892,17 +889,11 @@ public class ActivityOptions {
}
}
- ExitTransitionCoordinator exit = new ExitTransitionCoordinator(activity, window,
+ ExitTransitionCoordinator exit = new ExitTransitionCoordinator(exitCallbacks, window,
callback, names, names, views, false);
opts.mTransitionReceiver = exit;
opts.mSharedElementNames = names;
- opts.mIsReturning = (activity == null);
- if (activity == null) {
- opts.mExitCoordinatorIndex = -1;
- } else {
- opts.mExitCoordinatorIndex =
- activity.mActivityTransitionState.addExitTransitionCoordinator(exit);
- }
+ opts.mIsReturning = false;
return exit;
}
@@ -928,8 +919,12 @@ public class ActivityOptions {
opts.mIsReturning = true;
opts.mResultCode = resultCode;
opts.mResultData = resultData;
- opts.mExitCoordinatorIndex =
- activity.mActivityTransitionState.addExitTransitionCoordinator(exitCoordinator);
+ if (activity == null) {
+ opts.mExitCoordinatorIndex = -1;
+ } else {
+ opts.mExitCoordinatorIndex =
+ activity.mActivityTransitionState.addExitTransitionCoordinator(exitCoordinator);
+ }
return opts;
}
@@ -1868,67 +1863,6 @@ public class ActivityOptions {
+ mStartY + ", mWidth=" + mWidth + ", mHeight=" + mHeight;
}
- private static class HideWindowListener extends TransitionListenerAdapter
- implements ExitTransitionCoordinator.HideSharedElementsCallback {
- private final Window mWindow;
- private final ExitTransitionCoordinator mExit;
- private final boolean mWaitingForTransition;
- private boolean mTransitionEnded;
- private boolean mSharedElementHidden;
- private ArrayList<View> mSharedElements;
-
- public HideWindowListener(Window window, ExitTransitionCoordinator exit) {
- mWindow = window;
- mExit = exit;
- mSharedElements = new ArrayList<>(exit.mSharedElements);
- Transition transition = mWindow.getExitTransition();
- if (transition != null) {
- transition.addListener(this);
- mWaitingForTransition = true;
- } else {
- mWaitingForTransition = false;
- }
- View decorView = mWindow.getDecorView();
- if (decorView != null) {
- if (decorView.getTag(com.android.internal.R.id.cross_task_transition) != null) {
- throw new IllegalStateException(
- "Cannot start a transition while one is running");
- }
- decorView.setTagInternal(com.android.internal.R.id.cross_task_transition, exit);
- }
- }
-
- @Override
- public void onTransitionEnd(Transition transition) {
- mTransitionEnded = true;
- hideWhenDone();
- transition.removeListener(this);
- }
-
- @Override
- public void hideSharedElements() {
- mSharedElementHidden = true;
- hideWhenDone();
- }
-
- private void hideWhenDone() {
- if (mSharedElementHidden && (!mWaitingForTransition || mTransitionEnded)) {
- mExit.resetViews();
- int numSharedElements = mSharedElements.size();
- for (int i = 0; i < numSharedElements; i++) {
- View view = mSharedElements.get(i);
- view.requestLayout();
- }
- View decorView = mWindow.getDecorView();
- if (decorView != null) {
- decorView.setTagInternal(
- com.android.internal.R.id.cross_task_transition, null);
- decorView.setVisibility(View.GONE);
- }
- }
- }
- }
-
/**
* The information about the source of activity launch. E.g. describe an activity is launched
* from launcher by receiving a motion event with a timestamp.
diff --git a/core/java/android/app/ActivityTaskManager.java b/core/java/android/app/ActivityTaskManager.java
index c7b90897c8e7..03c1a011f198 100644
--- a/core/java/android/app/ActivityTaskManager.java
+++ b/core/java/android/app/ActivityTaskManager.java
@@ -27,7 +27,6 @@ import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Rect;
import android.os.Build;
-import android.os.Handler;
import android.os.IBinder;
import android.os.Parcel;
import android.os.Parcelable;
@@ -35,6 +34,7 @@ import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.DisplayMetrics;
import android.util.Singleton;
+import android.view.RemoteAnimationDefinition;
import java.util.List;
@@ -147,7 +147,20 @@ public class ActivityTaskManager {
private static int sMaxRecentTasks = -1;
- ActivityTaskManager(Context context, Handler handler) {
+ private static final Singleton<ActivityTaskManager> sInstance =
+ new Singleton<ActivityTaskManager>() {
+ @Override
+ protected ActivityTaskManager create() {
+ return new ActivityTaskManager();
+ }
+ };
+
+ private ActivityTaskManager() {
+ }
+
+ /** @hide */
+ public static ActivityTaskManager getInstance() {
+ return sInstance.get();
}
/** @hide */
@@ -444,6 +457,98 @@ public class ActivityTaskManager {
}
/**
+ * @return List of running tasks.
+ * @hide
+ */
+ public List<ActivityManager.RunningTaskInfo> getTasks(int maxNum) {
+ return getTasks(maxNum, false /* filterForVisibleRecents */);
+ }
+
+ /**
+ * @return List of running tasks that can be filtered by visibility in recents.
+ * @hide
+ */
+ public List<ActivityManager.RunningTaskInfo> getTasks(
+ int maxNum, boolean filterOnlyVisibleRecents) {
+ try {
+ return getService().getTasks(maxNum, filterOnlyVisibleRecents);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * @return List of recent tasks.
+ * @hide
+ */
+ public List<ActivityManager.RecentTaskInfo> getRecentTasks(
+ int maxNum, int flags, int userId) {
+ try {
+ return getService().getRecentTasks(maxNum, flags, userId).getList();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /** @hide */
+ public void registerTaskStackListener(TaskStackListener listener) {
+ try {
+ getService().registerTaskStackListener(listener);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /** @hide */
+ public void unregisterTaskStackListener(TaskStackListener listener) {
+ try {
+ getService().unregisterTaskStackListener(listener);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /** @hide */
+ public Rect getTaskBounds(int taskId) {
+ try {
+ return getService().getTaskBounds(taskId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Registers remote animations for a display.
+ * @hide
+ */
+ public void registerRemoteAnimationsForDisplay(
+ int displayId, RemoteAnimationDefinition definition) {
+ try {
+ getService().registerRemoteAnimationsForDisplay(displayId, definition);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /** @hide */
+ public boolean isInLockTaskMode() {
+ try {
+ return getService().isInLockTaskMode();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /** @hide */
+ public boolean removeTask(int taskId) {
+ try {
+ return getService().removeTask(taskId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Information you can retrieve about a root task in the system.
* @hide
*/
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 2211807a422b..d9c0c71d44ae 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -85,6 +85,7 @@ import android.database.sqlite.SQLiteDebug.DbStats;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.HardwareRenderer;
+import android.graphics.Typeface;
import android.hardware.display.DisplayManagerGlobal;
import android.inputmethodservice.InputMethodService;
import android.media.MediaFrameworkInitializer;
@@ -117,6 +118,7 @@ import android.os.Process;
import android.os.RemoteCallback;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.SharedMemory;
import android.os.StatsFrameworkInitializer;
import android.os.StatsServiceManager;
import android.os.StrictMode;
@@ -844,6 +846,8 @@ public final class ActivityThread extends ClientTransactionHandler {
long[] disabledCompatChanges;
+ SharedMemory mSerializedSystemFontMap;
+
@Override
public String toString() {
return "AppBindData{appInfo=" + appInfo + "}";
@@ -1054,7 +1058,8 @@ public final class ActivityThread extends ClientTransactionHandler {
boolean isRestrictedBackupMode, boolean persistent, Configuration config,
CompatibilityInfo compatInfo, Map services, Bundle coreSettings,
String buildSerial, AutofillOptions autofillOptions,
- ContentCaptureOptions contentCaptureOptions, long[] disabledCompatChanges) {
+ ContentCaptureOptions contentCaptureOptions, long[] disabledCompatChanges,
+ SharedMemory serializedSystemFontMap) {
if (services != null) {
if (false) {
// Test code to make sure the app could see the passed-in services.
@@ -1103,6 +1108,7 @@ public final class ActivityThread extends ClientTransactionHandler {
data.autofillOptions = autofillOptions;
data.contentCaptureOptions = contentCaptureOptions;
data.disabledCompatChanges = disabledCompatChanges;
+ data.mSerializedSystemFontMap = serializedSystemFontMap;
sendMessage(H.BIND_APPLICATION, data);
}
@@ -6411,6 +6417,13 @@ public final class ActivityThread extends ClientTransactionHandler {
*/
LocaleList.setDefault(data.config.getLocales());
+ try {
+ Typeface.setSystemFontMap(data.mSerializedSystemFontMap);
+ } catch (IOException | ErrnoException e) {
+ Slog.e(TAG, "Failed to parse serialized system font map");
+ Typeface.loadPreinstalledSystemFontMap();
+ }
+
synchronized (mResourcesManager) {
/*
* Update the system configuration since its preloaded and might not
diff --git a/core/java/android/app/ActivityTransitionState.java b/core/java/android/app/ActivityTransitionState.java
index 5c4125e01dfd..62619509184a 100644
--- a/core/java/android/app/ActivityTransitionState.java
+++ b/core/java/android/app/ActivityTransitionState.java
@@ -247,14 +247,14 @@ class ActivityTransitionState {
mEnterActivityOptions = null;
}
- public void onStop() {
+ public void onStop(Activity activity) {
restoreExitedViews();
if (mEnterTransitionCoordinator != null) {
mEnterTransitionCoordinator.stop();
mEnterTransitionCoordinator = null;
}
if (mReturnExitCoordinator != null) {
- mReturnExitCoordinator.stop();
+ mReturnExitCoordinator.stop(activity);
mReturnExitCoordinator = null;
}
}
@@ -331,7 +331,8 @@ class ActivityTransitionState {
}
}
- mReturnExitCoordinator = new ExitTransitionCoordinator(activity,
+ mReturnExitCoordinator = new ExitTransitionCoordinator(
+ new ExitTransitionCoordinator.ActivityExitTransitionCallbacks(activity),
activity.getWindow(), activity.mEnterTransitionListener, pendingExitNames,
null, null, true);
if (enterViewsTransition != null && decor != null) {
@@ -341,12 +342,11 @@ class ActivityTransitionState {
final ViewGroup finalDecor = decor;
OneShotPreDrawListener.add(decor, () -> {
if (mReturnExitCoordinator != null) {
- mReturnExitCoordinator.startExit(activity.mResultCode,
- activity.mResultData);
+ mReturnExitCoordinator.startExit(activity);
}
});
} else {
- mReturnExitCoordinator.startExit(activity.mResultCode, activity.mResultData);
+ mReturnExitCoordinator.startExit(activity);
}
}
return true;
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index cdfe41e85917..4dd6a7efe7c5 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -358,7 +358,7 @@ public class AppOpsManager {
/** @hide */
@Retention(RetentionPolicy.SOURCE)
- @IntDef(flag = true, prefix = { "MODE_" }, value = {
+ @IntDef(prefix = { "MODE_" }, value = {
MODE_ALLOWED,
MODE_IGNORED,
MODE_ERRORED,
diff --git a/core/java/android/app/ExitTransitionCoordinator.java b/core/java/android/app/ExitTransitionCoordinator.java
index 68824cd26eaa..9fdff5979cd0 100644
--- a/core/java/android/app/ExitTransitionCoordinator.java
+++ b/core/java/android/app/ExitTransitionCoordinator.java
@@ -18,6 +18,7 @@ package android.app;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
+import android.annotation.NonNull;
import android.app.SharedElementCallback.OnSharedElementsReadyListener;
import android.content.Intent;
import android.graphics.Color;
@@ -45,15 +46,17 @@ import java.util.ArrayList;
* This ActivityTransitionCoordinator is created in ActivityOptions#makeSceneTransitionAnimation
* to govern the exit of the Scene and the shared elements when calling an Activity as well as
* the reentry of the Scene when coming back from the called Activity.
+ *
+ * @hide
*/
-class ExitTransitionCoordinator extends ActivityTransitionCoordinator {
+public class ExitTransitionCoordinator extends ActivityTransitionCoordinator {
private static final String TAG = "ExitTransitionCoordinator";
static long sMaxWaitMillis = 1000;
private Bundle mSharedElementBundle;
private boolean mExitNotified;
private boolean mSharedElementNotified;
- private Activity mActivity;
+ private ExitTransitionCallbacks mExitCallbacks;
private boolean mIsBackgroundReady;
private boolean mIsCanceled;
private Handler mHandler;
@@ -62,20 +65,15 @@ class ExitTransitionCoordinator extends ActivityTransitionCoordinator {
private Bundle mExitSharedElementBundle;
private boolean mIsExitStarted;
private boolean mSharedElementsHidden;
- private HideSharedElementsCallback mHideSharedElementsCallback;
- public ExitTransitionCoordinator(Activity activity, Window window,
- SharedElementCallback listener, ArrayList<String> names,
+ public ExitTransitionCoordinator(ExitTransitionCallbacks exitCallbacks,
+ Window window, SharedElementCallback listener, ArrayList<String> names,
ArrayList<String> accepted, ArrayList<View> mapped, boolean isReturning) {
super(window, names, listener, isReturning);
viewsReady(mapSharedElements(accepted, mapped));
stripOffscreenViews();
mIsBackgroundReady = !isReturning;
- mActivity = activity;
- }
-
- void setHideSharedElementsCallback(HideSharedElementsCallback callback) {
- mHideSharedElementsCallback = callback;
+ mExitCallbacks = exitCallbacks;
}
@Override
@@ -190,8 +188,8 @@ class ExitTransitionCoordinator extends ActivityTransitionCoordinator {
private void hideSharedElements() {
moveSharedElementsFromOverlay();
- if (mHideSharedElementsCallback != null) {
- mHideSharedElementsCallback.hideSharedElements();
+ if (mExitCallbacks != null) {
+ mExitCallbacks.hideSharedElements();
}
if (!mIsHidden) {
hideViews(mSharedElements);
@@ -210,20 +208,16 @@ class ExitTransitionCoordinator extends ActivityTransitionCoordinator {
decorView.suppressLayout(true);
}
moveSharedElementsToOverlay();
- startTransition(new Runnable() {
- @Override
- public void run() {
- if (mActivity != null) {
- beginTransitions();
- } else {
- startExitTransition();
- }
- }
- });
+ startTransition(this::beginTransitions);
}
}
- public void startExit(int resultCode, Intent data) {
+ /**
+ * Starts the exit animation and sends back the activity result
+ */
+ public void startExit(Activity activity) {
+ int resultCode = activity.mResultCode;
+ Intent data = activity.mResultData;
if (!mIsExitStarted) {
mIsExitStarted = true;
pauseInput();
@@ -247,9 +241,9 @@ class ExitTransitionCoordinator extends ActivityTransitionCoordinator {
.getApplicationInfo().targetSdkVersion >= VERSION_CODES.M;
ArrayList<String> sharedElementNames = targetsM ? mSharedElementNames :
mAllSharedElementNames;
- ActivityOptions options = ActivityOptions.makeSceneTransitionAnimation(mActivity, this,
+ ActivityOptions options = ActivityOptions.makeSceneTransitionAnimation(activity, this,
sharedElementNames, resultCode, data);
- mActivity.convertToTranslucent(new Activity.TranslucentConversionListener() {
+ activity.convertToTranslucent(new Activity.TranslucentConversionListener() {
@Override
public void onTranslucentConversionComplete(boolean drawComplete) {
if (!mIsCanceled) {
@@ -257,21 +251,19 @@ class ExitTransitionCoordinator extends ActivityTransitionCoordinator {
}
}
}, options);
- startTransition(new Runnable() {
- @Override
- public void run() {
- startExitTransition();
- }
- });
+ startTransition(this::startExitTransition);
}
}
- public void stop() {
- if (mIsReturning && mActivity != null) {
+ /**
+ * Called from {@link Activity#onStop()}
+ */
+ public void stop(Activity activity) {
+ if (mIsReturning && mExitCallbacks != null) {
// Override the previous ActivityOptions. We don't want the
// activity to have options since we're essentially canceling the
// transition and finishing right now.
- mActivity.convertToTranslucent(null, null);
+ activity.convertToTranslucent(null, null);
finish();
}
}
@@ -434,7 +426,7 @@ class ExitTransitionCoordinator extends ActivityTransitionCoordinator {
mSharedElementNotified = true;
delayCancel();
- if (!mActivity.isTopOfTask()) {
+ if (mExitCallbacks.isReturnTransitionAllowed()) {
mResultReceiver.send(MSG_ALLOW_RETURN_TRANSITION, null);
}
@@ -474,22 +466,20 @@ class ExitTransitionCoordinator extends ActivityTransitionCoordinator {
}
private void finishIfNecessary() {
- if (mIsReturning && mExitNotified && mActivity != null && (mSharedElements.isEmpty() ||
- mSharedElementsHidden)) {
+ if (mIsReturning && mExitNotified && mExitCallbacks != null && (mSharedElements.isEmpty()
+ || mSharedElementsHidden)) {
finish();
}
if (!mIsReturning && mExitNotified) {
- mActivity = null; // don't need it anymore
+ mExitCallbacks = null; // don't need it anymore
}
}
private void finish() {
stopCancel();
- if (mActivity != null) {
- mActivity.mActivityTransitionState.clear();
- mActivity.finish();
- mActivity.overridePendingTransition(0, 0);
- mActivity = null;
+ if (mExitCallbacks != null) {
+ mExitCallbacks.onFinish();
+ mExitCallbacks = null;
}
// Clear the state so that we can't hold any references accidentally and leak memory.
clearState();
@@ -529,7 +519,49 @@ class ExitTransitionCoordinator extends ActivityTransitionCoordinator {
}
}
- interface HideSharedElementsCallback {
- void hideSharedElements();
+ /**
+ * @hide
+ */
+ public interface ExitTransitionCallbacks {
+
+ /**
+ * Returns true if reverse exit animation is supported
+ */
+ boolean isReturnTransitionAllowed();
+
+ /**
+ * Called then the transition finishes
+ */
+ void onFinish();
+
+ /**
+ * Optional callback when the transition is hiding elements in the source surface
+ */
+ default void hideSharedElements() { };
+ }
+
+ /**
+ * @hide
+ */
+ public static class ActivityExitTransitionCallbacks implements ExitTransitionCallbacks {
+
+ @NonNull
+ final Activity mActivity;
+
+ ActivityExitTransitionCallbacks(@NonNull Activity activity) {
+ mActivity = activity;
+ }
+
+ @Override
+ public boolean isReturnTransitionAllowed() {
+ return !mActivity.isTopOfTask();
+ }
+
+ @Override
+ public void onFinish() {
+ mActivity.mActivityTransitionState.clear();
+ mActivity.finish();
+ mActivity.overridePendingTransition(0, 0);
+ }
}
}
diff --git a/core/java/android/app/IActivityTaskManager.aidl b/core/java/android/app/IActivityTaskManager.aidl
index bd5913efdecb..ab48baea48e8 100644
--- a/core/java/android/app/IActivityTaskManager.aidl
+++ b/core/java/android/app/IActivityTaskManager.aidl
@@ -83,6 +83,15 @@ import java.util.List;
*
* {@hide}
*/
+// TODO(b/174040395): Make this interface private to ActivityTaskManager.java and have external
+// caller go through that call instead. This would help us better separate and control the API
+// surface exposed.
+// TODO(b/174041144): Move callback methods from Activity (Things that take param 'IBinder token')
+// to a separate interface that is only available to the Activity.
+// TODO(b/174041603): Create a builder interface for things like startActivityXXX(...) to reduce
+// interface duplication.
+// TODO(b/174040691): Clean-up/remove all obsolete or unused interfaces like things that should be
+// going through task organizer now.
interface IActivityTaskManager {
int startActivity(in IApplicationThread caller, in String callingPackage,
in String callingFeatureId, in Intent intent, in String resolvedType,
@@ -154,9 +163,7 @@ interface IActivityTaskManager {
void setFocusedTask(int taskId);
boolean removeTask(int taskId);
void removeAllVisibleRecentTasks();
- List<ActivityManager.RunningTaskInfo> getTasks(int maxNum);
- List<ActivityManager.RunningTaskInfo> getFilteredTasks(int maxNum,
- boolean filterOnlyVisibleRecents);
+ List<ActivityManager.RunningTaskInfo> getTasks(int maxNum, boolean filterOnlyVisibleRecents);
boolean shouldUpRecreateTask(in IBinder token, in String destAffinity);
boolean navigateUpTo(in IBinder token, in Intent target, int resultCode,
in Intent resultData);
diff --git a/core/java/android/app/IApplicationThread.aidl b/core/java/android/app/IApplicationThread.aidl
index 22ca42eb9cf4..890e957bdff4 100644
--- a/core/java/android/app/IApplicationThread.aidl
+++ b/core/java/android/app/IApplicationThread.aidl
@@ -43,6 +43,7 @@ import android.os.IInterface;
import android.os.ParcelFileDescriptor;
import android.os.PersistableBundle;
import android.os.RemoteCallback;
+import android.os.SharedMemory;
import com.android.internal.app.IVoiceInteractor;
import com.android.internal.content.ReferrerIntent;
@@ -75,7 +76,8 @@ oneway interface IApplicationThread {
boolean restrictedBackupMode, boolean persistent, in Configuration config,
in CompatibilityInfo compatInfo, in Map services,
in Bundle coreSettings, in String buildSerial, in AutofillOptions autofillOptions,
- in ContentCaptureOptions contentCaptureOptions, in long[] disabledCompatChanges);
+ in ContentCaptureOptions contentCaptureOptions, in long[] disabledCompatChanges,
+ in SharedMemory serializedSystemFontMap);
void runIsolatedEntryPoint(in String entryPoint, in String[] entryPointArgs);
void scheduleExit();
void scheduleServiceArgs(IBinder token, in ParceledListSlice args);
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index a886beddf64c..a1135809fd4c 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -30,6 +30,7 @@ import android.annotation.IdRes;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.Px;
import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
@@ -4873,6 +4874,7 @@ public class Notification implements Parcelable
// Small icon doesn't need to be reset, as it's always set. Resetting would prevent
// re-using the drawable when the notification is updated.
contentView.setBoolean(R.id.expand_button, "setExpanded", false);
+ contentView.setViewVisibility(R.id.app_name_text, View.GONE);
contentView.setTextViewText(R.id.app_name_text, null);
contentView.setViewVisibility(R.id.chronometer, View.GONE);
contentView.setViewVisibility(R.id.header_text, View.GONE);
@@ -5105,33 +5107,29 @@ public class Notification implements Parcelable
if (result == null) {
result = new TemplateBindResult();
}
- boolean largeIconShown = bindLargeIcon(contentView, p);
+ final boolean largeIconShown = bindLargeIcon(contentView, p);
calculateLargeIconMarginEnd(largeIconShown, result);
if (p.mHeaderless) {
// views in the headerless (collapsed) state
- contentView.setViewLayoutMarginEnd(R.id.notification_standard_view_column,
- result.getHeadingExtraMarginEnd());
+ result.mHeadingExtraMarginSet.applyToView(contentView,
+ R.id.notification_headerless_view_column);
} else {
// views in states with a header (big states)
- contentView.setInt(R.id.notification_header, "setTopLineExtraMarginEnd",
- result.getHeadingExtraMarginEnd());
- contentView.setViewLayoutMarginEnd(R.id.line1, result.getTitleMarginEnd());
+ result.mHeadingExtraMarginSet.applyToView(contentView, R.id.notification_header);
+ result.mTitleMarginSet.applyToView(contentView, R.id.line1);
}
}
private void calculateLargeIconMarginEnd(boolean largeIconShown,
@NonNull TemplateBindResult result) {
- int contentMargin = mContext.getResources().getDimensionPixelSize(
+ final Resources resources = mContext.getResources();
+ final int contentMargin = resources.getDimensionPixelOffset(
R.dimen.notification_content_margin_end);
- int expanderSize = mContext.getResources().getDimensionPixelSize(
+ final int expanderSize = resources.getDimensionPixelSize(
R.dimen.notification_header_expand_icon_size) - contentMargin;
- int extraMarginEnd = 0;
- if (largeIconShown) {
- int iconSize = mContext.getResources().getDimensionPixelSize(
- R.dimen.notification_right_icon_size);
- extraMarginEnd = iconSize + contentMargin;
- }
- result.setRightIconState(largeIconShown, extraMarginEnd, expanderSize);
+ final int extraMarginEndIfVisible = resources.getDimensionPixelSize(
+ R.dimen.notification_right_icon_size) + contentMargin;
+ result.setRightIconState(largeIconShown, extraMarginEndIfVisible, expanderSize);
}
/**
@@ -5153,9 +5151,14 @@ public class Notification implements Parcelable
private void bindNotificationHeader(RemoteViews contentView, StandardTemplateParams p) {
bindSmallIcon(contentView, p);
- boolean hasTextToLeft = bindHeaderAppName(contentView, p);
+ // Populate text left-to-right so that separators are only shown between strings
+ boolean hasTextToLeft = bindHeaderAppName(contentView, p, false /* force */);
hasTextToLeft |= bindHeaderTextSecondary(contentView, p, hasTextToLeft);
hasTextToLeft |= bindHeaderText(contentView, p, hasTextToLeft);
+ if (!hasTextToLeft) {
+ // If there's still no text, force add the app name so there is some text.
+ hasTextToLeft |= bindHeaderAppName(contentView, p, true /* force */);
+ }
bindHeaderChronometerAndTime(contentView, p, hasTextToLeft);
bindProfileBadge(contentView, p);
bindAlertedIcon(contentView, p);
@@ -5219,7 +5222,7 @@ public class Notification implements Parcelable
&& mN.extras.getCharSequence(EXTRA_INFO_TEXT) != null) {
summaryText = mN.extras.getCharSequence(EXTRA_INFO_TEXT);
}
- if (summaryText != null) {
+ if (!TextUtils.isEmpty(summaryText)) {
// TODO: Remove the span entirely to only have the string with propper formating.
contentView.setTextViewText(R.id.header_text, processTextSpans(
processLegacyText(summaryText)));
@@ -5291,13 +5294,13 @@ public class Notification implements Parcelable
/**
* @return true if the app name will be visible
*/
- private boolean bindHeaderAppName(RemoteViews contentView, StandardTemplateParams p) {
- if (p.mViewType == StandardTemplateParams.VIEW_TYPE_MINIMIZED) {
- contentView.setViewVisibility(R.id.app_name_text, View.GONE);
+ private boolean bindHeaderAppName(RemoteViews contentView, StandardTemplateParams p,
+ boolean force) {
+ if (p.mViewType == StandardTemplateParams.VIEW_TYPE_MINIMIZED && !force) {
+ // unless the force flag is set, don't show the app name in the minimized state.
return false;
}
if (p.mHeaderless && p.hasTitle()) {
- contentView.setViewVisibility(R.id.app_name_text, View.GONE);
// the headerless template will have the TITLE in this position; return true to
// keep the divider visible between that title and the next text element.
return true;
@@ -5929,8 +5932,7 @@ public class Notification implements Parcelable
}
int color;
- int background = mContext.getColor(
- com.android.internal.R.color.notification_material_background_color);
+ int background = obtainBackgroundColor();
if (rawColor == COLOR_DEFAULT) {
ensureColors(p);
color = ContrastColorUtil.resolveDefaultColor(mContext, background, mInNightMode);
@@ -5963,8 +5965,7 @@ public class Notification implements Parcelable
if (mNeutralColor != COLOR_INVALID) {
return mNeutralColor;
}
- int background = mContext.getColor(
- com.android.internal.R.color.notification_material_background_color);
+ int background = obtainBackgroundColor();
mNeutralColor = ContrastColorUtil.resolveDefaultColor(mContext, background,
mInNightMode);
if (Color.alpha(mNeutralColor) < 255) {
@@ -6115,6 +6116,21 @@ public class Notification implements Parcelable
return mN;
}
+ private @ColorInt int obtainBackgroundColor() {
+ int defaultColor = mInNightMode ? Color.BLACK : Color.WHITE;
+ Resources.Theme theme = mContext.getTheme();
+ if (theme == null) {
+ return defaultColor;
+ }
+ TypedArray ta = theme.obtainStyledAttributes(new int[]{R.attr.colorBackground});
+ if (ta == null) {
+ return defaultColor;
+ }
+ int background = ta.getColor(0, defaultColor);
+ ta.recycle();
+ return background;
+ }
+
/**
* Apply this Builder to an existing {@link Notification} object.
*
@@ -6248,8 +6264,7 @@ public class Notification implements Parcelable
private int resolveBackgroundColor(StandardTemplateParams p) {
int backgroundColor = getBackgroundColor(p);
if (backgroundColor == COLOR_DEFAULT) {
- backgroundColor = mContext.getColor(
- com.android.internal.R.color.notification_material_background_color);
+ backgroundColor = obtainBackgroundColor();
}
return backgroundColor;
}
@@ -7759,8 +7774,10 @@ public class Notification implements Parcelable
addExtras(mBuilder.mN.extras);
if (!isConversationLayout) {
// also update the end margin if there is an image
+ // NOTE: This template doesn't support moving this icon to the left, so we don't
+ // need to fully apply the MarginSet
contentView.setViewLayoutMarginEnd(R.id.notification_messaging,
- bindResult.getHeadingExtraMarginEnd());
+ bindResult.mHeadingExtraMarginSet.getValue());
}
contentView.setInt(R.id.status_bar_latest_event_content, "setLayoutColor",
mBuilder.isColorized(p)
@@ -8757,9 +8774,8 @@ public class Notification implements Parcelable
if (!headerless) {
// also update the end margin to account for the large icon or expander
Resources resources = mBuilder.mContext.getResources();
- int endMargin = resources.getDimensionPixelSize(
- R.dimen.notification_content_margin_end) + result.getTitleMarginEnd();
- remoteViews.setViewLayoutMarginEnd(R.id.notification_main_column, endMargin);
+ result.mTitleMarginSet.applyToView(remoteViews, R.id.notification_main_column,
+ resources.getDimensionPixelOffset(R.dimen.notification_content_margin_end));
}
}
@@ -10997,42 +11013,74 @@ public class Notification implements Parcelable
*/
private static class TemplateBindResult {
boolean mRightIconVisible;
- int mRightIconMarginEnd;
- int mExpanderSize;
/**
- * @return the margin end that needs to be added to the heading so that it won't overlap
+ * The margin end that needs to be added to the heading so that it won't overlap
* with the large icon. This value includes the space required to accommodate the large
* icon, but should be added to the space needed to accommodate the expander. This does
* not include the 16dp content margin that all notification views must have.
*/
- public int getHeadingExtraMarginEnd() {
- return mRightIconMarginEnd;
- }
+ public final MarginSet mHeadingExtraMarginSet = new MarginSet();
/**
- * @return the margin end that needs to be added to the heading so that it won't overlap
+ * The margin end that needs to be added to the heading so that it won't overlap
* with the large icon. This value includes the space required to accommodate the large
* icon as well as the expander. This does not include the 16dp content margin that all
* notification views must have.
*/
- public int getHeadingFullMarginEnd() {
- return mRightIconMarginEnd + mExpanderSize;
- }
+ public final MarginSet mHeadingFullMarginSet = new MarginSet();
/**
- * @return the margin end that needs to be added to the title text of the big state
+ * The margin end that needs to be added to the title text of the big state
* so that it won't overlap with the large icon, but assuming the text can run under
* the expander when that icon is not visible.
*/
- public int getTitleMarginEnd() {
- return mRightIconVisible ? getHeadingFullMarginEnd() : 0;
- }
+ public final MarginSet mTitleMarginSet = new MarginSet();
- public void setRightIconState(boolean visible, int marginEnd, int expanderSize) {
+ public void setRightIconState(boolean visible, int marginEndIfVisible, int expanderSize) {
mRightIconVisible = visible;
- mRightIconMarginEnd = marginEnd;
- mExpanderSize = expanderSize;
+ mHeadingExtraMarginSet.setValues(0, marginEndIfVisible);
+ mHeadingFullMarginSet.setValues(expanderSize, marginEndIfVisible + expanderSize);
+ mTitleMarginSet.setValues(0, marginEndIfVisible + expanderSize);
+ }
+
+ /**
+ * This contains the end margins for a view when the right icon is visible or not. These
+ * values are both needed so that NotificationGroupingUtil can 'move' the right_icon to the
+ * left_icon and adjust the margins, and to undo that change as well.
+ */
+ private class MarginSet {
+ private int mValueIfGone;
+ private int mValueIfVisible;
+
+ public void setValues(int valueIfGone, int valueIfVisible) {
+ mValueIfGone = valueIfGone;
+ mValueIfVisible = valueIfVisible;
+ }
+
+ public void applyToView(@NonNull RemoteViews views, @IdRes int viewId) {
+ applyToView(views, viewId, 0);
+ }
+
+ public void applyToView(@NonNull RemoteViews views, @IdRes int viewId,
+ @Px int extraMargin) {
+ final int marginEnd = getValue() + extraMargin;
+ if (viewId == R.id.notification_header) {
+ views.setInt(R.id.notification_header, "setTopLineExtraMarginEnd", marginEnd);
+ } else {
+ views.setViewLayoutMarginEnd(viewId, marginEnd);
+ }
+ if (mRightIconVisible) {
+ views.setIntTag(viewId, R.id.tag_margin_end_when_icon_visible,
+ mValueIfVisible + extraMargin);
+ views.setIntTag(viewId, R.id.tag_margin_end_when_icon_gone,
+ mValueIfGone + extraMargin);
+ }
+ }
+
+ public int getValue() {
+ return mRightIconVisible ? mValueIfVisible : mValueIfGone;
+ }
}
}
@@ -11074,7 +11122,9 @@ public class Notification implements Parcelable
}
final boolean hasTitle() {
- return title != null && title.length() != 0 && !mHasCustomContent;
+ // We hide the title when the notification is a decorated custom view so that decorated
+ // custom views always have to include their own title.
+ return !TextUtils.isEmpty(title) && !mHasCustomContent;
}
final StandardTemplateParams viewType(int viewType) {
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 73777909d417..7287acdd0241 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -284,8 +284,7 @@ public final class SystemServiceRegistry {
new CachedServiceFetcher<ActivityTaskManager>() {
@Override
public ActivityTaskManager createService(ContextImpl ctx) {
- return new ActivityTaskManager(
- ctx.getOuterContext(), ctx.mMainThread.getHandler());
+ return ActivityTaskManager.getInstance();
}});
registerService(Context.URI_GRANTS_SERVICE, UriGrantsManager.class,
diff --git a/core/java/android/app/TEST_MAPPING b/core/java/android/app/TEST_MAPPING
index d2be8a4a6597..36241a8ebe08 100644
--- a/core/java/android/app/TEST_MAPPING
+++ b/core/java/android/app/TEST_MAPPING
@@ -92,6 +92,54 @@
}
],
"file_patterns": ["(/|^)Activity.java"]
+ },
+ {
+ "name": "CtsContentTestCases",
+ "options": [
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ },
+ {
+ "exclude-annotation": "org.junit.Ignore"
+ },
+ {
+ "include-filter": "android.content.wm.cts"
+ }
+ ],
+ "file_patterns": ["(/|^)ContextImpl.java"]
+ },
+ {
+ "name": "CtsOsTestCases",
+ "options": [
+ {
+ "include-annotation": "android.platform.test.annotations.Presubmit"
+ },
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ },
+ {
+ "exclude-annotation": "org.junit.Ignore"
+ },
+ {
+ "include-filter": "android.os.cts.StrictModeTest"
+ }
+ ],
+ "file_patterns": ["(/|^)ContextImpl.java"]
+ },
+ {
+ "name": "FrameworksCoreTests",
+ "options": [
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ },
+ {
+ "exclude-annotation": "org.junit.Ignore"
+ },
+ {
+ "include-filter": "android.content.ContextTest"
+ }
+ ],
+ "file_patterns": ["(/|^)ContextImpl.java"]
}
],
"postsubmit": [
diff --git a/core/java/android/app/TaskInfo.java b/core/java/android/app/TaskInfo.java
index ca67dba45dd0..1a8a4b7f16da 100644
--- a/core/java/android/app/TaskInfo.java
+++ b/core/java/android/app/TaskInfo.java
@@ -214,7 +214,6 @@ public class TaskInfo {
*/
public int parentTaskId;
-
/**
* Parent bounds.
* @hide
@@ -227,6 +226,12 @@ public class TaskInfo {
*/
public boolean isFocused;
+ /**
+ * Whether this task is visible.
+ * @hide
+ */
+ public boolean isVisible;
+
TaskInfo() {
// Do nothing
}
@@ -311,7 +316,8 @@ public class TaskInfo {
&& pictureInPictureParams == that.pictureInPictureParams
&& getWindowingMode() == that.getWindowingMode()
&& Objects.equals(taskDescription, that.taskDescription)
- && isFocused == that.isFocused;
+ && isFocused == that.isFocused
+ && isVisible == that.isVisible;
}
private boolean equalsLetterboxParams(TaskInfo that) {
@@ -358,6 +364,7 @@ public class TaskInfo {
parentTaskId = source.readInt();
parentBounds = source.readTypedObject(Rect.CREATOR);
isFocused = source.readBoolean();
+ isVisible = source.readBoolean();
}
/**
@@ -394,6 +401,7 @@ public class TaskInfo {
dest.writeInt(parentTaskId);
dest.writeTypedObject(parentBounds, flags);
dest.writeBoolean(isFocused);
+ dest.writeBoolean(isVisible);
}
@Override
@@ -413,12 +421,13 @@ public class TaskInfo {
+ " topActivityType=" + topActivityType
+ " pictureInPictureParams=" + pictureInPictureParams
+ " topActivityInfo=" + topActivityInfo
- + " launchCookies" + launchCookies
+ + " launchCookies=" + launchCookies
+ " letterboxActivityBounds=" + letterboxActivityBounds
+ " positionInParent=" + positionInParent
+ " parentTaskId=" + parentTaskId
+ " parentBounds=" + parentBounds
+ " isFocused=" + isFocused
+ + " isVisible=" + isVisible
+ "}";
}
}
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 42427fa825eb..5eb1922a163c 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -87,6 +87,7 @@ import android.service.restrictions.RestrictionsReceiver;
import android.telephony.TelephonyManager;
import android.telephony.data.ApnSetting;
import android.util.ArraySet;
+import android.util.DebugUtils;
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
@@ -2453,19 +2454,45 @@ public class DevicePolicyManager {
@Retention(RetentionPolicy.SOURCE)
public @interface PersonalAppsSuspensionReason {}
+ // TODO(b/172376923) - make all (or none) @TestApi
+
/** @hide */
@TestApi
public static final int OPERATION_LOCK_NOW = 1;
+ /** @hide */
+ public static final int OPERATION_SWITCH_USER = 2;
+ /** @hide */
+ public static final int OPERATION_START_USER_IN_BACKGROUND = 3;
+ /** @hide */
+ public static final int OPERATION_STOP_USER = 4;
+ /** @hide */
+ public static final int OPERATION_CREATE_AND_MANAGE_USER = 5;
+ /** @hide */
+ public static final int OPERATION_REMOVE_USER = 6;
+
+ private static final String PREFIX_OPERATION = "OPERATION_";
+
+
// TODO(b/172376923) - add all operations
/** @hide */
- @IntDef(prefix = "OPERATION_", value = {
+ @IntDef(prefix = PREFIX_OPERATION, value = {
OPERATION_LOCK_NOW,
+ OPERATION_SWITCH_USER,
+ OPERATION_START_USER_IN_BACKGROUND,
+ OPERATION_STOP_USER,
+ OPERATION_CREATE_AND_MANAGE_USER,
+ OPERATION_REMOVE_USER
})
@Retention(RetentionPolicy.SOURCE)
public static @interface DevicePolicyOperation {
}
+ /** @hide */
+ public static String operationToString(@DevicePolicyOperation int operation) {
+ return DebugUtils.constantToString(DevicePolicyManager.class, PREFIX_OPERATION, operation);
+ }
+
/**
* Return true if the given administrator component is currently active (enabled) in the system.
*
@@ -3721,6 +3748,27 @@ public class DevicePolicyManager {
}
/**
+ * Returns the password complexity that applies to this user, aggregated from other users if
+ * necessary (for example, if the DPC has set password complexity requirements on the parent
+ * profile DPM instance of a managed profile user, they would apply to the primary user on the
+ * device).
+ * @hide
+ */
+ @PasswordComplexity
+ public int getAggregatedPasswordComplexityForUser(int userId) {
+ if (mService == null) {
+ return PASSWORD_COMPLEXITY_NONE;
+ }
+
+ try {
+ return mService.getAggregatedPasswordComplexityForUser(userId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+
+ /**
* When called by a profile owner of a managed profile returns true if the profile uses unified
* challenge with its parent user.
*
@@ -5192,9 +5240,22 @@ public class DevicePolicyManager {
}
/**
- * Called by a device or profile owner, or delegated certificate installer, to install a
- * certificate and corresponding private key. All apps within the profile will be able to access
- * the certificate and use the private key, given direct user approval.
+ * This API can be called by the following to install a certificate and corresponding
+ * private key:
+ * <ul>
+ * <li>Device owner</li>
+ * <li>Profile owner</li>
+ * <li>Delegated certificate installer</li>
+ * <li>Credential management app</li>
+ * </ul>
+ * All apps within the profile will be able to access the certificate and use the private key,
+ * given direct user approval.
+ *
+ * <p>From Android {@link android.os.Build.VERSION_CODES#S}, the credential management app
+ * can call this API. However, this API sets the key pair as user selectable by default,
+ * which is not permitted when called by the credential management app. Instead,
+ * {@link #installKeyPair(ComponentName, PrivateKey, Certificate[], String, int)} should be
+ * called with {@link #INSTALLKEY_SET_USER_SELECTABLE} not set as a flag.
*
* <p>Access to the installed credentials will not be granted to the caller of this API without
* direct user approval. This is for security - should a certificate installer become
@@ -5225,10 +5286,23 @@ public class DevicePolicyManager {
}
/**
- * Called by a device or profile owner, or delegated certificate installer, to install a
- * certificate chain and corresponding private key for the leaf certificate. All apps within the
- * profile will be able to access the certificate chain and use the private key, given direct
- * user approval.
+ * This API can be called by the following to install a certificate chain and corresponding
+ * private key for the leaf certificate:
+ * <ul>
+ * <li>Device owner</li>
+ * <li>Profile owner</li>
+ * <li>Delegated certificate installer</li>
+ * <li>Credential management app</li>
+ * </ul>
+ * All apps within the profile will be able to access the certificate chain and use the private
+ * key, given direct user approval.
+ *
+ * <p>From Android {@link android.os.Build.VERSION_CODES#S}, the credential management app
+ * can call this API. However, this API sets the key pair as user selectable by default,
+ * which is not permitted when called by the credential management app. Instead,
+ * {@link #installKeyPair(ComponentName, PrivateKey, Certificate[], String, int)} should be
+ * called with {@link #INSTALLKEY_SET_USER_SELECTABLE} not set as a flag.
+ * Note, there can only be a credential management app on an unmanaged device.
*
* <p>The caller of this API may grant itself access to the certificate and private key
* immediately, without user approval. It is a best practice not to request this unless strictly
@@ -5266,10 +5340,26 @@ public class DevicePolicyManager {
}
/**
- * Called by a device or profile owner, or delegated certificate installer, to install a
- * certificate chain and corresponding private key for the leaf certificate. All apps within the
- * profile will be able to access the certificate chain and use the private key, given direct
- * user approval (if the user is allowed to select the private key).
+ * This API can be called by the following to install a certificate chain and corresponding
+ * private key for the leaf certificate:
+ * <ul>
+ * <li>Device owner</li>
+ * <li>Profile owner</li>
+ * <li>Delegated certificate installer</li>
+ * <li>Credential management app</li>
+ * </ul>
+ * All apps within the profile will be able to access the certificate chain and use the
+ * private key, given direct user approval (if the user is allowed to select the private key).
+ *
+ * <p>From Android {@link android.os.Build.VERSION_CODES#S}, the credential management app
+ * can call this API. If called by the credential management app:
+ * <ul>
+ * <li>The componentName must be {@code null}r</li>
+ * <li>The alias must exist in the credential management app's
+ * {@link android.security.AppUriAuthenticationPolicy}</li>
+ * <li>The key pair must not be user selectable</li>
+ * </ul>
+ * Note, there can only be a credential management app on an unmanaged device.
*
* <p>The caller of this API may grant itself access to the certificate and private key
* immediately, without user approval. It is a best practice not to request this unless strictly
@@ -5295,7 +5385,8 @@ public class DevicePolicyManager {
* {@link #INSTALLKEY_REQUEST_CREDENTIALS_ACCESS}.
* @return {@code true} if the keys were installed, {@code false} otherwise.
* @throws SecurityException if {@code admin} is not {@code null} and not a device or profile
- * owner.
+ * owner, or {@code admin} is null but the calling application is not a delegated
+ * certificate installer or credential management app.
* @see android.security.KeyChain#getCertificateChain
* @see #setDelegatedScopes
* @see #DELEGATION_CERT_INSTALL
@@ -5328,15 +5419,26 @@ public class DevicePolicyManager {
}
/**
- * Called by a device or profile owner, or delegated certificate installer, to remove a
- * certificate and private key pair installed under a given alias.
+ * This API can be called by the following to remove a certificate and private key pair
+ * installed under a given alias:
+ * <ul>
+ * <li>Device owner</li>
+ * <li>Profile owner</li>
+ * <li>Delegated certificate installer</li>
+ * <li>Credential management app</li>
+ * </ul>
+ *
+ * <p>From Android {@link android.os.Build.VERSION_CODES#S}, the credential management app
+ * can call this API. If called by the credential management app, the componentName must be
+ * {@code null}. Note, there can only be a credential management app on an unmanaged device.
*
* @param admin Which {@link DeviceAdminReceiver} this request is associated with, or
* {@code null} if calling from a delegated certificate installer.
* @param alias The private key alias under which the certificate is installed.
* @return {@code true} if the private key alias no longer exists, {@code false} otherwise.
* @throws SecurityException if {@code admin} is not {@code null} and not a device or profile
- * owner.
+ * owner, or {@code admin} is null but the calling application is not a delegated
+ * certificate installer or credential management app.
* @see #setDelegatedScopes
* @see #DELEGATION_CERT_INSTALL
*/
@@ -5349,11 +5451,42 @@ public class DevicePolicyManager {
}
}
+ // STOPSHIP(b/174298501): clarify the expected return value following generateKeyPair call.
+ /**
+ * Called by a device or profile owner, or delegated certificate installer, to query whether a
+ * certificate and private key are installed under a given alias.
+ *
+ * @param alias The alias under which the key pair is installed.
+ * @return {@code true} if a key pair with this alias exists, {@code false} otherwise.
+ * @throws SecurityException if the caller is not a device or profile owner or a delegated
+ * certificate installer.
+ * @see #setDelegatedScopes
+ * @see #DELEGATION_CERT_INSTALL
+ */
+ public boolean hasKeyPair(@NonNull String alias) {
+ throwIfParentInstance("hasKeyPair");
+ try {
+ return mService.hasKeyPair(mContext.getPackageName(), alias);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
/**
- * Called by a device or profile owner, or delegated certificate installer, to generate a
- * new private/public key pair. If the device supports key generation via secure hardware,
- * this method is useful for creating a key in KeyChain that never left the secure hardware.
- * Access to the key is controlled the same way as in {@link #installKeyPair}.
+ * This API can be called by the following to generate a new private/public key pair:
+ * <ul>
+ * <li>Device owner</li>
+ * <li>Profile owner</li>
+ * <li>Delegated certificate installer</li>
+ * <li>Credential management app</li>
+ * </ul>
+ * If the device supports key generation via secure hardware, this method is useful for
+ * creating a key in KeyChain that never left the secure hardware. Access to the key is
+ * controlled the same way as in {@link #installKeyPair}.
+ *
+ * <p>From Android {@link android.os.Build.VERSION_CODES#S}, the credential management app
+ * can call this API. If called by the credential management app, the componentName must be
+ * {@code null}. Note, there can only be a credential management app on an unmanaged device.
*
* <p>Because this method might take several seconds to complete, it should only be called from
* a worker thread. This method returns {@code null} when called from the main thread.
@@ -5376,9 +5509,10 @@ public class DevicePolicyManager {
* supports these features, refer to {@link #isDeviceIdAttestationSupported()} and
* {@link #isUniqueDeviceAttestationSupported()}.
*
- * <p>Device owner, profile owner and their delegated certificate installer can use
- * {@link #ID_TYPE_BASE_INFO} to request inclusion of the general device information
- * including manufacturer, model, brand, device and product in the attestation record.
+ * <p>Device owner, profile owner, their delegated certificate installer and the credential
+ * management app can use {@link #ID_TYPE_BASE_INFO} to request inclusion of the general device
+ * information including manufacturer, model, brand, device and product in the attestation
+ * record.
* Only device owner, profile owner on an organization-owned device and their delegated
* certificate installers can use {@link #ID_TYPE_SERIAL}, {@link #ID_TYPE_IMEI} and
* {@link #ID_TYPE_MEID} to request unique device identifiers to be attested (the serial number,
@@ -5413,9 +5547,11 @@ public class DevicePolicyManager {
* {@code keySpec}.
* @return A non-null {@code AttestedKeyPair} if the key generation succeeded, null otherwise.
* @throws SecurityException if {@code admin} is not {@code null} and not a device or profile
- * owner. If Device ID attestation is requested (using {@link #ID_TYPE_SERIAL},
- * {@link #ID_TYPE_IMEI} or {@link #ID_TYPE_MEID}), the caller must be the Device Owner
- * or the Certificate Installer delegate.
+ * owner, or {@code admin} is null but the calling application is not a delegated
+ * certificate installer or credential management app. If Device ID attestation is
+ * requested (using {@link #ID_TYPE_SERIAL}, {@link #ID_TYPE_IMEI} or
+ * {@link #ID_TYPE_MEID}), the caller must be the Device Owner or the Certificate
+ * Installer delegate.
* @throws IllegalArgumentException in the following cases:
* <p>
* <ul>
@@ -5578,10 +5714,19 @@ public class DevicePolicyManager {
}
/**
- * Called by a device or profile owner, or delegated certificate installer, to associate
- * certificates with a key pair that was generated using {@link #generateKeyPair}, and
- * set whether the key is available for the user to choose in the certificate selection
- * prompt.
+ * This API can be called by the following to associate certificates with a key pair that was
+ * generated using {@link #generateKeyPair}, and set whether the key is available for the user
+ * to choose in the certificate selection prompt:
+ * <ul>
+ * <li>Device owner</li>
+ * <li>Profile owner</li>
+ * <li>Delegated certificate installer</li>
+ * <li>Credential management app</li>
+ * </ul>
+ *
+ * <p>From Android {@link android.os.Build.VERSION_CODES#S}, the credential management app
+ * can call this API. If called by the credential management app, the componentName must be
+ * {@code null}. Note, there can only be a credential management app on an unmanaged device.
*
* @param admin Which {@link DeviceAdminReceiver} this request is associated with, or
* {@code null} if calling from a delegated certificate installer.
@@ -5599,7 +5744,7 @@ public class DevicePolicyManager {
* successfully associated with it, {@code false} otherwise.
* @throws SecurityException if {@code admin} is not {@code null} and not a device or profile
* owner, or {@code admin} is null but the calling application is not a delegated
- * certificate installer.
+ * certificate installer or credential management app.
*/
public boolean setKeyPairCertificate(@Nullable ComponentName admin,
@NonNull String alias, @NonNull List<Certificate> certs, boolean isUserSelectable) {
diff --git a/core/java/android/app/admin/DevicePolicyManagerInternal.java b/core/java/android/app/admin/DevicePolicyManagerInternal.java
index cb879fce9c10..c02fcabfcf62 100644
--- a/core/java/android/app/admin/DevicePolicyManagerInternal.java
+++ b/core/java/android/app/admin/DevicePolicyManagerInternal.java
@@ -16,6 +16,7 @@
package android.app.admin;
+import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.content.ComponentName;
import android.content.Intent;
@@ -229,5 +230,11 @@ public abstract class DevicePolicyManagerInternal {
/**
* Returns the profile owner component for the given user, or {@code null} if there is not one.
*/
+ @Nullable
public abstract ComponentName getProfileOwnerAsUser(int userHandle);
+
+ /**
+ * Returns whether the given package is a device owner or a profile owner in the calling user.
+ */
+ public abstract boolean isDeviceOrProfileOwnerInCallingUser(String packageName);
}
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 58368bc3779a..8be3cdc1296a 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -89,6 +89,7 @@ interface IDevicePolicyManager {
int getPasswordComplexity(boolean parent);
void setRequiredPasswordComplexity(int passwordComplexity, boolean parent);
int getRequiredPasswordComplexity(boolean parent);
+ int getAggregatedPasswordComplexityForUser(int userId);
boolean isUsingUnifiedPassword(in ComponentName admin);
int getCurrentFailedPasswordAttempts(int userHandle, boolean parent);
int getProfileWithMinimumFailedPasswordsForWipe(int userHandle, boolean parent);
@@ -184,6 +185,7 @@ interface IDevicePolicyManager {
in byte[] certBuffer, in byte[] certChainBuffer, String alias, boolean requestAccess,
boolean isUserSelectable);
boolean removeKeyPair(in ComponentName who, in String callerPackage, String alias);
+ boolean hasKeyPair(in String callerPackage, in String alias);
boolean generateKeyPair(in ComponentName who, in String callerPackage, in String algorithm,
in ParcelableKeyGenParameterSpec keySpec,
in int idAttestationFlags, out KeymasterCertificateChain attestationChain);
diff --git a/core/java/android/app/admin/SecurityLog.java b/core/java/android/app/admin/SecurityLog.java
index 86f91d79ad2b..1cf45670ed93 100644
--- a/core/java/android/app/admin/SecurityLog.java
+++ b/core/java/android/app/admin/SecurityLog.java
@@ -85,7 +85,8 @@ public class SecurityLog {
TAG_CRYPTO_SELF_TEST_COMPLETED,
TAG_KEY_INTEGRITY_VIOLATION,
TAG_CERT_VALIDATION_FAILURE,
- TAG_CAMERA_POLICY_SET
+ TAG_CAMERA_POLICY_SET,
+ TAG_PASSWORD_COMPLEXITY_REQUIRED
})
public @interface SecurityLogTag {}
@@ -478,6 +479,21 @@ public class SecurityLog {
SecurityLogTags.SECURITY_CAMERA_POLICY_SET;
/**
+ * Indicates that an admin has set a password complexity requirement, using the platform's
+ * pre-defined complexity levels. The log entry contains the following information about the
+ * event, encapsulated in an {@link Object} array and accessible via
+ * {@link SecurityEvent#getData()}:
+ * <li> [0] admin package name ({@code String})
+ * <li> [1] admin user ID ({@code Integer})
+ * <li> [2] target user ID ({@code Integer})
+ * <li> [3] Password complexity ({@code Integer})
+ *
+ * @see DevicePolicyManager#setRequiredPasswordComplexity(int)
+ */
+ public static final int TAG_PASSWORD_COMPLEXITY_REQUIRED =
+ SecurityLogTags.SECURITY_PASSWORD_COMPLEXITY_REQUIRED;
+
+ /**
* Event severity level indicating that the event corresponds to normal workflow.
*/
public static final int LEVEL_INFO = 1;
@@ -617,6 +633,7 @@ public class SecurityLog {
case TAG_USER_RESTRICTION_ADDED:
case TAG_USER_RESTRICTION_REMOVED:
case TAG_CAMERA_POLICY_SET:
+ case TAG_PASSWORD_COMPLEXITY_REQUIRED:
return LEVEL_INFO;
case TAG_CERT_AUTHORITY_REMOVED:
case TAG_CRYPTO_SELF_TEST_COMPLETED:
diff --git a/core/java/android/app/admin/SecurityLogTags.logtags b/core/java/android/app/admin/SecurityLogTags.logtags
index 100fd4cbd40f..db5245c919ab 100644
--- a/core/java/android/app/admin/SecurityLogTags.logtags
+++ b/core/java/android/app/admin/SecurityLogTags.logtags
@@ -1,4 +1,4 @@
-# See system/core/logcat/event.logtags for a description of the format of this file.
+# See system/logging/logcat/event.logtags for a description of the format of this file.
option java_package android.app.admin
@@ -39,3 +39,4 @@ option java_package android.app.admin
210032 security_key_integrity_violation (key_id|3),(uid|1)
210033 security_cert_validation_failure (reason|3)
210034 security_camera_policy_set (package|3),(admin_user|1),(target_user|1),(disabled|1)
+210035 security_password_complexity_required (package|3),(admin_user|1),(target_user|1),(complexity|1)
diff --git a/core/java/android/app/people/PeopleSpaceTile.java b/core/java/android/app/people/PeopleSpaceTile.java
index f5674e5cd0ce..e870597bf6d1 100644
--- a/core/java/android/app/people/PeopleSpaceTile.java
+++ b/core/java/android/app/people/PeopleSpaceTile.java
@@ -18,7 +18,12 @@ package android.app.people;
import android.annotation.NonNull;
import android.content.Intent;
+import android.content.pm.LauncherApps;
import android.content.pm.ShortcutInfo;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
import android.net.Uri;
import android.os.Parcel;
@@ -147,10 +152,10 @@ public class PeopleSpaceTile implements Parcelable {
mPackageName = intent == null ? null : intent.getPackage();
}
- public Builder(ShortcutInfo info) {
+ public Builder(ShortcutInfo info, LauncherApps launcherApps) {
mId = info.getId();
mUserName = info.getLabel();
- mUserIcon = info.getIcon();
+ mUserIcon = convertDrawableToIcon(launcherApps.getShortcutIconDrawable(info, 0));
mUid = info.getUserId();
mPackageName = info.getPackage();
}
@@ -270,4 +275,32 @@ public class PeopleSpaceTile implements Parcelable {
return new PeopleSpaceTile[size];
}
};
+
+ /** Converts {@code drawable} to a {@link Icon}. */
+ public static Icon convertDrawableToIcon(Drawable drawable) {
+ if (drawable == null) {
+ return null;
+ }
+
+ if (drawable instanceof BitmapDrawable) {
+ BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
+ if (bitmapDrawable.getBitmap() != null) {
+ return Icon.createWithBitmap(bitmapDrawable.getBitmap());
+ }
+ }
+
+ Bitmap bitmap;
+ if (drawable.getIntrinsicWidth() <= 0 || drawable.getIntrinsicHeight() <= 0) {
+ bitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
+ // Single color bitmap will be created of 1x1 pixel
+ } else {
+ bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(),
+ drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
+ }
+
+ Canvas canvas = new Canvas(bitmap);
+ drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
+ drawable.draw(canvas);
+ return Icon.createWithBitmap(bitmap);
+ }
}
diff --git a/core/java/android/bluetooth/BluetoothLeAudio.java b/core/java/android/bluetooth/BluetoothLeAudio.java
new file mode 100644
index 000000000000..3f00fa6f4181
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothLeAudio.java
@@ -0,0 +1,451 @@
+/*
+ * Copyright 2020 HIMSA II K/S - www.himsa.com.
+ * Represented by EHIMA - www.ehima.com
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.bluetooth;
+
+import android.Manifest;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
+import android.annotation.SdkConstant;
+import android.annotation.SdkConstant.SdkConstantType;
+import android.content.Context;
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.CloseGuard;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * This class provides the public APIs to control the LeAudio profile.
+ *
+ * <p>BluetoothLeAudio is a proxy object for controlling the Bluetooth LE Audio
+ * Service via IPC. Use {@link BluetoothAdapter#getProfileProxy} to get
+ * the BluetoothLeAudio proxy object.
+ *
+ * <p> Android only supports one set of connected Bluetooth LeAudio device at a time. Each
+ * method is protected with its appropriate permission.
+ */
+public final class BluetoothLeAudio implements BluetoothProfile, AutoCloseable {
+ private static final String TAG = "BluetoothLeAudio";
+ private static final boolean DBG = false;
+ private static final boolean VDBG = false;
+
+ private CloseGuard mCloseGuard;
+
+ /**
+ * Intent used to broadcast the change in connection state of the LeAudio
+ * profile. Please note that in the binaural case, there will be two different LE devices for
+ * the left and right side and each device will have their own connection state changes.
+ *
+ * <p>This intent will have 3 extras:
+ * <ul>
+ * <li> {@link #EXTRA_STATE} - The current state of the profile. </li>
+ * <li> {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile.</li>
+ * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li>
+ * </ul>
+ *
+ * <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of
+ * {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING},
+ * {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}.
+ *
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
+ * receive.
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_LE_AUDIO_CONNECTION_STATE_CHANGED =
+ "android.bluetooth.action.LE_AUDIO_CONNECTION_STATE_CHANGED";
+
+ /**
+ * Intent used to broadcast the selection of a connected device as active.
+ *
+ * <p>This intent will have one extra:
+ * <ul>
+ * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. It can
+ * be null if no device is active. </li>
+ * </ul>
+ *
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
+ * receive.
+ *
+ * @hide
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_LE_AUDIO_ACTIVE_DEVICE_CHANGED =
+ "android.bluetooth.action.LE_AUDIO_ACTIVE_DEVICE_CHANGED";
+
+ /**
+ * This represents an invalid group ID.
+ *
+ * @hide
+ */
+ public static final int GROUP_ID_INVALID = IBluetoothLeAudio.LE_AUDIO_GROUP_ID_INVALID;
+
+ private BluetoothAdapter mAdapter;
+ private final BluetoothProfileConnector<IBluetoothLeAudio> mProfileConnector =
+ new BluetoothProfileConnector(this, BluetoothProfile.LE_AUDIO, "BluetoothLeAudio",
+ IBluetoothLeAudio.class.getName()) {
+ @Override
+ public IBluetoothLeAudio getServiceInterface(IBinder service) {
+ return IBluetoothLeAudio.Stub.asInterface(Binder.allowBlocking(service));
+ }
+ };
+
+ /**
+ * Create a BluetoothLeAudio proxy object for interacting with the local
+ * Bluetooth LeAudio service.
+ */
+ /*package*/ BluetoothLeAudio(Context context, ServiceListener listener) {
+ mAdapter = BluetoothAdapter.getDefaultAdapter();
+ mProfileConnector.connect(context, listener);
+ mCloseGuard = new CloseGuard();
+ mCloseGuard.open("close");
+ }
+
+ /**
+ * @hide
+ */
+ @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ public void close() {
+ mProfileConnector.disconnect();
+ }
+
+ private IBluetoothLeAudio getService() {
+ return mProfileConnector.getService();
+ }
+
+ @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ protected void finalize() {
+ if (mCloseGuard != null) {
+ mCloseGuard.warnIfOpen();
+ }
+ close();
+ }
+
+ /**
+ * Initiate connection to a profile of the remote bluetooth device.
+ *
+ * <p> This API returns false in scenarios like the profile on the
+ * device is already connected or Bluetooth is not turned on.
+ * When this API returns true, it is guaranteed that
+ * connection state intent for the profile will be broadcasted with
+ * the state. Users can get the connection state of the profile
+ * from this intent.
+ *
+ *
+ * @param device Remote Bluetooth Device
+ * @return false on immediate error, true otherwise
+ * @hide
+ */
+ @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ public boolean connect(@Nullable BluetoothDevice device) {
+ if (DBG) log("connect(" + device + ")");
+ try {
+ final IBluetoothLeAudio service = getService();
+ if (service != null && mAdapter.isEnabled() && isValidDevice(device)) {
+ return service.connect(device);
+ }
+ if (service == null) Log.w(TAG, "Proxy not attached to service");
+ return false;
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return false;
+ }
+ }
+
+ /**
+ * Initiate disconnection from a profile
+ *
+ * <p> This API will return false in scenarios like the profile on the
+ * Bluetooth device is not in connected state etc. When this API returns,
+ * true, it is guaranteed that the connection state change
+ * intent will be broadcasted with the state. Users can get the
+ * disconnection state of the profile from this intent.
+ *
+ * <p> If the disconnection is initiated by a remote device, the state
+ * will transition from {@link #STATE_CONNECTED} to
+ * {@link #STATE_DISCONNECTED}. If the disconnect is initiated by the
+ * host (local) device the state will transition from
+ * {@link #STATE_CONNECTED} to state {@link #STATE_DISCONNECTING} to
+ * state {@link #STATE_DISCONNECTED}. The transition to
+ * {@link #STATE_DISCONNECTING} can be used to distinguish between the
+ * two scenarios.
+ *
+ *
+ * @param device Remote Bluetooth Device
+ * @return false on immediate error, true otherwise
+ * @hide
+ */
+ @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ public boolean disconnect(@Nullable BluetoothDevice device) {
+ if (DBG) log("disconnect(" + device + ")");
+ try {
+ final IBluetoothLeAudio service = getService();
+ if (service != null && mAdapter.isEnabled() && isValidDevice(device)) {
+ return service.disconnect(device);
+ }
+ if (service == null) Log.w(TAG, "Proxy not attached to service");
+ return false;
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return false;
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public @NonNull List<BluetoothDevice> getConnectedDevices() {
+ if (VDBG) log("getConnectedDevices()");
+ try {
+ final IBluetoothLeAudio service = getService();
+ if (service != null && mAdapter.isEnabled()) {
+ return service.getConnectedDevices();
+ }
+ if (service == null) Log.w(TAG, "Proxy not attached to service");
+ return new ArrayList<BluetoothDevice>();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return new ArrayList<BluetoothDevice>();
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public @NonNull List<BluetoothDevice> getDevicesMatchingConnectionStates(
+ @NonNull int[] states) {
+ if (VDBG) log("getDevicesMatchingStates()");
+ try {
+ final IBluetoothLeAudio service = getService();
+ if (service != null && mAdapter.isEnabled()) {
+ return service.getDevicesMatchingConnectionStates(states);
+ }
+ if (service == null) Log.w(TAG, "Proxy not attached to service");
+ return new ArrayList<BluetoothDevice>();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return new ArrayList<BluetoothDevice>();
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ @RequiresPermission(Manifest.permission.BLUETOOTH)
+ public @BtProfileState int getConnectionState(@NonNull BluetoothDevice device) {
+ if (VDBG) log("getState(" + device + ")");
+ try {
+ final IBluetoothLeAudio service = getService();
+ if (service != null && mAdapter.isEnabled()
+ && isValidDevice(device)) {
+ return service.getConnectionState(device);
+ }
+ if (service == null) Log.w(TAG, "Proxy not attached to service");
+ return BluetoothProfile.STATE_DISCONNECTED;
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return BluetoothProfile.STATE_DISCONNECTED;
+ }
+ }
+
+ /**
+ * Select a connected device as active.
+ *
+ * The active device selection is per profile. An active device's
+ * purpose is profile-specific. For example, LeAudio audio
+ * streaming is to the active LeAudio device. If a remote device
+ * is not connected, it cannot be selected as active.
+ *
+ * <p> This API returns false in scenarios like the profile on the
+ * device is not connected or Bluetooth is not turned on.
+ * When this API returns true, it is guaranteed that the
+ * {@link #ACTION_LEAUDIO_ACTIVE_DEVICE_CHANGED} intent will be broadcasted
+ * with the active device.
+ *
+ *
+ * @param device the remote Bluetooth device. Could be null to clear
+ * the active device and stop streaming audio to a Bluetooth device.
+ * @return false on immediate error, true otherwise
+ * @hide
+ */
+ @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ public boolean setActiveDevice(@Nullable BluetoothDevice device) {
+ if (DBG) log("setActiveDevice(" + device + ")");
+ try {
+ final IBluetoothLeAudio service = getService();
+ if (service != null && mAdapter.isEnabled()
+ && ((device == null) || isValidDevice(device))) {
+ service.setActiveDevice(device);
+ return true;
+ }
+ if (service == null) Log.w(TAG, "Proxy not attached to service");
+ return false;
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return false;
+ }
+ }
+
+ /**
+ * Get the connected LeAudio devices that are active
+ *
+ * @return the list of active devices. Returns empty list on error.
+ * @hide
+ */
+ @NonNull
+ @RequiresPermission(Manifest.permission.BLUETOOTH)
+ public List<BluetoothDevice> getActiveDevices() {
+ if (VDBG) log("getActiveDevices()");
+ try {
+ final IBluetoothLeAudio service = getService();
+ if (service != null && mAdapter.isEnabled()) {
+ return service.getActiveDevices();
+ }
+ if (service == null) Log.w(TAG, "Proxy not attached to service");
+ return new ArrayList<>();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return new ArrayList<>();
+ }
+ }
+
+ /**
+ * Get device group id. Devices with same group id belong to same group (i.e left and right
+ * earbud)
+ * @param device LE Audio capable device
+ * @return group id that this device currently belongs to
+ * @hide
+ */
+ @RequiresPermission(Manifest.permission.BLUETOOTH)
+ public int getGroupId(@NonNull BluetoothDevice device) {
+ if (VDBG) log("getGroupId()");
+ try {
+ final IBluetoothLeAudio service = getService();
+ if (service != null && mAdapter.isEnabled()) {
+ return service.getGroupId(device);
+ }
+ if (service == null) Log.w(TAG, "Proxy not attached to service");
+ return GROUP_ID_INVALID;
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return GROUP_ID_INVALID;
+ }
+ }
+
+ /**
+ * Set connection policy of the profile
+ *
+ * <p> The device should already be paired.
+ * Connection policy can be one of {@link #CONNECTION_POLICY_ALLOWED},
+ * {@link #CONNECTION_POLICY_FORBIDDEN}, {@link #CONNECTION_POLICY_UNKNOWN}
+ *
+ * @param device Paired bluetooth device
+ * @param connectionPolicy is the connection policy to set to for this profile
+ * @return true if connectionPolicy is set, false on error
+ * @hide
+ */
+ @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ public boolean setConnectionPolicy(@NonNull BluetoothDevice device,
+ @ConnectionPolicy int connectionPolicy) {
+ if (DBG) log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")");
+ try {
+ final IBluetoothLeAudio service = getService();
+ if (service != null && mAdapter.isEnabled()
+ && isValidDevice(device)) {
+ if (connectionPolicy != BluetoothProfile.CONNECTION_POLICY_FORBIDDEN
+ && connectionPolicy != BluetoothProfile.CONNECTION_POLICY_ALLOWED) {
+ return false;
+ }
+ return service.setConnectionPolicy(device, connectionPolicy);
+ }
+ if (service == null) Log.w(TAG, "Proxy not attached to service");
+ return false;
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return false;
+ }
+ }
+
+ /**
+ * Get the connection policy of the profile.
+ *
+ * <p> The connection policy can be any of:
+ * {@link #CONNECTION_POLICY_ALLOWED}, {@link #CONNECTION_POLICY_FORBIDDEN},
+ * {@link #CONNECTION_POLICY_UNKNOWN}
+ *
+ * @param device Bluetooth device
+ * @return connection policy of the device
+ * @hide
+ */
+ @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ public @ConnectionPolicy int getConnectionPolicy(@Nullable BluetoothDevice device) {
+ if (VDBG) log("getConnectionPolicy(" + device + ")");
+ try {
+ final IBluetoothLeAudio service = getService();
+ if (service != null && mAdapter.isEnabled()
+ && isValidDevice(device)) {
+ return service.getConnectionPolicy(device);
+ }
+ if (service == null) Log.w(TAG, "Proxy not attached to service");
+ return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
+ }
+ }
+
+
+ /**
+ * Helper for converting a state to a string.
+ *
+ * For debug use only - strings are not internationalized.
+ *
+ * @hide
+ */
+ public static String stateToString(int state) {
+ switch (state) {
+ case STATE_DISCONNECTED:
+ return "disconnected";
+ case STATE_CONNECTING:
+ return "connecting";
+ case STATE_CONNECTED:
+ return "connected";
+ case STATE_DISCONNECTING:
+ return "disconnecting";
+ default:
+ return "<unknown state " + state + ">";
+ }
+ }
+
+ private boolean isValidDevice(@Nullable BluetoothDevice device) {
+ if (device == null) return false;
+
+ if (BluetoothAdapter.checkBluetoothAddress(device.getAddress())) return true;
+ return false;
+ }
+
+ private static void log(String msg) {
+ Log.d(TAG, msg);
+ }
+}
diff --git a/core/java/android/bluetooth/BluetoothProfile.java b/core/java/android/bluetooth/BluetoothProfile.java
index db851c4f33b9..c31b04e81456 100644
--- a/core/java/android/bluetooth/BluetoothProfile.java
+++ b/core/java/android/bluetooth/BluetoothProfile.java
@@ -207,12 +207,19 @@ public interface BluetoothProfile {
int HEARING_AID = 21;
/**
+ * LE Audio Device
+ *
+ * @hide
+ */
+ int LE_AUDIO = 22;
+
+ /**
* Max profile ID. This value should be updated whenever a new profile is added to match
* the largest value assigned to a profile.
*
* @hide
*/
- int MAX_PROFILE_ID = 21;
+ int MAX_PROFILE_ID = 22;
/**
* Default priority for devices that we try to auto-connect to and
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index e35fb037582a..d7dc86a5c59f 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -63,7 +63,6 @@ import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.UserHandle;
-import android.os.storage.StorageManager;
import android.system.Int32Ref;
import android.text.TextUtils;
import android.util.EventLog;
@@ -110,7 +109,7 @@ public abstract class ContentResolver implements ContentInterface {
*
* @hide
*/
- public static final boolean DEPRECATE_DATA_COLUMNS = StorageManager.hasIsolatedStorage();
+ public static final boolean DEPRECATE_DATA_COLUMNS = true;
/**
* Special filesystem path prefix which indicates that a path should be
diff --git a/core/java/android/content/TEST_MAPPING b/core/java/android/content/TEST_MAPPING
new file mode 100644
index 000000000000..a2880dfdfd17
--- /dev/null
+++ b/core/java/android/content/TEST_MAPPING
@@ -0,0 +1,52 @@
+{
+ "presubmit": [
+ {
+ "name": "CtsContentTestCases",
+ "options": [
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ },
+ {
+ "exclude-annotation": "org.junit.Ignore"
+ },
+ {
+ "include-filter": "android.content.wm.cts"
+ }
+ ],
+ "file_patterns": ["(/|^)Context.java", "(/|^)ContextWrapper.java"]
+ },
+ {
+ "name": "CtsOsTestCases",
+ "options": [
+ {
+ "include-annotation": "android.platform.test.annotations.Presubmit"
+ },
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ },
+ {
+ "exclude-annotation": "org.junit.Ignore"
+ },
+ {
+ "include-filter": "android.os.cts.StrictModeTest"
+ }
+ ],
+ "file_patterns": ["(/|^)Context.java", "(/|^)ContextWrapper.java"]
+ },
+ {
+ "name": "FrameworksCoreTests",
+ "options": [
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ },
+ {
+ "exclude-annotation": "org.junit.Ignore"
+ },
+ {
+ "include-filter": "android.content.ContextTest"
+ }
+ ],
+ "file_patterns": ["(/|^)Context.java", "(/|^)ContextWrapper.java"]
+ }
+ ]
+} \ No newline at end of file
diff --git a/core/java/android/content/pm/CrossProfileApps.java b/core/java/android/content/pm/CrossProfileApps.java
index 8b411d5fe031..b290679c9fcc 100644
--- a/core/java/android/content/pm/CrossProfileApps.java
+++ b/core/java/android/content/pm/CrossProfileApps.java
@@ -119,8 +119,9 @@ public class CrossProfileApps {
* {@link #getTargetUserProfiles()} if different to the calling user, otherwise a
* {@link SecurityException} will be thrown.
* @param callingActivity The activity to start the new activity from for the purposes of
- * deciding which task the new activity should belong to. If {@code null}, the activity
- * will always be started in a new task.
+ * passing back any result and deciding which task the new activity should belong to. If
+ * {@code null}, the activity will always be started in a new task and no result will be
+ * returned.
*/
@RequiresPermission(anyOf = {
android.Manifest.permission.INTERACT_ACROSS_PROFILES,
@@ -146,8 +147,9 @@ public class CrossProfileApps {
* {@link #getTargetUserProfiles()} if different to the calling user, otherwise a
* {@link SecurityException} will be thrown.
* @param callingActivity The activity to start the new activity from for the purposes of
- * deciding which task the new activity should belong to. If {@code null}, the activity
- * will always be started in a new task.
+ * passing back any result and deciding which task the new activity should belong to. If
+ * {@code null}, the activity will always be started in a new task and no result will be
+ * returned.
* @param options The activity options or {@code null}. See {@link android.app.ActivityOptions}.
*/
@RequiresPermission(anyOf = {
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 044b3b2e8284..d1c4ae9c57c7 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -98,6 +98,11 @@ import java.util.Set;
* packages that are currently installed on the device.
*
* You can find this class through {@link Context#getPackageManager}.
+ *
+ * <p class="note"><strong>Note: </strong>If your app targets Android 11 (API level 30) or
+ * higher, the methods in this class each return a filtered list of apps. Learn more about how to
+ * <a href="/training/basics/intents/package-visibility">manage package visibility</a>.
+ * </p>
*/
public abstract class PackageManager {
private static final String TAG = "PackageManager";
diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java
index 32900225d887..ca5eeb1863c7 100644
--- a/core/java/android/hardware/display/DisplayManager.java
+++ b/core/java/android/hardware/display/DisplayManager.java
@@ -911,38 +911,77 @@ public final class DisplayManager {
public interface DeviceConfig {
/**
- * Key for refresh rate in the zone defined by thresholds.
+ * Key for refresh rate in the low zone defined by thresholds.
*
+ * Note that the name and value don't match because they were added before we had a high
+ * zone to consider.
* @see android.provider.DeviceConfig#NAMESPACE_DISPLAY_MANAGER
* @see android.R.integer#config_defaultZoneBehavior
*/
- String KEY_REFRESH_RATE_IN_ZONE = "refresh_rate_in_zone";
+ String KEY_REFRESH_RATE_IN_LOW_ZONE = "refresh_rate_in_zone";
/**
- * Key for accessing the display brightness thresholds for the configured refresh rate zone.
+ * Key for accessing the low display brightness thresholds for the configured refresh
+ * rate zone.
* The value will be a pair of comma separated integers representing the minimum and maximum
* thresholds of the zone, respectively, in display backlight units (i.e. [0, 255]).
*
+ * Note that the name and value don't match because they were added before we had a high
+ * zone to consider.
+ *
* @see android.provider.DeviceConfig#NAMESPACE_DISPLAY_MANAGER
* @see android.R.array#config_brightnessThresholdsOfPeakRefreshRate
* @hide
*/
- String KEY_PEAK_REFRESH_RATE_DISPLAY_BRIGHTNESS_THRESHOLDS =
+ String KEY_FIXED_REFRESH_RATE_LOW_DISPLAY_BRIGHTNESS_THRESHOLDS =
"peak_refresh_rate_brightness_thresholds";
/**
- * Key for accessing the ambient brightness thresholds for the configured refresh rate zone.
- * The value will be a pair of comma separated integers representing the minimum and maximum
- * thresholds of the zone, respectively, in lux.
+ * Key for accessing the low ambient brightness thresholds for the configured refresh
+ * rate zone. The value will be a pair of comma separated integers representing the minimum
+ * and maximum thresholds of the zone, respectively, in lux.
+ *
+ * Note that the name and value don't match because they were added before we had a high
+ * zone to consider.
*
* @see android.provider.DeviceConfig#NAMESPACE_DISPLAY_MANAGER
* @see android.R.array#config_ambientThresholdsOfPeakRefreshRate
* @hide
*/
- String KEY_PEAK_REFRESH_RATE_AMBIENT_BRIGHTNESS_THRESHOLDS =
+ String KEY_FIXED_REFRESH_RATE_LOW_AMBIENT_BRIGHTNESS_THRESHOLDS =
"peak_refresh_rate_ambient_thresholds";
+ /**
+ * Key for refresh rate in the high zone defined by thresholds.
+ *
+ * @see android.provider.DeviceConfig#NAMESPACE_DISPLAY_MANAGER
+ * @see android.R.integer#config_fixedRefreshRateInHighZone
+ */
+ String KEY_REFRESH_RATE_IN_HIGH_ZONE = "refresh_rate_in_high_zone";
/**
+ * Key for accessing the display brightness thresholds for the configured refresh rate zone.
+ * The value will be a pair of comma separated integers representing the minimum and maximum
+ * thresholds of the zone, respectively, in display backlight units (i.e. [0, 255]).
+ *
+ * @see android.provider.DeviceConfig#NAMESPACE_DISPLAY_MANAGER
+ * @see android.R.array#config_brightnessHighThresholdsOfFixedRefreshRate
+ * @hide
+ */
+ String KEY_FIXED_REFRESH_RATE_HIGH_DISPLAY_BRIGHTNESS_THRESHOLDS =
+ "fixed_refresh_rate_high_display_brightness_thresholds";
+
+ /**
+ * Key for accessing the ambient brightness thresholds for the configured refresh rate zone.
+ * The value will be a pair of comma separated integers representing the minimum and maximum
+ * thresholds of the zone, respectively, in lux.
+ *
+ * @see android.provider.DeviceConfig#NAMESPACE_DISPLAY_MANAGER
+ * @see android.R.array#config_ambientHighThresholdsOfFixedRefreshRate
+ * @hide
+ */
+ String KEY_FIXED_REFRESH_RATE_HIGH_AMBIENT_BRIGHTNESS_THRESHOLDS =
+ "fixed_refresh_rate_high_ambient_brightness_thresholds";
+ /**
* Key for default peak refresh rate
*
* @see android.provider.DeviceConfig#NAMESPACE_DISPLAY_MANAGER
diff --git a/core/java/android/hardware/hdmi/HdmiDeviceInfo.java b/core/java/android/hardware/hdmi/HdmiDeviceInfo.java
index 3fd20f12381e..c6007f1184f5 100644
--- a/core/java/android/hardware/hdmi/HdmiDeviceInfo.java
+++ b/core/java/android/hardware/hdmi/HdmiDeviceInfo.java
@@ -513,4 +513,19 @@ public class HdmiDeviceInfo implements Parcelable {
&& mDeviceId == other.mDeviceId
&& mAdopterId == other.mAdopterId;
}
+
+ @Override
+ public int hashCode() {
+ return java.util.Objects.hash(
+ mHdmiDeviceType,
+ mPhysicalAddress,
+ mPortId,
+ mLogicalAddress,
+ mDeviceType,
+ mVendorId,
+ mDevicePowerStatus,
+ mDisplayName,
+ mDeviceId,
+ mAdopterId);
+ }
}
diff --git a/core/java/android/inputmethodservice/AbstractInputMethodService.java b/core/java/android/inputmethodservice/AbstractInputMethodService.java
index 7cf0b10031ac..3cd13a212a4b 100644
--- a/core/java/android/inputmethodservice/AbstractInputMethodService.java
+++ b/core/java/android/inputmethodservice/AbstractInputMethodService.java
@@ -199,10 +199,11 @@ public abstract class AbstractInputMethodService extends Service
* Dumps the internal state of IME to a protocol buffer output stream.
*
* @param proto ProtoOutputStream to dump data to.
+ * @param icProto {@link InputConnection} call data in proto format.
* @hide
*/
@SuppressWarnings("HiddenAbstractMethod")
- public abstract void dumpProtoInternal(ProtoOutputStream proto);
+ public abstract void dumpProtoInternal(ProtoOutputStream proto, ProtoOutputStream icProto);
/**
* Implement this to handle {@link android.os.Binder#dump Binder.dump()}
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 4a5d831cd705..5576857d1f6b 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -25,6 +25,7 @@ import static android.inputmethodservice.InputMethodServiceProto.EXTRACTED_TOKEN
import static android.inputmethodservice.InputMethodServiceProto.EXTRACT_VIEW_HIDDEN;
import static android.inputmethodservice.InputMethodServiceProto.FULLSCREEN_APPLIED;
import static android.inputmethodservice.InputMethodServiceProto.INPUT_BINDING;
+import static android.inputmethodservice.InputMethodServiceProto.INPUT_CONNECTION_CALL;
import static android.inputmethodservice.InputMethodServiceProto.INPUT_EDITOR_INFO;
import static android.inputmethodservice.InputMethodServiceProto.INPUT_STARTED;
import static android.inputmethodservice.InputMethodServiceProto.INPUT_VIEW_STARTED;
@@ -585,10 +586,12 @@ public class InputMethodService extends AbstractInputMethodService {
Log.w(TAG, "The token has already registered, ignore this initialization.");
return;
}
+ Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMS.initializeInternal");
mPrivOps.set(privilegedOperations);
InputMethodPrivilegedOperationsRegistry.put(token, mPrivOps);
updateInputMethodDisplay(displayId);
attachToken(token);
+ Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
/**
@@ -642,6 +645,7 @@ public class InputMethodService extends AbstractInputMethodService {
@MainThread
@Override
public void bindInput(InputBinding binding) {
+ Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMS.bindInput");
mInputBinding = binding;
mInputConnection = binding.getConnection();
if (DEBUG) Log.v(TAG, "bindInput(): binding=" + binding
@@ -649,6 +653,7 @@ public class InputMethodService extends AbstractInputMethodService {
reportFullscreenMode();
initialize();
onBindInput();
+ Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
/**
@@ -686,7 +691,9 @@ public class InputMethodService extends AbstractInputMethodService {
@Override
public void restartInput(InputConnection ic, EditorInfo attribute) {
if (DEBUG) Log.v(TAG, "restartInput(): editor=" + attribute);
+ Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMS.restartInput");
doStartInput(ic, attribute, true);
+ Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
/**
@@ -736,7 +743,8 @@ public class InputMethodService extends AbstractInputMethodService {
return;
}
ImeTracing.getInstance().triggerServiceDump(
- "InputMethodService.InputMethodImpl#hideSoftInput", InputMethodService.this);
+ "InputMethodService.InputMethodImpl#hideSoftInput", InputMethodService.this,
+ null /* icProto */);
final boolean wasVisible = isInputViewShown();
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMS.hideSoftInput");
@@ -792,7 +800,8 @@ public class InputMethodService extends AbstractInputMethodService {
}
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMS.showSoftInput");
ImeTracing.getInstance().triggerServiceDump(
- "InputMethodService.InputMethodImpl#showSoftInput", InputMethodService.this);
+ "InputMethodService.InputMethodImpl#showSoftInput", InputMethodService.this,
+ null /* icProto */);
final boolean wasVisible = isInputViewShown();
if (dispatchOnShowInputRequested(flags, false)) {
@@ -1253,6 +1262,7 @@ public class InputMethodService extends AbstractInputMethodService {
}
@Override public void onCreate() {
+ Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMS.onCreate");
mTheme = Resources.selectSystemTheme(mTheme,
getApplicationInfo().targetSdkVersion,
android.R.style.Theme_InputMethod,
@@ -1273,6 +1283,7 @@ public class InputMethodService extends AbstractInputMethodService {
// in non-default display.
mInflater = (LayoutInflater)getSystemService(
Context.LAYOUT_INFLATER_SERVICE);
+ Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMS.initSoftInputWindow");
mWindow = new SoftInputWindow(this, "InputMethod", mTheme, null, null, mDispatcherState,
WindowManager.LayoutParams.TYPE_INPUT_METHOD, Gravity.BOTTOM, false);
mWindow.getWindow().getAttributes().setFitInsetsTypes(statusBars() | navigationBars());
@@ -1294,10 +1305,12 @@ public class InputMethodService extends AbstractInputMethodService {
initViews();
mWindow.getWindow().setLayout(MATCH_PARENT, WRAP_CONTENT);
+ Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
mInlineSuggestionSessionController = new InlineSuggestionSessionController(
this::onCreateInlineSuggestionsRequest, this::getHostInputToken,
this::onInlineSuggestionsResponse);
+ Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
/**
@@ -1318,6 +1331,7 @@ public class InputMethodService extends AbstractInputMethodService {
}
void initViews() {
+ Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMS.initViews");
mInitialized = false;
mViewsCreated = false;
mShowInputRequested = false;
@@ -1352,6 +1366,7 @@ public class InputMethodService extends AbstractInputMethodService {
mCandidatesVisibility = getCandidatesHiddenVisibility();
mCandidatesFrame.setVisibility(mCandidatesVisibility);
mInputFrame.setVisibility(View.GONE);
+ Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
@Override public void onDestroy() {
@@ -1393,6 +1408,7 @@ public class InputMethodService extends AbstractInputMethodService {
}
private void resetStateForNewConfiguration() {
+ Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMS.resetStateForNewConfiguration");
boolean visible = mDecorViewVisible;
int showFlags = mShowInputFlags;
boolean showingInput = mShowInputRequested;
@@ -1428,6 +1444,7 @@ public class InputMethodService extends AbstractInputMethodService {
boolean showing = onEvaluateInputViewShown();
setImeWindowStatus(IME_ACTIVE | (showing ? IME_VISIBLE : 0), mBackDisposition);
}
+ Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
/**
@@ -1589,6 +1606,7 @@ public class InputMethodService extends AbstractInputMethodService {
* is currently running in fullscreen mode.
*/
public void updateFullscreenMode() {
+ Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMS.updateFullscreenMode");
boolean isFullscreen = mShowInputRequested && onEvaluateFullscreenMode();
boolean changed = mLastShowInputRequested != mShowInputRequested;
if (mIsFullscreen != isFullscreen || !mFullscreenApplied) {
@@ -1627,6 +1645,7 @@ public class InputMethodService extends AbstractInputMethodService {
onConfigureWindow(mWindow.getWindow(), isFullscreen, !mShowInputRequested);
mLastShowInputRequested = mShowInputRequested;
}
+ Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
/**
@@ -1755,6 +1774,7 @@ public class InputMethodService extends AbstractInputMethodService {
* @param outInsets Fill in with the current UI insets.
*/
public void onComputeInsets(Insets outInsets) {
+ Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMS.onComputeInsets");
int[] loc = mTmpLocation;
if (mInputFrame.getVisibility() == View.VISIBLE) {
mInputFrame.getLocationInWindow(loc);
@@ -1775,6 +1795,7 @@ public class InputMethodService extends AbstractInputMethodService {
outInsets.visibleTopInsets = loc[1];
outInsets.touchableInsets = Insets.TOUCHABLE_INSETS_VISIBLE;
outInsets.touchableRegion.setEmpty();
+ Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
/**
@@ -2164,8 +2185,9 @@ public class InputMethodService extends AbstractInputMethodService {
return;
}
- ImeTracing.getInstance().triggerServiceDump("InputMethodService#showWindow", this);
-
+ ImeTracing.getInstance().triggerServiceDump("InputMethodService#showWindow", this,
+ null /* icProto */);
+ Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMS.showWindow");
mDecorViewWasVisible = mDecorViewVisible;
mInShowWindow = true;
final int previousImeWindowStatus =
@@ -2189,6 +2211,7 @@ public class InputMethodService extends AbstractInputMethodService {
}
mDecorViewWasVisible = true;
mInShowWindow = false;
+ Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
@@ -2241,7 +2264,8 @@ public class InputMethodService extends AbstractInputMethodService {
*/
private void applyVisibilityInInsetsConsumerIfNecessary(boolean setVisible) {
ImeTracing.getInstance().triggerServiceDump(
- "InputMethodService#applyVisibilityInInsetsConsumerIfNecessary", this);
+ "InputMethodService#applyVisibilityInInsetsConsumerIfNecessary", this,
+ null /* icProto */);
mPrivOps.applyImeVisibility(setVisible
? mCurShowInputToken : mCurHideInputToken, setVisible);
}
@@ -2266,7 +2290,8 @@ public class InputMethodService extends AbstractInputMethodService {
public void hideWindow() {
if (DEBUG) Log.v(TAG, "CALL: hideWindow");
- ImeTracing.getInstance().triggerServiceDump("InputMethodService#hideWindow", this);
+ ImeTracing.getInstance().triggerServiceDump("InputMethodService#hideWindow", this,
+ null /* icProto */);
mWindowVisible = false;
finishViews(false /* finishingInput */);
if (mDecorViewVisible) {
@@ -2337,7 +2362,8 @@ public class InputMethodService extends AbstractInputMethodService {
void doFinishInput() {
if (DEBUG) Log.v(TAG, "CALL: doFinishInput");
- ImeTracing.getInstance().triggerServiceDump("InputMethodService#doFinishInput", this);
+ ImeTracing.getInstance().triggerServiceDump("InputMethodService#doFinishInput", this,
+ null /* icProto */);
finishViews(true /* finishingInput */);
if (mInputStarted) {
mInlineSuggestionSessionController.notifyOnFinishInput();
@@ -2353,7 +2379,8 @@ public class InputMethodService extends AbstractInputMethodService {
if (!restarting && mInputStarted) {
doFinishInput();
}
- ImeTracing.getInstance().triggerServiceDump("InputMethodService#doStartInput", this);
+ ImeTracing.getInstance().triggerServiceDump("InputMethodService#doStartInput", this,
+ null /* icProto */);
mInputStarted = true;
mStartedInputConnection = ic;
mInputEditorInfo = attribute;
@@ -2512,7 +2539,8 @@ public class InputMethodService extends AbstractInputMethodService {
* @param flags Provides additional operating flags.
*/
public void requestHideSelf(int flags) {
- ImeTracing.getInstance().triggerServiceDump("InputMethodService#requestHideSelf", this);
+ ImeTracing.getInstance().triggerServiceDump("InputMethodService#requestHideSelf", this,
+ null /* icProto */);
mPrivOps.hideMySoftInput(flags);
}
@@ -2525,7 +2553,8 @@ public class InputMethodService extends AbstractInputMethodService {
* @param flags Provides additional operating flags.
*/
public final void requestShowSelf(int flags) {
- ImeTracing.getInstance().triggerServiceDump("InputMethodService#requestShowSelf", this);
+ ImeTracing.getInstance().triggerServiceDump("InputMethodService#requestShowSelf", this,
+ null /* icProto */);
mPrivOps.showMySoftInput(flags);
}
@@ -3345,7 +3374,7 @@ public class InputMethodService extends AbstractInputMethodService {
* @hide
*/
@Override
- public final void dumpProtoInternal(ProtoOutputStream proto) {
+ public final void dumpProtoInternal(ProtoOutputStream proto, ProtoOutputStream icProto) {
final long token = proto.start(InputMethodServiceTraceProto.INPUT_METHOD_SERVICE);
mWindow.dumpDebug(proto, SOFT_INPUT_WINDOW);
proto.write(VIEWS_CREATED, mViewsCreated);
@@ -3374,6 +3403,9 @@ public class InputMethodService extends AbstractInputMethodService {
proto.write(STATUS_ICON, mStatusIcon);
mTmpInsets.dumpDebug(proto, LAST_COMPUTED_INSETS);
proto.write(SETTINGS_OBSERVER, Objects.toString(mSettingsObserver));
+ if (icProto != null) {
+ proto.write(INPUT_CONNECTION_CALL, icProto.getBytes());
+ }
proto.end(token);
}
}
diff --git a/core/java/android/net/CaptivePortal.java b/core/java/android/net/CaptivePortal.java
index c2586fa0c825..269bbf20c8b1 100644
--- a/core/java/android/net/CaptivePortal.java
+++ b/core/java/android/net/CaptivePortal.java
@@ -15,7 +15,6 @@
*/
package android.net;
-import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
@@ -24,8 +23,6 @@ import android.os.Parcel;
import android.os.Parcelable;
import android.os.RemoteException;
-import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-
/**
* A class allowing apps handling the {@link ConnectivityManager#ACTION_CAPTIVE_PORTAL_SIGN_IN}
* activity to indicate to the system different outcomes of captive portal sign in. This class is
@@ -75,17 +72,6 @@ public class CaptivePortal implements Parcelable {
private final IBinder mBinder;
/** @hide */
- @IntDef(value = {
- MetricsEvent.ACTION_CAPTIVE_PORTAL_LOGIN_ACTIVITY,
- MetricsEvent.ACTION_CAPTIVE_PORTAL_LOGIN_RESULT_DISMISSED,
- MetricsEvent.ACTION_CAPTIVE_PORTAL_LOGIN_RESULT_UNWANTED,
- MetricsEvent.ACTION_CAPTIVE_PORTAL_LOGIN_RESULT_WANTED_AS_IS,
- MetricsEvent.CAPTIVE_PORTAL_LOGIN_ACTIVITY_SSL_ERROR,
- })
- public @interface EventId {
- }
-
- /** @hide */
public CaptivePortal(@NonNull IBinder binder) {
mBinder = binder;
}
@@ -176,7 +162,7 @@ public class CaptivePortal implements Parcelable {
* @hide
*/
@SystemApi
- public void logEvent(@EventId int eventId, @NonNull String packageName) {
+ public void logEvent(int eventId, @NonNull String packageName) {
try {
ICaptivePortal.Stub.asInterface(mBinder).logEvent(eventId, packageName);
} catch (RemoteException e) {
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 4b38d6377f37..3f2c966f9ed2 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -684,7 +684,7 @@ public class ConnectivityManager {
* {@hide}
*/
@Deprecated
- @UnsupportedAppUsage
+ @SystemApi
public static final int TYPE_PROXY = 16;
/**
diff --git a/core/java/android/net/NetworkProvider.java b/core/java/android/net/NetworkProvider.java
index d31218d9b67b..a17a49897d39 100644
--- a/core/java/android/net/NetworkProvider.java
+++ b/core/java/android/net/NetworkProvider.java
@@ -51,13 +51,6 @@ public class NetworkProvider {
public static final int ID_NONE = -1;
/**
- * A hardcoded ID for NetworkAgents representing VPNs. These agents are not created by any
- * provider, so they use this constant for clarity instead of NONE.
- * @hide only used by ConnectivityService.
- */
- public static final int ID_VPN = -2;
-
- /**
* The first providerId value that will be allocated.
* @hide only used by ConnectivityService.
*/
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index d130bc5d37e7..b951aca6d680 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -67,7 +67,7 @@ public final class PowerManager {
/* NOTE: Wake lock levels were previously defined as a bit field, except that only a few
* combinations were actually supported so the bit field was removed. This explains
* why the numbering scheme is so odd. If adding a new wake lock level, any unused
- * value (in frameworks/base/core/proto/android/os/enums.proto) can be used.
+ * value (in frameworks/proto_logging/stats/enums/os/enums.proto) can be used.
*/
/**
diff --git a/core/java/android/os/VibrationEffect.java b/core/java/android/os/VibrationEffect.java
index 0f2a9f21a0bc..f76eb86f0fca 100644
--- a/core/java/android/os/VibrationEffect.java
+++ b/core/java/android/os/VibrationEffect.java
@@ -1138,8 +1138,7 @@ public abstract class VibrationEffect implements Parcelable {
*
* @param primitiveId The primitive to add
* @param scale The scale to apply to the intensity of the primitive.
- * @param delay The amount of time, in milliseconds, to wait between playing the prior
- * primitive and this one
+ * @param delay The amount of time in milliseconds to wait before playing this primitive
* @return The {@link Composition} object to enable adding multiple primitives in one chain.
*/
@NonNull
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index cfc3e01c23c5..870d224f2ff7 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -156,10 +156,6 @@ public class StorageManager {
/** {@hide} */
public static final String PROP_VIRTUAL_DISK = "persist.sys.virtual_disk";
/** {@hide} */
- public static final String PROP_ISOLATED_STORAGE = "persist.sys.isolated_storage";
- /** {@hide} */
- public static final String PROP_ISOLATED_STORAGE_SNAPSHOT = "sys.isolated_storage_snapshot";
- /** {@hide} */
public static final String PROP_FORCED_SCOPED_STORAGE_WHITELIST =
"forced_scoped_storage_whitelist";
@@ -263,10 +259,6 @@ public class StorageManager {
public static final int DEBUG_SDCARDFS_FORCE_OFF = 1 << 4;
/** {@hide} */
public static final int DEBUG_VIRTUAL_DISK = 1 << 5;
- /** {@hide} */
- public static final int DEBUG_ISOLATED_STORAGE_FORCE_ON = 1 << 6;
- /** {@hide} */
- public static final int DEBUG_ISOLATED_STORAGE_FORCE_OFF = 1 << 7;
/** {@hide} */
public static final int FLAG_STORAGE_DE = IInstalld.FLAG_STORAGE_DE;
@@ -1695,16 +1687,13 @@ public class StorageManager {
/**
* Return if the currently booted device has the "isolated storage" feature
- * flag enabled. This will eventually be fully enabled in the final
- * {@link android.os.Build.VERSION_CODES#Q} release.
+ * flag enabled.
*
* @hide
*/
@SystemApi
public static boolean hasIsolatedStorage() {
- // Prefer to use snapshot for current boot when available
- return SystemProperties.getBoolean(PROP_ISOLATED_STORAGE_SNAPSHOT,
- SystemProperties.getBoolean(PROP_ISOLATED_STORAGE, true));
+ return false;
}
/**
diff --git a/core/java/android/os/storage/StorageManagerInternal.java b/core/java/android/os/storage/StorageManagerInternal.java
index 4379ce1055ef..55ba15a5e57b 100644
--- a/core/java/android/os/storage/StorageManagerInternal.java
+++ b/core/java/android/os/storage/StorageManagerInternal.java
@@ -28,50 +28,8 @@ import java.util.Set;
* @hide Only for use within the system server.
*/
public abstract class StorageManagerInternal {
-
- /**
- * Policy that influences how external storage is mounted and reported.
- */
- public interface ExternalStorageMountPolicy {
- /**
- * Gets the external storage mount mode for the given uid.
- *
- * @param uid The UID for which to determine mount mode.
- * @param packageName The package in the UID for making the call.
- * @return The mount mode.
- *
- * @see com.android.internal.os.Zygote#MOUNT_EXTERNAL_NONE
- * @see com.android.internal.os.Zygote#MOUNT_EXTERNAL_DEFAULT
- * @see com.android.internal.os.Zygote#MOUNT_EXTERNAL_READ
- * @see com.android.internal.os.Zygote#MOUNT_EXTERNAL_WRITE
- */
- public int getMountMode(int uid, String packageName);
-
- /**
- * Gets whether external storage should be reported to the given UID.
- *
- * @param uid The UID for which to determine whether it has external storage.
- * @param packageName The package in the UID for making the call.
- * @return Weather to report external storage.
- * @return True to report the state of external storage, false to
- * report it as unmounted.
- */
- public boolean hasExternalStorage(int uid, String packageName);
- }
-
- /**
- * Adds a policy for determining how external storage is mounted and reported.
- * The mount mode is the most conservative result from querying all registered
- * policies. Similarly, the reported state is the most conservative result from
- * querying all registered policies.
- *
- * @param policy The policy to add.
- */
- public abstract void addExternalStoragePolicy(ExternalStorageMountPolicy policy);
-
/**
- * Gets the mount mode to use for a given UID as determined by consultin all
- * policies.
+ * Gets the mount mode to use for a given UID
*
* @param uid The UID for which to get mount mode.
* @param packageName The package in the UID for making the call.
diff --git a/core/java/android/os/storage/VolumeInfo.java b/core/java/android/os/storage/VolumeInfo.java
index 901494b845b0..237a9f2867d6 100644
--- a/core/java/android/os/storage/VolumeInfo.java
+++ b/core/java/android/os/storage/VolumeInfo.java
@@ -200,6 +200,21 @@ public class VolumeInfo implements Parcelable {
internalPath = parcel.readString8();
}
+ public VolumeInfo(VolumeInfo volumeInfo) {
+ this.id = volumeInfo.id;
+ this.type = volumeInfo.type;
+ this.disk = volumeInfo.disk;
+ this.partGuid = volumeInfo.partGuid;
+ this.mountFlags = volumeInfo.mountFlags;
+ this.mountUserId = volumeInfo.mountUserId;
+ this.state = volumeInfo.state;
+ this.fsType = volumeInfo.fsType;
+ this.fsUuid = volumeInfo.fsUuid;
+ this.fsLabel = volumeInfo.fsLabel;
+ this.path = volumeInfo.path;
+ this.internalPath = volumeInfo.internalPath;
+ }
+
@UnsupportedAppUsage
public static @NonNull String getEnvironmentForState(int state) {
final String envState = sStateToEnvironment.get(state);
diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java
index 714bcea9c01f..44cc0f5c330d 100644
--- a/core/java/android/provider/DeviceConfig.java
+++ b/core/java/android/provider/DeviceConfig.java
@@ -451,6 +451,22 @@ public final class DeviceConfig {
"connectivity_thermal_power_manager";
/**
+ * Namespace for all statsd native features that can be applied immediately.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final String NAMESPACE_STATSD_NATIVE = "statsd_native";
+
+ /**
+ * Namespace for all statsd native features that are applied on boot.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final String NAMESPACE_STATSD_NATIVE_BOOT = "statsd_native_boot";
+
+ /**
* Namespace for configuration related features.
*
* @hide
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 884f8ccd5e54..b86b9ff814ae 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -9797,12 +9797,13 @@ public final class Settings {
"use_blast_adapter_sv";
/**
- * If {@code true}, vendor provided window manager display settings will be ignored.
- * (0 = false, 1 = true)
+ * Path to the WindowManager display settings file. If unset, the default file path will
+ * be used.
+ *
* @hide
*/
- public static final String DEVELOPMENT_IGNORE_VENDOR_DISPLAY_SETTINGS =
- "ignore_vendor_display_settings";
+ public static final String DEVELOPMENT_WM_DISPLAY_SETTINGS_PATH =
+ "wm_display_settings_path";
/**
* Whether user has enabled development settings.
@@ -13286,16 +13287,6 @@ public final class Settings {
"storage_settings_clobber_threshold";
/**
- * If set to 1, {@link Secure#LOCATION_MODE} will be set to {@link Secure#LOCATION_MODE_OFF}
- * temporarily for all users.
- *
- * @hide
- */
- @TestApi
- public static final String LOCATION_GLOBAL_KILL_SWITCH =
- "location_global_kill_switch";
-
- /**
* If set to 1, SettingsProvider's restoreAnyVersion="true" attribute will be ignored
* and restoring to lower version of platform API will be skipped.
*
@@ -13415,11 +13406,6 @@ public final class Settings {
public static final String MAX_SOUND_TRIGGER_DETECTION_SERVICE_OPS_PER_DAY =
"max_sound_trigger_detection_service_ops_per_day";
- /** {@hide} */
- public static final String ISOLATED_STORAGE_LOCAL = "isolated_storage_local";
- /** {@hide} */
- public static final String ISOLATED_STORAGE_REMOTE = "isolated_storage_remote";
-
/**
* Indicates whether aware is available in the current location.
* @hide
diff --git a/core/java/android/service/autofill/TEST_MAPPING b/core/java/android/service/autofill/TEST_MAPPING
new file mode 100644
index 000000000000..87a17ebee36d
--- /dev/null
+++ b/core/java/android/service/autofill/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "imports": [
+ {
+ "path": "frameworks/base/services/autofill/java/com/android/server/autofill"
+ }
+ ]
+}
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index 9a76f19f3e41..37637119c70a 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -199,6 +199,7 @@ public abstract class WallpaperService extends Service {
final InsetsSourceControl[] mTempControls = new InsetsSourceControl[0];
final MergedConfiguration mMergedConfiguration = new MergedConfiguration();
private final Point mSurfaceSize = new Point();
+ private final Point mLastSurfaceSize = new Point();
private final Matrix mTmpMatrix = new Matrix();
private final float[] mTmpValues = new float[9];
@@ -908,6 +909,14 @@ public abstract class WallpaperService extends Service {
if (mSurfaceControl.isValid()) {
mSurfaceHolder.mSurface.copyFrom(mSurfaceControl);
}
+ if (!mLastSurfaceSize.equals(mSurfaceSize)) {
+ mLastSurfaceSize.set(mSurfaceSize.x, mSurfaceSize.y);
+ if (mSurfaceControl != null && mSurfaceControl.isValid()) {
+ SurfaceControl.Transaction t = new SurfaceControl.Transaction();
+ t.setBufferSize(mSurfaceControl, mSurfaceSize.x, mSurfaceSize.y);
+ t.apply();
+ }
+ }
if (DEBUG) Log.v(TAG, "New surface: " + mSurfaceHolder.mSurface
+ ", frame=" + mWinFrames);
diff --git a/core/java/android/util/DebugUtils.java b/core/java/android/util/DebugUtils.java
index 6d5e830346cd..ece6b3516f7a 100644
--- a/core/java/android/util/DebugUtils.java
+++ b/core/java/android/util/DebugUtils.java
@@ -271,6 +271,26 @@ public class DebugUtils {
return res.toString();
}
+ /**
+ * Gets human-readable representation of constants (static final values).
+ *
+ * @hide
+ */
+ public static String constantToString(Class<?> clazz, String prefix, int value) {
+ for (Field field : clazz.getDeclaredFields()) {
+ final int modifiers = field.getModifiers();
+ try {
+ if (Modifier.isStatic(modifiers) && Modifier.isFinal(modifiers)
+ && field.getType().equals(int.class) && field.getName().startsWith(prefix)
+ && field.getInt(null) == value) {
+ return constNameWithoutPrefix(prefix, field);
+ }
+ } catch (IllegalAccessException ignored) {
+ }
+ }
+ return prefix + Integer.toString(value);
+ }
+
private static String constNameWithoutPrefix(String prefix, Field field) {
return field.getName().substring(prefix.length());
}
diff --git a/core/java/android/util/imetracing/ImeTracing.java b/core/java/android/util/imetracing/ImeTracing.java
index 4058eef3e2a3..723f1dd15e23 100644
--- a/core/java/android/util/imetracing/ImeTracing.java
+++ b/core/java/android/util/imetracing/ImeTracing.java
@@ -110,15 +110,20 @@ public abstract class ImeTracing {
*
* @param where Place where the trace was triggered.
* @param immInstance The {@link InputMethodManager} instance to dump.
+ * @param icProto {@link android.view.inputmethod.InputConnection} call data in proto format.
*/
- public abstract void triggerClientDump(String where, InputMethodManager immInstance);
+ public abstract void triggerClientDump(String where, InputMethodManager immInstance,
+ ProtoOutputStream icProto);
/**
* Starts a proto dump of the currently connected InputMethodService information.
*
* @param where Place where the trace was triggered.
+ * @param service The {@link android.inputmethodservice.InputMethodService} to be dumped.
+ * @param icProto {@link android.view.inputmethod.InputConnection} call data in proto format.
*/
- public abstract void triggerServiceDump(String where, AbstractInputMethodService service);
+ public abstract void triggerServiceDump(String where, AbstractInputMethodService service,
+ ProtoOutputStream icProto);
/**
* Starts a proto dump of the InputMethodManagerService information.
diff --git a/core/java/android/util/imetracing/ImeTracingClientImpl.java b/core/java/android/util/imetracing/ImeTracingClientImpl.java
index 904b44da97d7..6cc652d942cc 100644
--- a/core/java/android/util/imetracing/ImeTracingClientImpl.java
+++ b/core/java/android/util/imetracing/ImeTracingClientImpl.java
@@ -45,7 +45,8 @@ class ImeTracingClientImpl extends ImeTracing {
}
@Override
- public void triggerClientDump(String where, @NonNull InputMethodManager immInstance) {
+ public void triggerClientDump(String where, @NonNull InputMethodManager immInstance,
+ ProtoOutputStream icProto) {
if (!isEnabled() || !isAvailable()) {
return;
}
@@ -59,7 +60,7 @@ class ImeTracingClientImpl extends ImeTracing {
try {
ProtoOutputStream proto = new ProtoOutputStream();
- immInstance.dumpDebug(proto);
+ immInstance.dumpDebug(proto, icProto);
sendToService(proto.getBytes(), IME_TRACING_FROM_CLIENT, where);
} catch (RemoteException e) {
Log.e(TAG, "Exception while sending ime-related client dump to server", e);
@@ -69,7 +70,8 @@ class ImeTracingClientImpl extends ImeTracing {
}
@Override
- public void triggerServiceDump(String where, @NonNull AbstractInputMethodService service) {
+ public void triggerServiceDump(String where, @NonNull AbstractInputMethodService service,
+ ProtoOutputStream icProto) {
if (!isEnabled() || !isAvailable()) {
return;
}
@@ -83,7 +85,7 @@ class ImeTracingClientImpl extends ImeTracing {
try {
ProtoOutputStream proto = new ProtoOutputStream();
- service.dumpProtoInternal(proto);
+ service.dumpProtoInternal(proto, icProto);
sendToService(proto.getBytes(), IME_TRACING_FROM_IMS, where);
} catch (RemoteException e) {
Log.e(TAG, "Exception while sending ime-related service dump to server", e);
diff --git a/core/java/android/util/imetracing/ImeTracingServerImpl.java b/core/java/android/util/imetracing/ImeTracingServerImpl.java
index d758d77fb2f2..e793c280afbc 100644
--- a/core/java/android/util/imetracing/ImeTracingServerImpl.java
+++ b/core/java/android/util/imetracing/ImeTracingServerImpl.java
@@ -133,12 +133,14 @@ class ImeTracingServerImpl extends ImeTracing {
}
@Override
- public void triggerClientDump(String where, InputMethodManager immInstance) {
+ public void triggerClientDump(String where, InputMethodManager immInstance,
+ ProtoOutputStream icProto) {
// Intentionally left empty, this is implemented in ImeTracingClientImpl
}
@Override
- public void triggerServiceDump(String where, AbstractInputMethodService service) {
+ public void triggerServiceDump(String where, AbstractInputMethodService service,
+ ProtoOutputStream icProto) {
// Intentionally left empty, this is implemented in ImeTracingClientImpl
}
diff --git a/core/java/android/util/imetracing/InputConnectionHelper.java b/core/java/android/util/imetracing/InputConnectionHelper.java
new file mode 100644
index 000000000000..39f1e01eb4a9
--- /dev/null
+++ b/core/java/android/util/imetracing/InputConnectionHelper.java
@@ -0,0 +1,231 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.util.imetracing;
+
+import static android.view.inputmethod.InputConnectionCallProto.GET_CURSOR_CAPS_MODE;
+import static android.view.inputmethod.InputConnectionCallProto.GET_EXTRACTED_TEXT;
+import static android.view.inputmethod.InputConnectionCallProto.GET_SELECTED_TEXT;
+import static android.view.inputmethod.InputConnectionCallProto.GET_SURROUNDING_TEXT;
+import static android.view.inputmethod.InputConnectionCallProto.GET_TEXT_AFTER_CURSOR;
+import static android.view.inputmethod.InputConnectionCallProto.GET_TEXT_BEFORE_CURSOR;
+import static android.view.inputmethod.InputConnectionCallProto.GetExtractedText.REQUEST;
+
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.util.proto.ProtoOutputStream;
+import android.view.inputmethod.ExtractedText;
+import android.view.inputmethod.ExtractedTextRequest;
+import android.view.inputmethod.InputConnectionCallProto.GetCursorCapsMode;
+import android.view.inputmethod.InputConnectionCallProto.GetExtractedText;
+import android.view.inputmethod.InputConnectionCallProto.GetSelectedText;
+import android.view.inputmethod.InputConnectionCallProto.GetSurroundingText;
+import android.view.inputmethod.InputConnectionCallProto.GetTextAfterCursor;
+import android.view.inputmethod.InputConnectionCallProto.GetTextBeforeCursor;
+import android.view.inputmethod.SurroundingText;
+
+/**
+ * Helper class for constructing {@link android.view.inputmethod.InputConnection} dumps, which are
+ * integrated into {@link ImeTracing}.
+ * @hide
+ */
+public class InputConnectionHelper {
+ static final String TAG = "InputConnectionHelper";
+ public static final boolean DUMP_TEXT = false;
+
+ private InputConnectionHelper() {}
+
+ /**
+ * Builder for InputConnectionCallProto to hold
+ * {@link android.view.inputmethod.InputConnection#getTextAfterCursor(int, int)} data.
+ *
+ * @param length The expected length of the text. This must be non-negative.
+ * @param flags Supplies additional options controlling how the text is
+ * returned. May be either {@code 0} or
+ * {@link android.view.inputmethod.InputConnection#GET_TEXT_WITH_STYLES}.
+ * @param result The text after the cursor position; the length of the
+ * returned text might be less than <var>length</var>.
+ * @return ProtoOutputStream holding the InputConnectionCallProto data.
+ */
+ public static ProtoOutputStream buildGetTextAfterCursorProto(@IntRange(from = 0) int length,
+ int flags, @Nullable CharSequence result) {
+ ProtoOutputStream proto = new ProtoOutputStream();
+ final long token = proto.start(GET_TEXT_AFTER_CURSOR);
+ proto.write(GetTextAfterCursor.LENGTH, length);
+ proto.write(GetTextAfterCursor.FLAGS, flags);
+ if (result == null) {
+ proto.write(GetTextAfterCursor.RESULT, "null result");
+ } else if (DUMP_TEXT) {
+ proto.write(GetTextAfterCursor.RESULT, result.toString());
+ }
+ proto.end(token);
+ return proto;
+ }
+
+ /**
+ * Builder for InputConnectionCallProto to hold
+ * {@link android.view.inputmethod.InputConnection#getTextBeforeCursor(int, int)} data.
+ *
+ * @param length The expected length of the text. This must be non-negative.
+ * @param flags Supplies additional options controlling how the text is
+ * returned. May be either {@code 0} or
+ * {@link android.view.inputmethod.InputConnection#GET_TEXT_WITH_STYLES}.
+ * @param result The text before the cursor position; the length of the
+ * returned text might be less than <var>length</var>.
+ * @return ProtoOutputStream holding the InputConnectionCallProto data.
+ */
+ public static ProtoOutputStream buildGetTextBeforeCursorProto(@IntRange(from = 0) int length,
+ int flags, @Nullable CharSequence result) {
+ ProtoOutputStream proto = new ProtoOutputStream();
+ final long token = proto.start(GET_TEXT_BEFORE_CURSOR);
+ proto.write(GetTextBeforeCursor.LENGTH, length);
+ proto.write(GetTextBeforeCursor.FLAGS, flags);
+ if (result == null) {
+ proto.write(GetTextBeforeCursor.RESULT, "null result");
+ } else if (DUMP_TEXT) {
+ proto.write(GetTextBeforeCursor.RESULT, result.toString());
+ }
+ proto.end(token);
+ return proto;
+ }
+
+ /**
+ * Builder for InputConnectionCallProto to hold
+ * {@link android.view.inputmethod.InputConnection#getSelectedText(int)} data.
+ *
+ * @param flags Supplies additional options controlling how the text is
+ * returned. May be either {@code 0} or
+ * {@link android.view.inputmethod.InputConnection#GET_TEXT_WITH_STYLES}.
+ * @param result the text that is currently selected, if any, or null if
+ * no text is selected. In {@link android.os.Build.VERSION_CODES#N} and
+ * later, returns false when the target application does not implement
+ * this method.
+ * @return ProtoOutputStream holding the InputConnectionCallProto data.
+ */
+ public static ProtoOutputStream buildGetSelectedTextProto(int flags,
+ @Nullable CharSequence result) {
+ ProtoOutputStream proto = new ProtoOutputStream();
+ final long token = proto.start(GET_SELECTED_TEXT);
+ proto.write(GetSelectedText.FLAGS, flags);
+ if (result == null) {
+ proto.write(GetSelectedText.RESULT, "null result");
+ } else if (DUMP_TEXT) {
+ proto.write(GetSelectedText.RESULT, result.toString());
+ }
+ proto.end(token);
+ return proto;
+ }
+
+ /**
+ * Builder for InputConnectionCallProto to hold
+ * {@link android.view.inputmethod.InputConnection#getSurroundingText(int, int, int)} data.
+ *
+ * @param beforeLength The expected length of the text before the cursor.
+ * @param afterLength The expected length of the text after the cursor.
+ * @param flags Supplies additional options controlling how the text is
+ * returned. May be either {@code 0} or
+ * {@link android.view.inputmethod.InputConnection#GET_TEXT_WITH_STYLES}.
+ * @param result an {@link android.view.inputmethod.SurroundingText} object describing the
+ * surrounding text and state of selection, or null if the input connection is no longer valid,
+ * or the editor can't comply with the request for some reason, or the application does not
+ * implement this method. The length of the returned text might be less than the sum of
+ * <var>beforeLength</var> and <var>afterLength</var> .
+ * @return ProtoOutputStream holding the InputConnectionCallProto data.
+ */
+ public static ProtoOutputStream buildGetSurroundingTextProto(@IntRange(from = 0)
+ int beforeLength, @IntRange(from = 0) int afterLength, int flags,
+ @Nullable SurroundingText result) {
+ ProtoOutputStream proto = new ProtoOutputStream();
+ final long token = proto.start(GET_SURROUNDING_TEXT);
+ proto.write(GetSurroundingText.BEFORE_LENGTH, beforeLength);
+ proto.write(GetSurroundingText.AFTER_LENGTH, afterLength);
+ proto.write(GetSurroundingText.FLAGS, flags);
+ if (result == null) {
+ final long token_result = proto.start(GetSurroundingText.RESULT);
+ proto.write(GetSurroundingText.SurroundingText.TEXT, "null result");
+ proto.end(token_result);
+ } else if (DUMP_TEXT) {
+ final long token_result = proto.start(GetSurroundingText.RESULT);
+ proto.write(GetSurroundingText.SurroundingText.TEXT, result.getText().toString());
+ proto.write(GetSurroundingText.SurroundingText.SELECTION_START,
+ result.getSelectionStart());
+ proto.write(GetSurroundingText.SurroundingText.SELECTION_END,
+ result.getSelectionEnd());
+ proto.write(GetSurroundingText.SurroundingText.OFFSET, result.getOffset());
+ proto.end(token_result);
+ }
+ proto.end(token);
+ return proto;
+ }
+
+ /**
+ * Builder for InputConnectionCallProto to hold
+ * {@link android.view.inputmethod.InputConnection#getCursorCapsMode(int)} data.
+ *
+ * @param reqModes The desired modes to retrieve, as defined by
+ * {@link android.text.TextUtils#getCapsMode TextUtils.getCapsMode}.
+ * @param result the caps mode flags that are in effect at the current
+ * cursor position. See TYPE_TEXT_FLAG_CAPS_* in {@link android.text.InputType}.
+ * @return ProtoOutputStream holding the InputConnectionCallProto data.
+ */
+ public static ProtoOutputStream buildGetCursorCapsModeProto(int reqModes, int result) {
+ ProtoOutputStream proto = new ProtoOutputStream();
+ final long token = proto.start(GET_CURSOR_CAPS_MODE);
+ proto.write(GetCursorCapsMode.REQ_MODES, reqModes);
+ if (DUMP_TEXT) {
+ proto.write(GetCursorCapsMode.RESULT, result);
+ }
+ proto.end(token);
+ return proto;
+ }
+
+ /**
+ * Builder for InputConnectionCallProto to hold
+ * {@link android.view.inputmethod.InputConnection#getExtractedText(ExtractedTextRequest, int)}
+ * data.
+ *
+ * @param request Description of how the text should be returned.
+ * {@link android.view.inputmethod.ExtractedTextRequest}
+ * @param flags Additional options to control the client, either {@code 0} or
+ * {@link android.view.inputmethod.InputConnection#GET_EXTRACTED_TEXT_MONITOR}.
+ * @param result an {@link android.view.inputmethod.ExtractedText}
+ * object describing the state of the text view and containing the
+ * extracted text itself, or null if the input connection is no
+ * longer valid of the editor can't comply with the request for
+ * some reason.
+ * @return ProtoOutputStream holding the InputConnectionCallProto data.
+ */
+ public static ProtoOutputStream buildGetExtractedTextProto(@NonNull ExtractedTextRequest
+ request, int flags, @Nullable ExtractedText result) {
+ ProtoOutputStream proto = new ProtoOutputStream();
+ final long token = proto.start(GET_EXTRACTED_TEXT);
+ final long token_request = proto.start(REQUEST);
+ proto.write(GetExtractedText.ExtractedTextRequest.TOKEN, request.token);
+ proto.write(GetExtractedText.ExtractedTextRequest.FLAGS, request.flags);
+ proto.write(GetExtractedText.ExtractedTextRequest.HINT_MAX_LINES, request.hintMaxLines);
+ proto.write(GetExtractedText.ExtractedTextRequest.HINT_MAX_CHARS, request.hintMaxChars);
+ proto.end(token_request);
+ proto.write(GetExtractedText.FLAGS, flags);
+ if (result == null) {
+ proto.write(GetExtractedText.RESULT, "null result");
+ } else if (DUMP_TEXT) {
+ proto.write(GetExtractedText.RESULT, result.text.toString());
+ }
+ proto.end(token);
+ return proto;
+ }
+}
diff --git a/core/java/android/view/ContentInfo.java b/core/java/android/view/ContentInfo.java
new file mode 100644
index 000000000000..b58937beed55
--- /dev/null
+++ b/core/java/android/view/ContentInfo.java
@@ -0,0 +1,358 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.ClipData;
+import android.net.Uri;
+import android.os.Bundle;
+import android.util.ArrayMap;
+
+import com.android.internal.util.Preconditions;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.Map;
+import java.util.Objects;
+import java.util.function.Predicate;
+
+/**
+ * Holds all the relevant data for a request to {@link View#performReceiveContent}.
+ */
+public final class ContentInfo {
+
+ /**
+ * Specifies the UI through which content is being inserted. Future versions of Android may
+ * support additional values.
+ *
+ * @hide
+ */
+ @IntDef(prefix = {"SOURCE_"}, value = {SOURCE_APP, SOURCE_CLIPBOARD, SOURCE_INPUT_METHOD,
+ SOURCE_DRAG_AND_DROP, SOURCE_AUTOFILL, SOURCE_PROCESS_TEXT})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Source {}
+
+ /**
+ * Specifies that the operation was triggered by the app that contains the target view.
+ */
+ public static final int SOURCE_APP = 0;
+
+ /**
+ * Specifies that the operation was triggered by a paste from the clipboard (e.g. "Paste" or
+ * "Paste as plain text" action in the insertion/selection menu).
+ */
+ public static final int SOURCE_CLIPBOARD = 1;
+
+ /**
+ * Specifies that the operation was triggered from the soft keyboard (also known as input
+ * method editor or IME). See https://developer.android.com/guide/topics/text/image-keyboard
+ * for more info.
+ */
+ public static final int SOURCE_INPUT_METHOD = 2;
+
+ /**
+ * Specifies that the operation was triggered by the drag/drop framework. See
+ * https://developer.android.com/guide/topics/ui/drag-drop for more info.
+ */
+ public static final int SOURCE_DRAG_AND_DROP = 3;
+
+ /**
+ * Specifies that the operation was triggered by the autofill framework. See
+ * https://developer.android.com/guide/topics/text/autofill for more info.
+ */
+ public static final int SOURCE_AUTOFILL = 4;
+
+ /**
+ * Specifies that the operation was triggered by a result from a
+ * {@link android.content.Intent#ACTION_PROCESS_TEXT PROCESS_TEXT} action in the selection
+ * menu.
+ */
+ public static final int SOURCE_PROCESS_TEXT = 5;
+
+ /**
+ * Returns the symbolic name of the given source.
+ *
+ * @hide
+ */
+ static String sourceToString(@Source int source) {
+ switch (source) {
+ case SOURCE_APP: return "SOURCE_APP";
+ case SOURCE_CLIPBOARD: return "SOURCE_CLIPBOARD";
+ case SOURCE_INPUT_METHOD: return "SOURCE_INPUT_METHOD";
+ case SOURCE_DRAG_AND_DROP: return "SOURCE_DRAG_AND_DROP";
+ case SOURCE_AUTOFILL: return "SOURCE_AUTOFILL";
+ case SOURCE_PROCESS_TEXT: return "SOURCE_PROCESS_TEXT";
+ }
+ return String.valueOf(source);
+ }
+
+ /**
+ * Flags to configure the insertion behavior.
+ *
+ * @hide
+ */
+ @IntDef(flag = true, prefix = {"FLAG_"}, value = {FLAG_CONVERT_TO_PLAIN_TEXT})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Flags {}
+
+ /**
+ * Flag requesting that the content should be converted to plain text prior to inserting.
+ */
+ public static final int FLAG_CONVERT_TO_PLAIN_TEXT = 1 << 0;
+
+ /**
+ * Returns the symbolic names of the set flags or {@code "0"} if no flags are set.
+ *
+ * @hide
+ */
+ static String flagsToString(@Flags int flags) {
+ if ((flags & FLAG_CONVERT_TO_PLAIN_TEXT) != 0) {
+ return "FLAG_CONVERT_TO_PLAIN_TEXT";
+ }
+ return String.valueOf(flags);
+ }
+
+ @NonNull
+ private final ClipData mClip;
+ @Source
+ private final int mSource;
+ @Flags
+ private final int mFlags;
+ @Nullable
+ private final Uri mLinkUri;
+ @Nullable
+ private final Bundle mExtras;
+
+ private ContentInfo(Builder b) {
+ this.mClip = Objects.requireNonNull(b.mClip);
+ this.mSource = Preconditions.checkArgumentInRange(b.mSource, 0, SOURCE_PROCESS_TEXT,
+ "source");
+ this.mFlags = Preconditions.checkFlagsArgument(b.mFlags, FLAG_CONVERT_TO_PLAIN_TEXT);
+ this.mLinkUri = b.mLinkUri;
+ this.mExtras = b.mExtras;
+ }
+
+ @NonNull
+ @Override
+ public String toString() {
+ return "ContentInfo{"
+ + "clip=" + mClip
+ + ", source=" + sourceToString(mSource)
+ + ", flags=" + flagsToString(mFlags)
+ + ", linkUri=" + mLinkUri
+ + ", extras=" + mExtras
+ + "}";
+ }
+
+ /**
+ * The data to be inserted.
+ */
+ @NonNull
+ public ClipData getClip() {
+ return mClip;
+ }
+
+ /**
+ * The source of the operation. See {@code SOURCE_} constants. Future versions of Android
+ * may pass additional values.
+ */
+ @Source
+ public int getSource() {
+ return mSource;
+ }
+
+ /**
+ * Optional flags that control the insertion behavior. See {@code FLAG_} constants.
+ */
+ @Flags
+ public int getFlags() {
+ return mFlags;
+ }
+
+ /**
+ * Optional http/https URI for the content that may be provided by the IME. This is only
+ * populated if the source is {@link #SOURCE_INPUT_METHOD} and if a non-empty
+ * {@link android.view.inputmethod.InputContentInfo#getLinkUri linkUri} was passed by the
+ * IME.
+ */
+ @Nullable
+ public Uri getLinkUri() {
+ return mLinkUri;
+ }
+
+ /**
+ * Optional additional metadata. If the source is {@link #SOURCE_INPUT_METHOD}, this will
+ * include the {@link android.view.inputmethod.InputConnection#commitContent opts} passed by
+ * the IME.
+ */
+ @Nullable
+ public Bundle getExtras() {
+ return mExtras;
+ }
+
+ /**
+ * Partitions the content based on the given predicate.
+ *
+ * <p>Similar to a
+ * {@link java.util.stream.Collectors#partitioningBy(Predicate) partitioning collector},
+ * this function classifies the content and organizes it into a map, grouping the items that
+ * matched vs didn't match the predicate.
+ *
+ * <p>Except for the {@link ClipData} items, the returned objects will contain all the same
+ * metadata as the original.
+ *
+ * @param itemPredicate The predicate to test each {@link ClipData.Item} to determine which
+ * partition to place it into.
+ * @return A map containing the partitioned content. The map will contain a single entry if
+ * all items were classified into the same partition (all matched or all didn't match the
+ * predicate) or two entries (if there's at least one item that matched the predicate and at
+ * least one item that didn't match the predicate).
+ */
+ @NonNull
+ public Map<Boolean, ContentInfo> partition(@NonNull Predicate<ClipData.Item> itemPredicate) {
+ if (mClip.getItemCount() == 1) {
+ Map<Boolean, ContentInfo> result = new ArrayMap<>(1);
+ result.put(itemPredicate.test(mClip.getItemAt(0)), this);
+ return result;
+ }
+ ArrayList<ClipData.Item> accepted = new ArrayList<>();
+ ArrayList<ClipData.Item> remaining = new ArrayList<>();
+ for (int i = 0; i < mClip.getItemCount(); i++) {
+ ClipData.Item item = mClip.getItemAt(i);
+ if (itemPredicate.test(item)) {
+ accepted.add(item);
+ } else {
+ remaining.add(item);
+ }
+ }
+ Map<Boolean, ContentInfo> result = new ArrayMap<>(2);
+ if (!accepted.isEmpty()) {
+ ClipData acceptedClip = new ClipData(mClip.getDescription(), accepted);
+ result.put(true, new Builder(this).setClip(acceptedClip).build());
+ }
+ if (!remaining.isEmpty()) {
+ ClipData remainingClip = new ClipData(mClip.getDescription(), remaining);
+ result.put(false, new Builder(this).setClip(remainingClip).build());
+ }
+ return result;
+ }
+
+ /**
+ * Builder for {@link ContentInfo}.
+ */
+ public static final class Builder {
+ @NonNull
+ private ClipData mClip;
+ @Source
+ private int mSource;
+ @Flags
+ private int mFlags;
+ @Nullable
+ private Uri mLinkUri;
+ @Nullable
+ private Bundle mExtras;
+
+ /**
+ * Creates a new builder initialized with the data from the given builder.
+ */
+ public Builder(@NonNull ContentInfo other) {
+ mClip = other.mClip;
+ mSource = other.mSource;
+ mFlags = other.mFlags;
+ mLinkUri = other.mLinkUri;
+ mExtras = other.mExtras;
+ }
+
+ /**
+ * Creates a new builder.
+ * @param clip The data to insert.
+ * @param source The source of the operation. See {@code SOURCE_} constants.
+ */
+ public Builder(@NonNull ClipData clip, @Source int source) {
+ mClip = clip;
+ mSource = source;
+ }
+
+ /**
+ * Sets the data to be inserted.
+ * @param clip The data to insert.
+ * @return this builder
+ */
+ @NonNull
+ public Builder setClip(@NonNull ClipData clip) {
+ mClip = clip;
+ return this;
+ }
+
+ /**
+ * Sets the source of the operation.
+ * @param source The source of the operation. See {@code SOURCE_} constants.
+ * @return this builder
+ */
+ @NonNull
+ public Builder setSource(@Source int source) {
+ mSource = source;
+ return this;
+ }
+
+ /**
+ * Sets flags that control content insertion behavior.
+ * @param flags Optional flags to configure the insertion behavior. Use 0 for default
+ * behavior. See {@code FLAG_} constants.
+ * @return this builder
+ */
+ @NonNull
+ public Builder setFlags(@Flags int flags) {
+ mFlags = flags;
+ return this;
+ }
+
+ /**
+ * Sets the http/https URI for the content. See
+ * {@link android.view.inputmethod.InputContentInfo#getLinkUri} for more info.
+ * @param linkUri Optional http/https URI for the content.
+ * @return this builder
+ */
+ @NonNull
+ public Builder setLinkUri(@Nullable Uri linkUri) {
+ mLinkUri = linkUri;
+ return this;
+ }
+
+ /**
+ * Sets additional metadata.
+ * @param extras Optional bundle with additional metadata.
+ * @return this builder
+ */
+ @NonNull
+ public Builder setExtras(@Nullable Bundle extras) {
+ mExtras = extras;
+ return this;
+ }
+
+ /**
+ * @return A new {@link ContentInfo} instance with the data from this builder.
+ */
+ @NonNull
+ public ContentInfo build() {
+ return new ContentInfo(this);
+ }
+ }
+}
diff --git a/core/java/android/view/Gravity.java b/core/java/android/view/Gravity.java
index defa58e10e6e..c8bfd36b2b48 100644
--- a/core/java/android/view/Gravity.java
+++ b/core/java/android/view/Gravity.java
@@ -15,8 +15,13 @@
*/
package android.view;
+
+import android.annotation.IntDef;
import android.graphics.Rect;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
/**
* Standard constants and tools for placing an object within a potentially
* larger container.
@@ -122,6 +127,32 @@ public class Gravity
*/
public static final int RELATIVE_HORIZONTAL_GRAVITY_MASK = START | END;
+
+ /**
+ * @hide
+ */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(flag = true, value = {
+ Gravity.FILL,
+ Gravity.FILL_HORIZONTAL,
+ Gravity.FILL_VERTICAL,
+ Gravity.START,
+ Gravity.END,
+ Gravity.LEFT,
+ Gravity.RIGHT,
+ Gravity.TOP,
+ Gravity.BOTTOM,
+ Gravity.CENTER,
+ Gravity.CENTER_HORIZONTAL,
+ Gravity.CENTER_VERTICAL,
+ Gravity.DISPLAY_CLIP_HORIZONTAL,
+ Gravity.DISPLAY_CLIP_VERTICAL,
+ Gravity.CLIP_HORIZONTAL,
+ Gravity.CLIP_VERTICAL,
+ Gravity.NO_GRAVITY
+ })
+ public @interface GravityFlags {}
+
/**
* Apply a gravity constant to an object. This supposes that the layout direction is LTR.
*
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 1a6eea554cae..a23b7e193024 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -32,6 +32,7 @@ import android.graphics.Region;
import android.os.Bundle;
import android.os.IRemoteCallback;
import android.os.ParcelFileDescriptor;
+import android.service.attestation.ImpressionToken;
import android.view.DisplayCutout;
import android.view.IApplicationToken;
import android.view.IAppTransitionAnimationSpecsFuture;
@@ -760,4 +761,23 @@ interface IWindowManager
* {@link android.content.pm.PackageManager#getHoldLockToken()}.
*/
void holdLock(in IBinder token, in int durationMs);
+
+ /**
+ * Gets an array of support hashing algorithms that can be used to generate the hash of the
+ * screenshot. The String value of one algorithm should be used when requesting to generate
+ * the impression attestation token.
+ *
+ * @return a String array of supported hashing algorithms.
+ */
+ String[] getSupportedImpressionAlgorithms();
+
+ /**
+ * Validate the impression token was generated by the system. The impression token passed in
+ * should be the token generated when calling {@link IWindowSession#generateImpressionToken}
+ *
+ * @param impressionToken The token to verify that it was generated by the system.
+ * @return true if the token was generated by the system or false if the token cannot be
+ * verified.
+ */
+ boolean verifyImpressionToken(in ImpressionToken impressionToken);
}
diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl
index 0089a852a893..cfdaf8ccc5fb 100644
--- a/core/java/android/view/IWindowSession.aidl
+++ b/core/java/android/view/IWindowSession.aidl
@@ -22,6 +22,7 @@ import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.Region;
import android.os.Bundle;
+import android.service.attestation.ImpressionToken;
import android.util.MergedConfiguration;
import android.view.DisplayCutout;
import android.view.InputChannel;
@@ -344,4 +345,16 @@ interface IWindowSession {
* window, the system will try to find a new focus target.
*/
void grantEmbeddedWindowFocus(IWindow window, in IBinder inputToken, boolean grantFocus);
+
+ /**
+ * Generates an impression token that can be used to validate whether specific content was on
+ * screen.
+ *
+ * @param window The token for the window where the view to attest is shown.
+ * @param boundsInWindow The size and position of the ads view in the window
+ * @param hashAlgorithm The String for the hashing algorithm to use based on values returned
+ * from {@link IWindowManager#getSupportedImpressionAlgorithms()}
+ */
+ ImpressionToken generateImpressionToken(IWindow window, in Rect boundsInWindow,
+ in String hashAlgorithm);
}
diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java
index 1c82619a61ad..c4f32c433598 100644
--- a/core/java/android/view/InsetsController.java
+++ b/core/java/android/view/InsetsController.java
@@ -829,7 +829,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
}
if (fromIme) {
ImeTracing.getInstance().triggerClientDump("InsetsController#show",
- mHost.getInputMethodManager());
+ mHost.getInputMethodManager(), null /* icProto */);
Trace.asyncTraceEnd(TRACE_TAG_VIEW, "IC.showRequestFromApiToImeReady", 0);
Trace.asyncTraceBegin(TRACE_TAG_VIEW, "IC.showRequestFromIme", 0);
} else {
@@ -886,7 +886,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
void hide(@InsetsType int types, boolean fromIme) {
if (fromIme) {
ImeTracing.getInstance().triggerClientDump("InsetsController#hide",
- mHost.getInputMethodManager());
+ mHost.getInputMethodManager(), null /* icProto */);
Trace.asyncTraceBegin(TRACE_TAG_VIEW, "IC.hideRequestFromIme", 0);
} else {
Trace.asyncTraceBegin(TRACE_TAG_VIEW, "IC.hideRequestFromApi", 0);
@@ -928,7 +928,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
if (fromIme) {
ImeTracing.getInstance().triggerClientDump(
"InsetsController#controlWindowInsetsAnimation",
- mHost.getInputMethodManager());
+ mHost.getInputMethodManager(), null /* icProto */);
}
controlAnimationUnchecked(types, cancellationSignal, listener, mFrame, fromIme, durationMs,
@@ -1022,7 +1022,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
animationType, mHost.getTranslator());
if ((typesReady & WindowInsets.Type.ime()) != 0) {
ImeTracing.getInstance().triggerClientDump("InsetsAnimationControlImpl",
- mHost.getInputMethodManager());
+ mHost.getInputMethodManager(), null /* icProto */);
}
mRunningAnimations.add(new RunningAnimation(runner, animationType));
if (DEBUG) Log.d(TAG, "Animation added to runner. useInsetsAnimationThread: "
@@ -1200,7 +1200,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
if (types.valueAt(j) == ITYPE_IME) {
ImeTracing.getInstance().triggerClientDump(
"InsetsSourceConsumer#notifyAnimationFinished",
- mHost.getInputMethodManager());
+ mHost.getInputMethodManager(), null /* icProto */);
}
stateChanged |= getSourceConsumer(types.valueAt(j)).notifyAnimationFinished();
}
@@ -1345,7 +1345,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
boolean fromIme) {
if ((types & ime()) != 0) {
ImeTracing.getInstance().triggerClientDump("InsetsController#hideDirectly",
- mHost.getInputMethodManager());
+ mHost.getInputMethodManager(), null /* icProto */);
}
final ArraySet<Integer> internalTypes = InsetsState.toInternalType(types);
for (int i = internalTypes.size() - 1; i >= 0; i--) {
@@ -1361,7 +1361,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
private void showDirectly(@InsetsType int types, boolean fromIme) {
if ((types & ime()) != 0) {
ImeTracing.getInstance().triggerClientDump("InsetsController#showDirectly",
- mHost.getInputMethodManager());
+ mHost.getInputMethodManager(), null /* icProto */);
}
final ArraySet<Integer> internalTypes = InsetsState.toInternalType(types);
for (int i = internalTypes.size() - 1; i >= 0; i--) {
diff --git a/core/java/android/view/OnReceiveContentListener.java b/core/java/android/view/OnReceiveContentListener.java
index db9c53863c7f..b551fa80b5cd 100644
--- a/core/java/android/view/OnReceiveContentListener.java
+++ b/core/java/android/view/OnReceiveContentListener.java
@@ -16,22 +16,8 @@
package android.view;
-import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.content.ClipData;
-import android.net.Uri;
-import android.os.Bundle;
-import android.util.ArrayMap;
-
-import com.android.internal.util.Preconditions;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.ArrayList;
-import java.util.Map;
-import java.util.Objects;
-import java.util.function.Predicate;
/**
* Listener for apps to implement handling for insertion of content. Content may be both text and
@@ -48,10 +34,13 @@ import java.util.function.Predicate;
* public static final String[] MIME_TYPES = new String[] {"image/*", "video/*"};
*
* &#64;Override
- * public Payload onReceiveContent(View view, Payload payload) {
- * Map&lt;Boolean, Payload&gt; split = payload.partition(item -&gt; item.getUri() != null);
- * if (split.get(true) != null) {
- * ClipData clip = payload.getClip();
+ * public ContentInfo onReceiveContent(View view, ContentInfo payload) {
+ * Map&lt;Boolean, ContentInfo&gt; split =
+ * payload.partition(item -&gt; item.getUri() != null);
+ * ContentInfo uriItems = split.get(true);
+ * ContentInfo remainingItems = split.get(false);
+ * if (uriItems != null) {
+ * ClipData clip = uriItems.getClip();
* for (int i = 0; i < clip.getItemCount(); i++) {
* Uri uri = clip.getItemAt(i).getUri();
* // ... app-specific logic to handle the URI ...
@@ -59,7 +48,7 @@ import java.util.function.Predicate;
* }
* // Return anything that we didn't handle ourselves. This preserves the default platform
* // behavior for text and anything else for which we are not implementing custom handling.
- * return split.get(false);
+ * return remainingItems;
* }
* }
*
@@ -83,8 +72,8 @@ public interface OnReceiveContentListener {
* handling. For example, an implementation may provide handling for content URIs (to provide
* support for inserting images, etc) and delegate the processing of text to the platform to
* preserve the common behavior for inserting text. See the class javadoc for a sample
- * implementation and see {@link Payload#partition} for a convenient way to split the passed-in
- * content.
+ * implementation and see {@link ContentInfo#partition} for a convenient way to split the
+ * passed-in content.
*
* <p>If implementing handling for text: if the view has a selection, the selection should
* be overwritten by the passed-in content; if there's no selection, the passed-in content
@@ -103,314 +92,6 @@ public interface OnReceiveContentListener {
* succeed even if this method returns null. For example, an app may end up not inserting
* an item if it exceeds the app's size limit for that type of content.
*/
- @Nullable Payload onReceiveContent(@NonNull View view, @NonNull Payload payload);
-
- /**
- * Holds all the relevant data for a request to {@link OnReceiveContentListener}.
- */
- final class Payload {
-
- /**
- * Specifies the UI through which content is being inserted. Future versions of Android may
- * support additional values.
- *
- * @hide
- */
- @IntDef(prefix = {"SOURCE_"}, value = {SOURCE_APP, SOURCE_CLIPBOARD, SOURCE_INPUT_METHOD,
- SOURCE_DRAG_AND_DROP, SOURCE_AUTOFILL, SOURCE_PROCESS_TEXT})
- @Retention(RetentionPolicy.SOURCE)
- public @interface Source {}
-
- /**
- * Specifies that the operation was triggered by the app that contains the target view.
- */
- public static final int SOURCE_APP = 0;
-
- /**
- * Specifies that the operation was triggered by a paste from the clipboard (e.g. "Paste" or
- * "Paste as plain text" action in the insertion/selection menu).
- */
- public static final int SOURCE_CLIPBOARD = 1;
-
- /**
- * Specifies that the operation was triggered from the soft keyboard (also known as input
- * method editor or IME). See https://developer.android.com/guide/topics/text/image-keyboard
- * for more info.
- */
- public static final int SOURCE_INPUT_METHOD = 2;
-
- /**
- * Specifies that the operation was triggered by the drag/drop framework. See
- * https://developer.android.com/guide/topics/ui/drag-drop for more info.
- */
- public static final int SOURCE_DRAG_AND_DROP = 3;
-
- /**
- * Specifies that the operation was triggered by the autofill framework. See
- * https://developer.android.com/guide/topics/text/autofill for more info.
- */
- public static final int SOURCE_AUTOFILL = 4;
-
- /**
- * Specifies that the operation was triggered by a result from a
- * {@link android.content.Intent#ACTION_PROCESS_TEXT PROCESS_TEXT} action in the selection
- * menu.
- */
- public static final int SOURCE_PROCESS_TEXT = 5;
-
- /**
- * Returns the symbolic name of the given source.
- *
- * @hide
- */
- static String sourceToString(@Source int source) {
- switch (source) {
- case SOURCE_APP: return "SOURCE_APP";
- case SOURCE_CLIPBOARD: return "SOURCE_CLIPBOARD";
- case SOURCE_INPUT_METHOD: return "SOURCE_INPUT_METHOD";
- case SOURCE_DRAG_AND_DROP: return "SOURCE_DRAG_AND_DROP";
- case SOURCE_AUTOFILL: return "SOURCE_AUTOFILL";
- case SOURCE_PROCESS_TEXT: return "SOURCE_PROCESS_TEXT";
- }
- return String.valueOf(source);
- }
-
- /**
- * Flags to configure the insertion behavior.
- *
- * @hide
- */
- @IntDef(flag = true, prefix = {"FLAG_"}, value = {FLAG_CONVERT_TO_PLAIN_TEXT})
- @Retention(RetentionPolicy.SOURCE)
- public @interface Flags {}
-
- /**
- * Flag requesting that the content should be converted to plain text prior to inserting.
- */
- public static final int FLAG_CONVERT_TO_PLAIN_TEXT = 1 << 0;
-
- /**
- * Returns the symbolic names of the set flags or {@code "0"} if no flags are set.
- *
- * @hide
- */
- static String flagsToString(@Flags int flags) {
- if ((flags & FLAG_CONVERT_TO_PLAIN_TEXT) != 0) {
- return "FLAG_CONVERT_TO_PLAIN_TEXT";
- }
- return String.valueOf(flags);
- }
-
- @NonNull private final ClipData mClip;
- private final @Source int mSource;
- private final @Flags int mFlags;
- @Nullable private final Uri mLinkUri;
- @Nullable private final Bundle mExtras;
-
- private Payload(Builder b) {
- this.mClip = Objects.requireNonNull(b.mClip);
- this.mSource = Preconditions.checkArgumentInRange(b.mSource, 0, SOURCE_PROCESS_TEXT,
- "source");
- this.mFlags = Preconditions.checkFlagsArgument(b.mFlags, FLAG_CONVERT_TO_PLAIN_TEXT);
- this.mLinkUri = b.mLinkUri;
- this.mExtras = b.mExtras;
- }
-
- @NonNull
- @Override
- public String toString() {
- return "Payload{"
- + "clip=" + mClip
- + ", source=" + sourceToString(mSource)
- + ", flags=" + flagsToString(mFlags)
- + ", linkUri=" + mLinkUri
- + ", extras=" + mExtras
- + "}";
- }
-
- /**
- * The data to be inserted.
- */
- public @NonNull ClipData getClip() {
- return mClip;
- }
-
- /**
- * The source of the operation. See {@code SOURCE_} constants. Future versions of Android
- * may pass additional values.
- */
- public @Source int getSource() {
- return mSource;
- }
-
- /**
- * Optional flags that control the insertion behavior. See {@code FLAG_} constants.
- */
- public @Flags int getFlags() {
- return mFlags;
- }
-
- /**
- * Optional http/https URI for the content that may be provided by the IME. This is only
- * populated if the source is {@link #SOURCE_INPUT_METHOD} and if a non-empty
- * {@link android.view.inputmethod.InputContentInfo#getLinkUri linkUri} was passed by the
- * IME.
- */
- public @Nullable Uri getLinkUri() {
- return mLinkUri;
- }
-
- /**
- * Optional additional metadata. If the source is {@link #SOURCE_INPUT_METHOD}, this will
- * include the {@link android.view.inputmethod.InputConnection#commitContent opts} passed by
- * the IME.
- */
- public @Nullable Bundle getExtras() {
- return mExtras;
- }
-
- /**
- * Partitions this payload based on the given predicate.
- *
- * <p>Similar to a
- * {@link java.util.stream.Collectors#partitioningBy(Predicate) partitioning collector},
- * this function classifies the content in this payload and organizes it into a map,
- * grouping the content that matched vs didn't match the predicate.
- *
- * <p>Except for the {@link ClipData} items, the returned payloads will contain all the same
- * metadata as the original payload.
- *
- * @param itemPredicate The predicate to test each {@link ClipData.Item} to determine which
- * partition to place it into.
- * @return A map containing the partitioned content. The map will contain a single entry if
- * all items were classified into the same partition (all matched or all didn't match the
- * predicate) or two entries (if there's at least one item that matched the predicate and at
- * least one item that didn't match the predicate).
- */
- public @NonNull Map<Boolean, Payload> partition(
- @NonNull Predicate<ClipData.Item> itemPredicate) {
- if (mClip.getItemCount() == 1) {
- Map<Boolean, Payload> result = new ArrayMap<>(1);
- result.put(itemPredicate.test(mClip.getItemAt(0)), this);
- return result;
- }
- ArrayList<ClipData.Item> accepted = new ArrayList<>();
- ArrayList<ClipData.Item> remaining = new ArrayList<>();
- for (int i = 0; i < mClip.getItemCount(); i++) {
- ClipData.Item item = mClip.getItemAt(i);
- if (itemPredicate.test(item)) {
- accepted.add(item);
- } else {
- remaining.add(item);
- }
- }
- Map<Boolean, Payload> result = new ArrayMap<>(2);
- if (!accepted.isEmpty()) {
- ClipData acceptedClip = new ClipData(mClip.getDescription(), accepted);
- result.put(true, new Builder(this).setClip(acceptedClip).build());
- }
- if (!remaining.isEmpty()) {
- ClipData remainingClip = new ClipData(mClip.getDescription(), remaining);
- result.put(false, new Builder(this).setClip(remainingClip).build());
- }
- return result;
- }
-
- /**
- * Builder for {@link Payload}.
- */
- public static final class Builder {
- @NonNull private ClipData mClip;
- private @Source int mSource;
- private @Flags int mFlags;
- @Nullable private Uri mLinkUri;
- @Nullable private Bundle mExtras;
-
- /**
- * Creates a new builder initialized with the data from the given builder.
- */
- public Builder(@NonNull Payload payload) {
- mClip = payload.mClip;
- mSource = payload.mSource;
- mFlags = payload.mFlags;
- mLinkUri = payload.mLinkUri;
- mExtras = payload.mExtras;
- }
-
- /**
- * Creates a new builder.
- * @param clip The data to insert.
- * @param source The source of the operation. See {@code SOURCE_} constants.
- */
- public Builder(@NonNull ClipData clip, @Source int source) {
- mClip = clip;
- mSource = source;
- }
-
- /**
- * Sets the data to be inserted.
- * @param clip The data to insert.
- * @return this builder
- */
- @NonNull
- public Builder setClip(@NonNull ClipData clip) {
- mClip = clip;
- return this;
- }
-
- /**
- * Sets the source of the operation.
- * @param source The source of the operation. See {@code SOURCE_} constants.
- * @return this builder
- */
- @NonNull
- public Builder setSource(@Source int source) {
- mSource = source;
- return this;
- }
-
- /**
- * Sets flags that control content insertion behavior.
- * @param flags Optional flags to configure the insertion behavior. Use 0 for default
- * behavior. See {@code FLAG_} constants.
- * @return this builder
- */
- @NonNull
- public Builder setFlags(@Flags int flags) {
- mFlags = flags;
- return this;
- }
-
- /**
- * Sets the http/https URI for the content. See
- * {@link android.view.inputmethod.InputContentInfo#getLinkUri} for more info.
- * @param linkUri Optional http/https URI for the content.
- * @return this builder
- */
- @NonNull
- public Builder setLinkUri(@Nullable Uri linkUri) {
- mLinkUri = linkUri;
- return this;
- }
-
- /**
- * Sets additional metadata.
- * @param extras Optional bundle with additional metadata.
- * @return this builder
- */
- @NonNull
- public Builder setExtras(@Nullable Bundle extras) {
- mExtras = extras;
- return this;
- }
-
- /**
- * @return A new {@link Payload} instance with the data from this builder.
- */
- @NonNull
- public Payload build() {
- return new Payload(this);
- }
- }
- }
+ @Nullable
+ ContentInfo onReceiveContent(@NonNull View view, @NonNull ContentInfo payload);
}
diff --git a/core/java/android/view/TEST_MAPPING b/core/java/android/view/TEST_MAPPING
index 4ea4310b25a4..c8b746f2248f 100644
--- a/core/java/android/view/TEST_MAPPING
+++ b/core/java/android/view/TEST_MAPPING
@@ -2,6 +2,24 @@
"presubmit": [
{
"name": "CtsAccelerationTestCases"
+ },
+ {
+ "name": "CtsOsTestCases",
+ "options": [
+ {
+ "include-annotation": "android.platform.test.annotations.Presubmit"
+ },
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ },
+ {
+ "exclude-annotation": "org.junit.Ignore"
+ },
+ {
+ "include-filter": "android.os.cts.StrictModeTest"
+ }
+ ],
+ "file_patterns": ["(/|^)ViewConfiguration.java", "(/|^)GestureDetector.java"]
}
],
"imports": [
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 30ec2b050dbe..a5c66537b11f 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -112,7 +112,6 @@ import android.view.AccessibilityIterators.TextSegmentIterator;
import android.view.AccessibilityIterators.WordTextSegmentIterator;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.InputDevice.InputSourceClass;
-import android.view.OnReceiveContentListener.Payload;
import android.view.Window.OnContentApplyWindowInsetsListener;
import android.view.WindowInsets.Type;
import android.view.WindowInsetsAnimation.Bounds;
@@ -9063,11 +9062,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @return The portion of the passed-in content that was not accepted (may be all, some, or none
* of the passed-in content).
*/
- public @Nullable Payload performReceiveContent(@NonNull Payload payload) {
+ @Nullable
+ public ContentInfo performReceiveContent(@NonNull ContentInfo payload) {
final OnReceiveContentListener listener = (mListenerInfo == null) ? null
: getListenerInfo().mOnReceiveContentListener;
if (listener != null) {
- final Payload remaining = listener.onReceiveContent(this, payload);
+ final ContentInfo remaining = listener.onReceiveContent(this, payload);
return (remaining == null) ? null : onReceiveContent(remaining);
}
return onReceiveContent(payload);
@@ -9088,7 +9088,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @return The portion of the passed-in content that was not handled (may be all, some, or none
* of the passed-in content).
*/
- public @Nullable Payload onReceiveContent(@NonNull Payload payload) {
+ @Nullable
+ public ContentInfo onReceiveContent(@NonNull ContentInfo payload) {
return payload;
}
@@ -9113,7 +9114,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @return The MIME types accepted by {@link #performReceiveContent} for this view (may
* include patterns such as "image/*").
*/
- public @Nullable String[] getOnReceiveContentMimeTypes() {
+ @Nullable
+ public String[] getOnReceiveContentMimeTypes() {
return mOnReceiveContentMimeTypes;
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 2bea0d6b4b04..8321f2b28771 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -9225,7 +9225,8 @@ public final class ViewRootImpl implements ViewParent,
final ViewRootImpl viewAncestor = mViewAncestor.get();
if (fromIme) {
ImeTracing.getInstance().triggerClientDump("ViewRootImpl.W#showInsets",
- viewAncestor.getInsetsController().getHost().getInputMethodManager());
+ viewAncestor.getInsetsController().getHost().getInputMethodManager(),
+ null /* icProto */);
}
if (viewAncestor != null) {
viewAncestor.showInsets(types, fromIme);
@@ -9238,7 +9239,8 @@ public final class ViewRootImpl implements ViewParent,
final ViewRootImpl viewAncestor = mViewAncestor.get();
if (fromIme) {
ImeTracing.getInstance().triggerClientDump("ViewRootImpl.W#hideInsets",
- viewAncestor.getInsetsController().getHost().getInputMethodManager());
+ viewAncestor.getInsetsController().getHost().getInputMethodManager(),
+ null /* icProto */);
}
if (viewAncestor != null) {
viewAncestor.hideInsets(types, fromIme);
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 8c8ea00ef41f..b9afbc95de0d 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -104,6 +104,7 @@ import android.os.Parcelable;
import android.text.TextUtils;
import android.util.Log;
import android.util.proto.ProtoOutputStream;
+import android.view.Gravity.GravityFlags;
import android.view.View.OnApplyWindowInsetsListener;
import android.view.WindowInsets.Side;
import android.view.WindowInsets.Side.InsetsSide;
@@ -2157,15 +2158,6 @@ public interface WindowManager extends ViewManager {
public static final int PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY = 0x00100000;
/**
- * Flag to indicate that this window should be considered a screen decoration similar to the
- * nav bar and status bar. This will cause this window to affect the window insets reported
- * to other windows when it is visible.
- * @hide
- */
- @RequiresPermission(permission.STATUS_BAR_SERVICE)
- public static final int PRIVATE_FLAG_IS_SCREEN_DECOR = 0x00400000;
-
- /**
* Flag to indicate that the status bar window is in a state such that it forces showing
* the navigation bar unless the navigation bar window is explicitly set to
* {@link View#GONE}.
@@ -2270,7 +2262,6 @@ public interface WindowManager extends ViewManager {
PRIVATE_FLAG_SUSTAINED_PERFORMANCE_MODE,
SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS,
PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY,
- PRIVATE_FLAG_IS_SCREEN_DECOR,
PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION,
PRIVATE_FLAG_COLOR_SPACE_AGNOSTIC,
PRIVATE_FLAG_USE_BLAST,
@@ -2358,10 +2349,6 @@ public interface WindowManager extends ViewManager {
equals = PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY,
name = "IS_ROUNDED_CORNERS_OVERLAY"),
@ViewDebug.FlagToString(
- mask = PRIVATE_FLAG_IS_SCREEN_DECOR,
- equals = PRIVATE_FLAG_IS_SCREEN_DECOR,
- name = "IS_SCREEN_DECOR"),
- @ViewDebug.FlagToString(
mask = PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION,
equals = PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION,
name = "STATUS_FORCE_SHOW_NAVIGATION"),
@@ -2586,6 +2573,7 @@ public interface WindowManager extends ViewManager {
*
* @see Gravity
*/
+ @GravityFlags
public int gravity;
/**
diff --git a/core/java/android/view/WindowlessWindowManager.java b/core/java/android/view/WindowlessWindowManager.java
index 0ed7ca79113e..673073ea197d 100644
--- a/core/java/android/view/WindowlessWindowManager.java
+++ b/core/java/android/view/WindowlessWindowManager.java
@@ -24,6 +24,7 @@ import android.graphics.Rect;
import android.graphics.Region;
import android.os.IBinder;
import android.os.RemoteException;
+import android.service.attestation.ImpressionToken;
import android.util.Log;
import android.util.MergedConfiguration;
import android.window.ClientWindowFrames;
@@ -460,4 +461,10 @@ public class WindowlessWindowManager implements IWindowSession {
public void grantEmbeddedWindowFocus(IWindow callingWindow, IBinder targetInputToken,
boolean grantFocus) {
}
+
+ @Override
+ public ImpressionToken generateImpressionToken(IWindow window, Rect boundsInWindow,
+ String hashAlgorithm) {
+ return null;
+ }
}
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index 8fdcac7b4f9d..364ae8186e54 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -19,7 +19,7 @@ package android.view.autofill;
import static android.service.autofill.FillRequest.FLAG_MANUAL_REQUEST;
import static android.service.autofill.FillRequest.FLAG_PASSWORD_INPUT_TYPE;
import static android.service.autofill.FillRequest.FLAG_VIEW_NOT_FOCUSED;
-import static android.view.OnReceiveContentListener.Payload.SOURCE_AUTOFILL;
+import static android.view.ContentInfo.SOURCE_AUTOFILL;
import static android.view.autofill.Helper.sDebug;
import static android.view.autofill.Helper.sVerbose;
import static android.view.autofill.Helper.toList;
@@ -61,8 +61,8 @@ import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
import android.view.Choreographer;
+import android.view.ContentInfo;
import android.view.KeyEvent;
-import android.view.OnReceiveContentListener.Payload;
import android.view.View;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
@@ -2371,8 +2371,8 @@ public final class AutofillManager {
reportAutofillContentFailure(id);
return;
}
- Payload payload = new Payload.Builder(clip, SOURCE_AUTOFILL).build();
- Payload result = view.performReceiveContent(payload);
+ ContentInfo payload = new ContentInfo.Builder(clip, SOURCE_AUTOFILL).build();
+ ContentInfo result = view.performReceiveContent(payload);
if (result != null) {
Log.w(TAG, "autofillContent(): receiver could not insert content: id=" + id
+ ", view=" + view + ", clip=" + clip);
diff --git a/core/java/android/view/autofill/TEST_MAPPING b/core/java/android/view/autofill/TEST_MAPPING
new file mode 100644
index 000000000000..87a17ebee36d
--- /dev/null
+++ b/core/java/android/view/autofill/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "imports": [
+ {
+ "path": "frameworks/base/services/autofill/java/com/android/server/autofill"
+ }
+ ]
+}
diff --git a/core/java/android/view/inputmethod/BaseInputConnection.java b/core/java/android/view/inputmethod/BaseInputConnection.java
index 1ab9edf0caa2..f057c1239e52 100644
--- a/core/java/android/view/inputmethod/BaseInputConnection.java
+++ b/core/java/android/view/inputmethod/BaseInputConnection.java
@@ -16,7 +16,7 @@
package android.view.inputmethod;
-import static android.view.OnReceiveContentListener.Payload.SOURCE_INPUT_METHOD;
+import static android.view.ContentInfo.SOURCE_INPUT_METHOD;
import android.annotation.CallSuper;
import android.annotation.IntRange;
@@ -38,9 +38,9 @@ import android.text.TextUtils;
import android.text.method.MetaKeyKeyListener;
import android.util.Log;
import android.util.LogPrinter;
+import android.view.ContentInfo;
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
-import android.view.OnReceiveContentListener;
import android.view.View;
import com.android.internal.util.Preconditions;
@@ -952,8 +952,8 @@ public class BaseInputConnection implements InputConnection {
}
final ClipData clip = new ClipData(inputContentInfo.getDescription(),
new ClipData.Item(inputContentInfo.getContentUri()));
- final OnReceiveContentListener.Payload payload =
- new OnReceiveContentListener.Payload.Builder(clip, SOURCE_INPUT_METHOD)
+ final ContentInfo payload =
+ new ContentInfo.Builder(clip, SOURCE_INPUT_METHOD)
.setLinkUri(inputContentInfo.getLinkUri())
.setExtras(opts)
.build();
diff --git a/core/java/android/view/inputmethod/DumpableInputConnection.java b/core/java/android/view/inputmethod/DumpableInputConnection.java
new file mode 100644
index 000000000000..9819a5734491
--- /dev/null
+++ b/core/java/android/view/inputmethod/DumpableInputConnection.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.inputmethod;
+
+import android.annotation.NonNull;
+import android.util.proto.ProtoOutputStream;
+
+/** @hide */
+public interface DumpableInputConnection {
+
+ /**
+ * Method used to dump state of InputConnection implementations of interest.
+ *
+ * @param proto Stream to write the state to
+ * @param fieldId FieldId of DumpableInputConnection as defined in the parent message
+ */
+ void dumpDebug(@NonNull ProtoOutputStream proto, long fieldId);
+}
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 315d4461692c..907b5b085b59 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -22,6 +22,8 @@ import static android.util.imetracing.ImeTracing.PROTO_ARG;
import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodClientsTraceProto.ClientSideProto.DISPLAY_ID;
import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodClientsTraceProto.ClientSideProto.EDITOR_INFO;
import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodClientsTraceProto.ClientSideProto.IME_INSETS_SOURCE_CONSUMER;
+import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodClientsTraceProto.ClientSideProto.INPUT_CONNECTION;
+import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodClientsTraceProto.ClientSideProto.INPUT_CONNECTION_CALL;
import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodClientsTraceProto.ClientSideProto.INPUT_METHOD_MANAGER;
import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodClientsTraceProto.ClientSideProto.VIEW_ROOT_IMPL;
import static android.view.inputmethod.InputMethodManagerProto.ACTIVE;
@@ -87,8 +89,10 @@ import android.view.WindowManager.LayoutParams.SoftInputModeFlags;
import android.view.autofill.AutofillManager;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.inputmethod.Completable;
import com.android.internal.inputmethod.InputMethodDebug;
import com.android.internal.inputmethod.InputMethodPrivilegedOperationsRegistry;
+import com.android.internal.inputmethod.ResultCallbacks;
import com.android.internal.inputmethod.StartInputFlags;
import com.android.internal.inputmethod.StartInputReason;
import com.android.internal.inputmethod.UnbindReason;
@@ -576,7 +580,8 @@ public final class InputMethodManager {
int windowFlags) {
final View servedView;
ImeTracing.getInstance().triggerClientDump(
- "InputMethodManager.DelegateImpl#startInput", InputMethodManager.this);
+ "InputMethodManager.DelegateImpl#startInput", InputMethodManager.this,
+ null /* icProto */);
synchronized (mH) {
mCurrentTextBoxAttribute = null;
mCompletions = null;
@@ -665,6 +670,7 @@ public final class InputMethodManager {
final int startInputReason =
nextFocusHasConnection ? WINDOW_FOCUS_GAIN_REPORT_WITH_CONNECTION
: WINDOW_FOCUS_GAIN_REPORT_WITHOUT_CONNECTION;
+ final Completable.InputBindResult value = Completable.createInputBindResult();
mService.startInputOrWindowGainedFocus(
startInputReason, mClient,
focusedView.getWindowToken(), startInputFlags, softInputMode,
@@ -672,7 +678,9 @@ public final class InputMethodManager {
null,
null,
0 /* missingMethodFlags */,
- mCurRootView.mContext.getApplicationInfo().targetSdkVersion);
+ mCurRootView.mContext.getApplicationInfo().targetSdkVersion,
+ ResultCallbacks.of(value));
+ Completable.getResult(value); // ignore the result
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -998,9 +1006,9 @@ public final class InputMethodManager {
private final InputMethodManager mParentInputMethodManager;
private final WeakReference<View> mServedView;
- ControlledInputConnectionWrapper(Looper mainLooper, InputConnection conn,
+ ControlledInputConnectionWrapper(Looper icLooper, InputConnection conn,
InputMethodManager inputMethodManager, View servedView) {
- super(mainLooper, conn);
+ super(icLooper, conn);
mParentInputMethodManager = inputMethodManager;
mServedView = new WeakReference<>(servedView);
}
@@ -1010,6 +1018,11 @@ public final class InputMethodManager {
return mParentInputMethodManager.mActive && !isFinished();
}
+ @Override
+ public InputMethodManager getIMM() {
+ return mParentInputMethodManager;
+ }
+
void deactivate() {
if (isFinished()) {
// This is a small performance optimization. Still only the 1st call of
@@ -1046,6 +1059,18 @@ public final class InputMethodManager {
+ " mServedView=" + mServedView.get()
+ "}";
}
+
+ void dumpDebug(ProtoOutputStream proto, long fieldId) {
+ // Check that the call is initiated in the main thread of the current InputConnection
+ // {@link InputConnection#getHandler} since the messages to IInputConnectionWrapper are
+ // executed on this thread. Otherwise the messages are dispatched to the correct thread
+ // in IInputConnectionWrapper, but this is not wanted while dumpng, for performance
+ // reasons.
+ if (getInputConnection() instanceof DumpableInputConnection && Looper.myLooper()
+ == getLooper()) {
+ ((DumpableInputConnection) getInputConnection()).dumpDebug(proto, fieldId);
+ }
+ }
}
private static class ImeThreadFactory implements ThreadFactory {
@@ -1695,7 +1720,8 @@ public final class InputMethodManager {
* {@link #RESULT_HIDDEN}.
*/
public boolean showSoftInput(View view, int flags, ResultReceiver resultReceiver) {
- ImeTracing.getInstance().triggerClientDump("InputMethodManager#showSoftInput", this);
+ ImeTracing.getInstance().triggerClientDump("InputMethodManager#showSoftInput", this,
+ null /* icProto */);
// Re-dispatch if there is a context mismatch.
final InputMethodManager fallbackImm = getFallbackInputMethodManagerIfNecessary(view);
if (fallbackImm != null) {
@@ -1804,7 +1830,7 @@ public final class InputMethodManager {
public boolean hideSoftInputFromWindow(IBinder windowToken, int flags,
ResultReceiver resultReceiver) {
ImeTracing.getInstance().triggerClientDump("InputMethodManager#hideSoftInputFromWindow",
- this);
+ this, null /* icProto */);
checkFocus();
synchronized (mH) {
final View servedView = getServedViewLocked();
@@ -2026,10 +2052,13 @@ public final class InputMethodManager {
if (DEBUG) Log.v(TAG, "START INPUT: view=" + dumpViewInfo(view) + " ic="
+ ic + " tba=" + tba + " startInputFlags="
+ InputMethodDebug.startInputFlagsToString(startInputFlags));
- res = mService.startInputOrWindowGainedFocus(
+ final Completable.InputBindResult value = Completable.createInputBindResult();
+ mService.startInputOrWindowGainedFocus(
startInputReason, mClient, windowGainingFocus, startInputFlags,
softInputMode, windowFlags, tba, servedContext, missingMethodFlags,
- view.getContext().getApplicationInfo().targetSdkVersion);
+ view.getContext().getApplicationInfo().targetSdkVersion,
+ ResultCallbacks.of(value));
+ res = Completable.getResult(value);
if (DEBUG) Log.v(TAG, "Starting input: Bind result=" + res);
if (res == null) {
Log.wtf(TAG, "startInputOrWindowGainedFocus must not return"
@@ -2207,6 +2236,8 @@ public final class InputMethodManager {
* @hide
*/
public void notifyImeHidden(IBinder windowToken) {
+ ImeTracing.getInstance().triggerClientDump("InputMethodManager#notifyImeHidden", this,
+ null /* icProto */);
synchronized (mH) {
try {
if (mCurMethod != null && mCurRootView != null
@@ -3274,7 +3305,7 @@ public final class InputMethodManager {
for (String arg : args) {
if (arg.equals(PROTO_ARG)) {
final ProtoOutputStream proto = new ProtoOutputStream(fd);
- dumpDebug(proto);
+ dumpDebug(proto, null /* icProto */);
proto.flush();
return true;
}
@@ -3287,10 +3318,11 @@ public final class InputMethodManager {
* {@link ProtoOutputStream}.
*
* @param proto The proto stream to which the dumps are written.
+ * @param icProto {@link InputConnection} call data in proto format.
* @hide
*/
@GuardedBy("mH")
- public void dumpDebug(ProtoOutputStream proto) {
+ public void dumpDebug(ProtoOutputStream proto, ProtoOutputStream icProto) {
if (mCurMethod == null) {
return;
}
@@ -3312,6 +3344,12 @@ public final class InputMethodManager {
if (mImeInsetsConsumer != null) {
mImeInsetsConsumer.dumpDebug(proto, IME_INSETS_SOURCE_CONSUMER);
}
+ if (mServedInputConnectionWrapper != null) {
+ mServedInputConnectionWrapper.dumpDebug(proto, INPUT_CONNECTION);
+ }
+ if (icProto != null) {
+ proto.write(INPUT_CONNECTION_CALL, icProto.getBytes());
+ }
}
}
}
diff --git a/core/java/android/view/inputmethod/InputMethodSubtype.java b/core/java/android/view/inputmethod/InputMethodSubtype.java
index 14abbdb6d33f..9c63d56d74da 100644
--- a/core/java/android/view/inputmethod/InputMethodSubtype.java
+++ b/core/java/android/view/inputmethod/InputMethodSubtype.java
@@ -71,7 +71,8 @@ public final class InputMethodSubtype implements Parcelable {
// TODO: remove this
private static final String EXTRA_KEY_UNTRANSLATABLE_STRING_IN_SUBTYPE_NAME =
"UntranslatableReplacementStringInSubtypeName";
- private static final int SUBTYPE_ID_NONE = 0;
+ /** {@hide} */
+ public static final int SUBTYPE_ID_NONE = 0;
private final boolean mIsAuxiliary;
private final boolean mOverridesImplicitlyEnabledSubtype;
diff --git a/core/java/android/webkit/WebViewFactory.java b/core/java/android/webkit/WebViewFactory.java
index dde9c3089370..b91e7d39f51c 100644
--- a/core/java/android/webkit/WebViewFactory.java
+++ b/core/java/android/webkit/WebViewFactory.java
@@ -251,15 +251,8 @@ public final class WebViewFactory {
Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "WebViewFactory.getProvider()");
try {
Class<WebViewFactoryProvider> providerClass = getProviderClass();
- Method staticFactory = null;
- try {
- staticFactory = providerClass.getMethod(
+ Method staticFactory = providerClass.getMethod(
CHROMIUM_WEBVIEW_FACTORY_METHOD, WebViewDelegate.class);
- } catch (Exception e) {
- if (DEBUG) {
- Log.w(LOGTAG, "error instantiating provider with static factory method", e);
- }
- }
Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "WebViewFactoryProvider invocation");
try {
@@ -267,12 +260,12 @@ public final class WebViewFactory {
staticFactory.invoke(null, new WebViewDelegate());
if (DEBUG) Log.v(LOGTAG, "Loaded provider: " + sProviderInstance);
return sProviderInstance;
- } catch (Exception e) {
- Log.e(LOGTAG, "error instantiating provider", e);
- throw new AndroidRuntimeException(e);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
}
+ } catch (Exception e) {
+ Log.e(LOGTAG, "error instantiating provider", e);
+ throw new AndroidRuntimeException(e);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
}
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 00ba326d2ba9..0025d1e2a853 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -16,7 +16,7 @@
package android.widget;
-import static android.view.OnReceiveContentListener.Payload.SOURCE_DRAG_AND_DROP;
+import static android.view.ContentInfo.SOURCE_DRAG_AND_DROP;
import android.R;
import android.animation.ValueAnimator;
@@ -87,6 +87,7 @@ import android.util.SparseArray;
import android.util.TypedValue;
import android.view.ActionMode;
import android.view.ActionMode.Callback;
+import android.view.ContentInfo;
import android.view.ContextMenu;
import android.view.ContextThemeWrapper;
import android.view.DragAndDropPermissions;
@@ -98,7 +99,6 @@ import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
-import android.view.OnReceiveContentListener;
import android.view.SubMenu;
import android.view.View;
import android.view.View.DragShadowBuilder;
@@ -2869,8 +2869,8 @@ public class Editor {
final int originalLength = mTextView.getText().length();
Selection.setSelection((Spannable) mTextView.getText(), offset);
final ClipData clip = event.getClipData();
- final OnReceiveContentListener.Payload payload =
- new OnReceiveContentListener.Payload.Builder(clip, SOURCE_DRAG_AND_DROP)
+ final ContentInfo payload =
+ new ContentInfo.Builder(clip, SOURCE_DRAG_AND_DROP)
.build();
mTextView.performReceiveContent(payload);
if (dragDropIntoItself) {
diff --git a/core/java/android/widget/NumberPicker.java b/core/java/android/widget/NumberPicker.java
index 7c20472df357..4f1c40a8d1c2 100644
--- a/core/java/android/widget/NumberPicker.java
+++ b/core/java/android/widget/NumberPicker.java
@@ -2773,6 +2773,7 @@ public class NumberPicker extends LinearLayout {
int left, int top, int right, int bottom) {
AccessibilityNodeInfo info = mInputText.createAccessibilityNodeInfo();
info.setSource(NumberPicker.this, VIRTUAL_VIEW_ID_INPUT);
+ info.setAccessibilityFocused(mAccessibilityFocusedView == VIRTUAL_VIEW_ID_INPUT);
if (mAccessibilityFocusedView != VIRTUAL_VIEW_ID_INPUT) {
info.addAction(AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS);
}
@@ -2802,6 +2803,7 @@ public class NumberPicker extends LinearLayout {
info.setClickable(true);
info.setLongClickable(true);
info.setEnabled(NumberPicker.this.isEnabled());
+ info.setAccessibilityFocused(mAccessibilityFocusedView == virtualViewId);
Rect boundsInParent = mTempRect;
boundsInParent.set(left, top, right, bottom);
info.setVisibleToUser(isVisibleToUser(boundsInParent));
@@ -2843,6 +2845,7 @@ public class NumberPicker extends LinearLayout {
info.setParent((View) getParentForAccessibility());
info.setEnabled(NumberPicker.this.isEnabled());
info.setScrollable(true);
+ info.setAccessibilityFocused(mAccessibilityFocusedView == View.NO_ID);
final float applicationScale =
getContext().getResources().getCompatibilityInfo().applicationScale;
diff --git a/core/java/android/widget/SelectionActionModeHelper.java b/core/java/android/widget/SelectionActionModeHelper.java
index a034a7c2dc7e..e08ccfddc4c5 100644
--- a/core/java/android/widget/SelectionActionModeHelper.java
+++ b/core/java/android/widget/SelectionActionModeHelper.java
@@ -156,8 +156,7 @@ public final class SelectionActionModeHelper {
mSmartSelectSprite != null
? this::startSelectionActionModeWithSmartSelectAnimation
: this::startSelectionActionMode,
- mTextClassificationHelper::getOriginalSelection,
- mTextClassificationHelper::isTextClassifierDestroyed)
+ mTextClassificationHelper::getOriginalSelection)
.execute();
}
}
@@ -179,8 +178,7 @@ public final class SelectionActionModeHelper {
mTextClassificationHelper.getTimeoutDuration(),
mTextClassificationHelper::classifyText,
this::startLinkActionMode,
- mTextClassificationHelper::getOriginalSelection,
- mTextClassificationHelper::isTextClassifierDestroyed)
+ mTextClassificationHelper::getOriginalSelection)
.execute();
}
}
@@ -196,8 +194,7 @@ public final class SelectionActionModeHelper {
mTextClassificationHelper.getTimeoutDuration(),
mTextClassificationHelper::classifyText,
this::invalidateActionMode,
- mTextClassificationHelper::getOriginalSelection,
- mTextClassificationHelper::isTextClassifierDestroyed)
+ mTextClassificationHelper::getOriginalSelection)
.execute();
}
}
@@ -995,7 +992,6 @@ public final class SelectionActionModeHelper {
private final Supplier<SelectionResult> mSelectionResultSupplier;
private final Consumer<SelectionResult> mSelectionResultCallback;
private final Supplier<SelectionResult> mTimeOutResultSupplier;
- private final Supplier<Boolean> mIsTextClassifierDestroyedSupplier;
private final TextView mTextView;
private final String mOriginalText;
@@ -1010,16 +1006,13 @@ public final class SelectionActionModeHelper {
@NonNull TextView textView, int timeOut,
@NonNull Supplier<SelectionResult> selectionResultSupplier,
@NonNull Consumer<SelectionResult> selectionResultCallback,
- @NonNull Supplier<SelectionResult> timeOutResultSupplier,
- @NonNull Supplier<Boolean> isTextClassifierDestroyedSupplier) {
+ @NonNull Supplier<SelectionResult> timeOutResultSupplier) {
super(textView != null ? textView.getHandler() : null);
mTextView = Objects.requireNonNull(textView);
mTimeOutDuration = timeOut;
mSelectionResultSupplier = Objects.requireNonNull(selectionResultSupplier);
mSelectionResultCallback = Objects.requireNonNull(selectionResultCallback);
mTimeOutResultSupplier = Objects.requireNonNull(timeOutResultSupplier);
- mIsTextClassifierDestroyedSupplier =
- Objects.requireNonNull(isTextClassifierDestroyedSupplier);
// Make a copy of the original text.
mOriginalText = getText(mTextView).toString();
}
@@ -1033,14 +1026,8 @@ public final class SelectionActionModeHelper {
try {
result = mSelectionResultSupplier.get();
} catch (IllegalStateException e) {
- // Swallows the exception if the text classifier session is destroyed
- if (mIsTextClassifierDestroyedSupplier.get()) {
- Log.w(LOG_TAG,
- "TextClassificationAsyncTask failed because TextClassifier destroyed",
- e);
- } else {
- throw e;
- }
+ // TODO(b/174300371): Only swallows the exception if the TCSession is destroyed
+ Log.w(LOG_TAG, "TextClassificationAsyncTask failed.", e);
}
mTextView.removeCallbacks(onTimeOut);
return result;
@@ -1173,10 +1160,6 @@ public final class SelectionActionModeHelper {
}
}
- public boolean isTextClassifierDestroyed() {
- return mTextClassifier.get().isDestroyed();
- }
-
private boolean isDarkLaunchEnabled() {
return TextClassificationManager.getSettings(mContext).isModelDarkLaunchEnabled();
}
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 98f808784803..02a930017906 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -17,10 +17,10 @@
package android.widget;
import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
-import static android.view.OnReceiveContentListener.Payload.FLAG_CONVERT_TO_PLAIN_TEXT;
-import static android.view.OnReceiveContentListener.Payload.SOURCE_AUTOFILL;
-import static android.view.OnReceiveContentListener.Payload.SOURCE_CLIPBOARD;
-import static android.view.OnReceiveContentListener.Payload.SOURCE_PROCESS_TEXT;
+import static android.view.ContentInfo.FLAG_CONVERT_TO_PLAIN_TEXT;
+import static android.view.ContentInfo.SOURCE_AUTOFILL;
+import static android.view.ContentInfo.SOURCE_CLIPBOARD;
+import static android.view.ContentInfo.SOURCE_PROCESS_TEXT;
import static android.view.accessibility.AccessibilityNodeInfo.EXTRA_DATA_RENDERING_INFO_KEY;
import static android.view.accessibility.AccessibilityNodeInfo.EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_LENGTH;
import static android.view.accessibility.AccessibilityNodeInfo.EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_START_INDEX;
@@ -146,6 +146,7 @@ import android.util.TypedValue;
import android.view.AccessibilityIterators.TextSegmentIterator;
import android.view.ActionMode;
import android.view.Choreographer;
+import android.view.ContentInfo;
import android.view.ContextMenu;
import android.view.DragEvent;
import android.view.Gravity;
@@ -154,7 +155,6 @@ import android.view.InputDevice;
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
import android.view.MotionEvent;
-import android.view.OnReceiveContentListener.Payload;
import android.view.PointerIcon;
import android.view.View;
import android.view.ViewConfiguration;
@@ -964,6 +964,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
* @hide
*/
public static void preloadFontCache() {
+ if (Typeface.ENABLE_LAZY_TYPEFACE_INITIALIZATION) {
+ return;
+ }
Paint p = new Paint();
p.setAntiAlias(true);
// Ensure that the Typeface is loaded here.
@@ -2151,7 +2154,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
if (result != null) {
if (isTextEditable()) {
ClipData clip = ClipData.newPlainText("", result);
- Payload payload = new Payload.Builder(clip, SOURCE_PROCESS_TEXT).build();
+ ContentInfo payload =
+ new ContentInfo.Builder(clip, SOURCE_PROCESS_TEXT).build();
performReceiveContent(payload);
if (mEditor != null) {
mEditor.refreshTextActionMode();
@@ -11857,7 +11861,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
+ " cannot be autofilled into " + this);
return;
}
- final Payload payload = new Payload.Builder(clip, SOURCE_AUTOFILL).build();
+ final ContentInfo payload = new ContentInfo.Builder(clip, SOURCE_AUTOFILL).build();
performReceiveContent(payload);
}
@@ -12924,7 +12928,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
if (clip == null) {
return;
}
- final Payload payload = new Payload.Builder(clip, SOURCE_CLIPBOARD)
+ final ContentInfo payload = new ContentInfo.Builder(clip, SOURCE_CLIPBOARD)
.setFlags(withFormatting ? 0 : FLAG_CONVERT_TO_PLAIN_TEXT)
.build();
performReceiveContent(payload);
@@ -13740,8 +13744,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
* @return The portion of the passed-in content that was not handled (may be all, some, or none
* of the passed-in content).
*/
+ @Nullable
@Override
- public @Nullable Payload onReceiveContent(@NonNull Payload payload) {
+ public ContentInfo onReceiveContent(@NonNull ContentInfo payload) {
if (mEditor != null) {
return mEditor.getDefaultOnReceiveContentListener().onReceiveContent(this, payload);
}
diff --git a/core/java/android/widget/TextViewOnReceiveContentListener.java b/core/java/android/widget/TextViewOnReceiveContentListener.java
index 7ef68ec7a4ee..8cef1061c423 100644
--- a/core/java/android/widget/TextViewOnReceiveContentListener.java
+++ b/core/java/android/widget/TextViewOnReceiveContentListener.java
@@ -17,10 +17,10 @@
package android.widget;
import static android.content.ContentResolver.SCHEME_CONTENT;
-import static android.view.OnReceiveContentListener.Payload.FLAG_CONVERT_TO_PLAIN_TEXT;
-import static android.view.OnReceiveContentListener.Payload.SOURCE_AUTOFILL;
-import static android.view.OnReceiveContentListener.Payload.SOURCE_DRAG_AND_DROP;
-import static android.view.OnReceiveContentListener.Payload.SOURCE_INPUT_METHOD;
+import static android.view.ContentInfo.FLAG_CONVERT_TO_PLAIN_TEXT;
+import static android.view.ContentInfo.SOURCE_AUTOFILL;
+import static android.view.ContentInfo.SOURCE_DRAG_AND_DROP;
+import static android.view.ContentInfo.SOURCE_INPUT_METHOD;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -38,9 +38,10 @@ import android.text.Selection;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.util.Log;
+import android.view.ContentInfo;
+import android.view.ContentInfo.Flags;
+import android.view.ContentInfo.Source;
import android.view.OnReceiveContentListener;
-import android.view.OnReceiveContentListener.Payload.Flags;
-import android.view.OnReceiveContentListener.Payload.Source;
import android.view.View;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputConnection;
@@ -53,20 +54,21 @@ import java.util.ArrayList;
import java.util.Arrays;
/**
- * Default implementation of {@link OnReceiveContentListener} for editable
- * {@link TextView} components. This class handles insertion of text (plain text, styled text, HTML,
- * etc) but not images or other content.
+ * Default implementation for {@link View#onReceiveContent} for editable {@link TextView}
+ * components. This class handles insertion of text (plain text, styled text, HTML, etc) but not
+ * images or other content.
*
* @hide
*/
@VisibleForTesting
public final class TextViewOnReceiveContentListener implements OnReceiveContentListener {
- private static final String LOG_TAG = "OnReceiveContent";
+ private static final String LOG_TAG = "ReceiveContent";
@Nullable private InputConnectionInfo mInputConnectionInfo;
+ @Nullable
@Override
- public @Nullable Payload onReceiveContent(@NonNull View view, @NonNull Payload payload) {
+ public ContentInfo onReceiveContent(@NonNull View view, @NonNull ContentInfo payload) {
if (Log.isLoggable(LOG_TAG, Log.DEBUG)) {
Log.d(LOG_TAG, "onReceive: " + payload);
}
@@ -126,7 +128,7 @@ public final class TextViewOnReceiveContentListener implements OnReceiveContentL
editable.replace(start, end, replacement);
}
- private void onReceiveForAutofill(@NonNull TextView view, @NonNull Payload payload) {
+ private void onReceiveForAutofill(@NonNull TextView view, @NonNull ContentInfo payload) {
ClipData clip = payload.getClip();
if (isUsageOfImeCommitContentEnabled(view)) {
clip = handleNonTextViaImeCommitContent(clip);
@@ -145,7 +147,8 @@ public final class TextViewOnReceiveContentListener implements OnReceiveContentL
Selection.setSelection(editable, editable.length());
}
- private static void onReceiveForDragAndDrop(@NonNull TextView view, @NonNull Payload payload) {
+ private static void onReceiveForDragAndDrop(@NonNull TextView view,
+ @NonNull ContentInfo payload) {
final CharSequence text = coerceToText(payload.getClip(), view.getContext(),
payload.getFlags());
replaceSelection((Editable) view.getText(), text);
diff --git a/core/java/com/android/internal/inputmethod/CallbackUtils.java b/core/java/com/android/internal/inputmethod/CallbackUtils.java
new file mode 100644
index 000000000000..ec6779216ae5
--- /dev/null
+++ b/core/java/com/android/internal/inputmethod/CallbackUtils.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.inputmethod;
+
+import android.annotation.AnyThread;
+import android.annotation.NonNull;
+import android.os.RemoteException;
+
+import com.android.internal.view.InputBindResult;
+
+import java.util.function.Supplier;
+
+/**
+ * Defines a set of helper methods to callback corresponding results in {@link ResultCallbacks}.
+ */
+public final class CallbackUtils {
+
+ /**
+ * Not intended to be instantiated.
+ */
+ private CallbackUtils() {
+ }
+
+ /**
+ * A utility method using given {@link IInputBindResultResultCallback} to callback the
+ * {@link InputBindResult}.
+ *
+ * @param callback {@link IInputBindResultResultCallback} to be called back.
+ * @param resultSupplier the supplier from which {@link InputBindResult} is provided.
+ */
+ @AnyThread
+ public static void onResult(@NonNull IInputBindResultResultCallback callback,
+ @NonNull Supplier<InputBindResult> resultSupplier) {
+ try {
+ callback.onResult(resultSupplier.get());
+ } catch (RemoteException ignored) { }
+ }
+}
diff --git a/core/java/com/android/internal/inputmethod/Completable.java b/core/java/com/android/internal/inputmethod/Completable.java
index d8d1a7df6aa8..b9e1cf09dc07 100644
--- a/core/java/com/android/internal/inputmethod/Completable.java
+++ b/core/java/com/android/internal/inputmethod/Completable.java
@@ -124,6 +124,16 @@ public final class Completable {
return true;
}
}
+
+ /**
+ * Blocks the calling thread until this object becomes ready to return the value.
+ */
+ @AnyThread
+ public void await() {
+ try {
+ mLatch.await();
+ } catch (InterruptedException ignored) { }
+ }
}
/**
@@ -250,6 +260,13 @@ public final class Completable {
}
/**
+ * @return an instance of {@link Completable.InputBindResult}.
+ */
+ public static Completable.InputBindResult createInputBindResult() {
+ return new Completable.InputBindResult();
+ }
+
+ /**
* Completable object of {@link java.lang.Boolean}.
*/
public static final class Boolean extends Values<java.lang.Boolean> { }
@@ -278,6 +295,18 @@ public final class Completable {
extends Values<com.android.internal.view.InputBindResult> { }
/**
+ * Await the result by the {@link Completable.Values}.
+ *
+ * @return the result once {@link ValueBase#onComplete()}
+ */
+ @AnyThread
+ @Nullable
+ public static <T> T getResult(@NonNull Completable.Values<T> value) {
+ value.await();
+ return value.getValue();
+ }
+
+ /**
* Await the result by the {@link Completable.Int}, and log it if there is no result after
* given timeout.
*
diff --git a/core/java/com/android/internal/inputmethod/IInputBindResultResultCallback.aidl b/core/java/com/android/internal/inputmethod/IInputBindResultResultCallback.aidl
new file mode 100644
index 000000000000..b52b3b100ed0
--- /dev/null
+++ b/core/java/com/android/internal/inputmethod/IInputBindResultResultCallback.aidl
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.inputmethod;
+
+import com.android.internal.view.InputBindResult;
+
+oneway interface IInputBindResultResultCallback {
+ void onResult(in InputBindResult result);
+} \ No newline at end of file
diff --git a/core/java/com/android/internal/inputmethod/ResultCallbacks.java b/core/java/com/android/internal/inputmethod/ResultCallbacks.java
index 7131284e42df..c59dcf4ce420 100644
--- a/core/java/com/android/internal/inputmethod/ResultCallbacks.java
+++ b/core/java/com/android/internal/inputmethod/ResultCallbacks.java
@@ -21,6 +21,8 @@ import android.annotation.BinderThread;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import com.android.internal.view.InputBindResult;
+
import java.lang.ref.WeakReference;
import java.util.concurrent.atomic.AtomicReference;
@@ -154,4 +156,31 @@ public final class ResultCallbacks {
}
};
}
+
+ /**
+ * Creates {@link IInputBindResultResultCallback.Stub} that is to set
+ * {@link Completable.InputBindResult} when receiving the result.
+ *
+ * @param value {@link Completable.InputBindResult} to be set when receiving the result.
+ * @return {@link IInputBindResultResultCallback.Stub} that can be passed as a binder IPC
+ * parameter.
+ */
+ @AnyThread
+ public static IInputBindResultResultCallback.Stub of(
+ @NonNull Completable.InputBindResult value) {
+ final AtomicReference<WeakReference<Completable.InputBindResult>>
+ atomicRef = new AtomicReference<>(new WeakReference<>(value));
+
+ return new IInputBindResultResultCallback.Stub() {
+ @BinderThread
+ @Override
+ public void onResult(InputBindResult result) {
+ final Completable.InputBindResult value = unwrap(atomicRef);
+ if (value == null) {
+ return;
+ }
+ value.onComplete(result);
+ }
+ };
+ }
}
diff --git a/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java b/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java
index ffc7f05eb703..1553e2eb0793 100644
--- a/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java
+++ b/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java
@@ -48,7 +48,8 @@ import java.lang.annotation.Retention;
SoftInputShowHideReason.HIDE_DOCKED_STACK_ATTACHED,
SoftInputShowHideReason.HIDE_RECENTS_ANIMATION,
SoftInputShowHideReason.HIDE_BUBBLES,
- SoftInputShowHideReason.HIDE_SAME_WINDOW_FOCUSED_WITHOUT_EDITOR})
+ SoftInputShowHideReason.HIDE_SAME_WINDOW_FOCUSED_WITHOUT_EDITOR,
+ SoftInputShowHideReason.HIDE_REMOVE_CLIENT})
public @interface SoftInputShowHideReason {
/** Show soft input by {@link android.view.inputmethod.InputMethodManager#showSoftInput}. */
int SHOW_SOFT_INPUT = 0;
@@ -161,4 +162,9 @@ public @interface SoftInputShowHideReason {
* soft-input when the same window focused again to align with the same behavior prior to R.
*/
int HIDE_SAME_WINDOW_FOCUSED_WITHOUT_EDITOR = 20;
+
+ /**
+ * Hide soft input when a {@link com.android.internal.view.IInputMethodClient} is removed.
+ */
+ int HIDE_REMOVE_CLIENT = 21;
}
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 7571f5db8cad..dcd74fd1ad3e 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -38,6 +38,7 @@ import android.net.NetworkStats;
import android.net.Uri;
import android.net.wifi.WifiManager;
import android.os.BatteryManager;
+import android.os.BatteryProperty;
import android.os.BatteryStats;
import android.os.Binder;
import android.os.Build;
@@ -54,6 +55,7 @@ import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
+import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.WorkSource;
import android.os.WorkSource.WorkChain;
@@ -144,6 +146,14 @@ import java.util.concurrent.locks.ReentrantLock;
public class BatteryStatsImpl extends BatteryStats {
private static final String TAG = "BatteryStatsImpl";
private static final boolean DEBUG = false;
+
+ // TODO(b/169376495): STOPSHIP if true
+ private static final boolean DEBUG_FOREGROUND_STATS = true;
+
+ private static final boolean ENABLE_FOREGROUND_STATS_COLLECTION =
+ DEBUG_FOREGROUND_STATS && SystemProperties.getBoolean(
+ "debug.battery_foreground_stats_collection", false);
+
public static final boolean DEBUG_ENERGY = false;
private static final boolean DEBUG_ENERGY_CPU = DEBUG_ENERGY;
private static final boolean DEBUG_BINDER_STATS = false;
@@ -739,6 +749,37 @@ public class BatteryStatsImpl extends BatteryStats {
long mTrackRunningHistoryElapsedRealtimeMs = 0;
long mTrackRunningHistoryUptimeMs = 0;
+ private static final int FOREGROUND_UID_INITIAL_CAPACITY = 10;
+ private static final int INVALID_UID = -1;
+
+ private final IntArray mForegroundUids = ENABLE_FOREGROUND_STATS_COLLECTION
+ ? new IntArray(FOREGROUND_UID_INITIAL_CAPACITY) : null;
+
+ // Last recorded battery energy capacity.
+ // This is used for computing foregrund power per application.
+ // See: PowerForUid below
+ private long mLastBatteryEnergyCapacityNWh = 0;
+
+ private static final class PowerForUid {
+ public long energyNwh = 0;
+ // Same as energyNwh, but not tracked for the first 2 minutes;
+ public long filteredEnergyNwh = 0;
+ public double totalHours = 0;
+ public long baseTimeMs = 0;
+
+ double computePower() {
+ // units in nW
+ return totalHours != 0 ? energyNwh / totalHours : -1.0;
+ }
+
+ double computeFilteredPower() {
+ // units in nW
+ return totalHours != 0 ? filteredEnergyNwh / totalHours : -1.0;
+ }
+ }
+ private final HashMap<Integer, PowerForUid> mUidToPower = ENABLE_FOREGROUND_STATS_COLLECTION
+ ? new HashMap<>() : null;
+
final BatteryStatsHistory mBatteryStatsHistory;
final HistoryItem mHistoryCur = new HistoryItem();
@@ -1026,6 +1067,8 @@ public class BatteryStatsImpl extends BatteryStats {
private int mNumConnectivityChange;
+ private int mBatteryVolt = -1;
+ private int mBatteryCharge = -1;
private int mEstimatedBatteryCapacity = -1;
private int mMinLearnedBatteryCapacity = -1;
@@ -4154,6 +4197,49 @@ public class BatteryStatsImpl extends BatteryStats {
// TODO(b/155216561): It is possible for isolated uids to be in a higher
// state than its parent uid. We should track the highest state within the union of host
// and isolated uids rather than only the parent uid.
+
+
+ int uidState = mapToInternalProcessState(state);
+
+ boolean isForeground = (uidState == Uid.PROCESS_STATE_TOP)
+ || (uidState == Uid.PROCESS_STATE_FOREGROUND);
+
+
+ if (ENABLE_FOREGROUND_STATS_COLLECTION) {
+ boolean previouslyInForegrond = false;
+ for (int i = 0; i < mForegroundUids.size(); i++) {
+ if (mForegroundUids.get(i) == uid) {
+ previouslyInForegrond = true;
+ if (!isForeground) {
+ // If we were previously in the foreground, remove the uid
+ // from the foreground set and dirty the slot.
+ mForegroundUids.set(i, INVALID_UID);
+ final PowerForUid pfu =
+ mUidToPower.computeIfAbsent(uid, unused -> new PowerForUid());
+ pfu.baseTimeMs = 0;
+ break;
+ }
+ }
+ }
+
+ if (!previouslyInForegrond && isForeground) {
+ boolean addedToForeground = false;
+ // Check if we have a free slot to clobber...
+ for (int i = 0; i < mForegroundUids.size(); i++) {
+ if (mForegroundUids.get(i) == INVALID_UID) {
+ addedToForeground = true;
+ mForegroundUids.set(i, uid);
+ break;
+ }
+ }
+
+ // ...if not, append to the end of the array.
+ if (!addedToForeground) {
+ mForegroundUids.add(uid);
+ }
+ }
+ }
+
FrameworkStatsLog.write(FrameworkStatsLog.UID_PROCESS_STATE_CHANGED, uid,
ActivityManager.processStateAmToProto(state));
getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs)
@@ -12968,6 +13054,7 @@ public class BatteryStatsImpl extends BatteryStats {
doWrite = true;
resetAllStatsLocked(mSecUptime, mSecRealtime);
if (chargeUAh > 0 && level > 0) {
+ mBatteryCharge = chargeUAh;
// Only use the reported coulomb charge value if it is supported and reported.
mEstimatedBatteryCapacity = (int) ((chargeUAh / 1000) / (level / 100.0));
}
@@ -13140,6 +13227,47 @@ public class BatteryStatsImpl extends BatteryStats {
startRecordingHistory(elapsedRealtimeMs, uptimeMs, true);
}
}
+
+ if (ENABLE_FOREGROUND_STATS_COLLECTION) {
+ mBatteryVolt = volt;
+ if (onBattery) {
+ final long energyNwh = (volt * (long) chargeUAh);
+ final long energyDelta = mLastBatteryEnergyCapacityNWh - energyNwh;
+ for (int i = 0; i < mForegroundUids.size(); i++) {
+ final int uid = mForegroundUids.get(i);
+ if (uid == INVALID_UID) {
+ continue;
+ }
+ final PowerForUid pfu = mUidToPower
+ .computeIfAbsent(uid, unused -> new PowerForUid());
+ if (pfu.baseTimeMs <= 0) {
+ pfu.baseTimeMs = currentTimeMs;
+ } else {
+ // Check if mLastBatteryEnergyCapacityNWh > energyNwh,
+ // to make sure we only count discharges
+ if (energyDelta > 0) {
+ pfu.energyNwh += energyDelta;
+ // Convert from milliseconds to hours
+ // 1000 ms per second * 3600 seconds per hour
+ pfu.totalHours += ((double) (currentTimeMs - pfu.baseTimeMs)
+ / (1.0 * 1000 * 60 * 60));
+ // Now convert from 2 minutes to hours
+ // 2 minutes = 1/30 of an hour
+ if (pfu.totalHours > (2.0 / 60)) {
+ pfu.filteredEnergyNwh += energyDelta;
+ }
+
+ }
+ pfu.baseTimeMs = currentTimeMs;
+ }
+ }
+ mLastBatteryEnergyCapacityNWh = energyNwh;
+ } else if (onBattery != mOnBattery) {
+ // Transition to onBattery = false
+ mUidToPower.values().forEach(v -> v.baseTimeMs = 0);
+ }
+ }
+
mCurrentBatteryLevel = level;
if (mDischargePlugLevel < 0) {
mDischargePlugLevel = level;
@@ -16056,6 +16184,48 @@ public class BatteryStatsImpl extends BatteryStats {
}
public void dumpLocked(Context context, PrintWriter pw, int flags, int reqUid, long histStart) {
+ if (ENABLE_FOREGROUND_STATS_COLLECTION) {
+ long actualCharge = -1;
+ long actualEnergy = -1;
+ try {
+ IBatteryPropertiesRegistrar registrar =
+ IBatteryPropertiesRegistrar.Stub.asInterface(
+ ServiceManager.getService("batteryproperties"));
+ if (registrar != null) {
+ BatteryProperty prop = new BatteryProperty();
+ if (registrar.getProperty(
+ BatteryManager.BATTERY_PROPERTY_CHARGE_COUNTER, prop) == 0) {
+ actualCharge = prop.getLong();
+ }
+ prop = new BatteryProperty();
+ if (registrar.getProperty(
+ BatteryManager.BATTERY_PROPERTY_ENERGY_COUNTER, prop) == 0) {
+ actualEnergy = prop.getLong();
+ }
+ }
+ } catch (RemoteException e) {
+ // Ignore.
+ }
+ pw.printf("ActualCharge (uAh): %d\n", (int) actualCharge);
+ pw.printf("ActualEnergy (nWh): %d\n", actualEnergy);
+ pw.printf("mBatteryCharge (uAh): %d\n", mBatteryCharge);
+ pw.printf("mBatteryVolts (mV): %d\n", mBatteryVolt);
+ pw.printf("est energy (nWh): %d\n", mBatteryVolt * (long) mBatteryCharge);
+ pw.printf("mEstimatedBatteryCapacity (mAh): %d\n", mEstimatedBatteryCapacity);
+ pw.printf("mMinLearnedBatteryCapacity (uAh): %d\n", mMinLearnedBatteryCapacity);
+ pw.printf("mMaxLearnedBatteryCapacity (uAh): %d\n", mMaxLearnedBatteryCapacity);
+ pw.printf("est. capacity: %f\n",
+ (float) actualCharge / (mEstimatedBatteryCapacity * 1000));
+ pw.printf("mCurrentBatteryLevel: %d\n", mCurrentBatteryLevel);
+ pw.println("Total Power per app:");
+ mUidToPower.entrySet().forEach(e ->
+ pw.printf("Uid: %d, Total watts (nW): %f\n",
+ e.getKey(), e.getValue().computePower()));
+ pw.println("Total Power per app after first 2 minutes initial launch:");
+ mUidToPower.entrySet().forEach(e ->
+ pw.printf("Uid: %d, Total watts (nW): %f\n",
+ e.getKey(), e.getValue().computeFilteredPower()));
+ }
if (DEBUG) {
pw.println("mOnBatteryTimeBase:");
mOnBatteryTimeBase.dump(pw, " ");
diff --git a/core/java/com/android/internal/util/FastXmlSerializer.java b/core/java/com/android/internal/util/FastXmlSerializer.java
index 94e07a85867e..929c9e8bb8c1 100644
--- a/core/java/com/android/internal/util/FastXmlSerializer.java
+++ b/core/java/com/android/internal/util/FastXmlSerializer.java
@@ -367,8 +367,11 @@ public class FastXmlSerializer implements XmlSerializer {
public void startDocument(String encoding, Boolean standalone) throws IOException,
IllegalArgumentException, IllegalStateException {
- append("<?xml version='1.0' encoding='utf-8' standalone='"
- + (standalone ? "yes" : "no") + "' ?>\n");
+ append("<?xml version='1.0' encoding='utf-8'");
+ if (standalone != null) {
+ append(" standalone='" + (standalone ? "yes" : "no") + "'");
+ }
+ append(" ?>\n");
mLineStart = true;
}
diff --git a/core/java/com/android/internal/view/IInputConnectionWrapper.java b/core/java/com/android/internal/view/IInputConnectionWrapper.java
index 33ebe43cb23a..1d5935db6322 100644
--- a/core/java/com/android/internal/view/IInputConnectionWrapper.java
+++ b/core/java/com/android/internal/view/IInputConnectionWrapper.java
@@ -25,7 +25,11 @@ import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
+import android.os.Trace;
import android.util.Log;
+import android.util.imetracing.ImeTracing;
+import android.util.imetracing.InputConnectionHelper;
+import android.util.proto.ProtoOutputStream;
import android.view.KeyEvent;
import android.view.inputmethod.CompletionInfo;
import android.view.inputmethod.CorrectionInfo;
@@ -35,6 +39,7 @@ import android.view.inputmethod.InputConnection;
import android.view.inputmethod.InputConnectionInspector;
import android.view.inputmethod.InputConnectionInspector.MissingMethodFlags;
import android.view.inputmethod.InputContentInfo;
+import android.view.inputmethod.InputMethodManager;
import android.view.inputmethod.SurroundingText;
import com.android.internal.annotations.GuardedBy;
@@ -111,13 +116,21 @@ public abstract class IInputConnectionWrapper extends IInputContext.Stub {
}
}
+ protected Looper getLooper() {
+ synchronized (mMainLooper) {
+ return mMainLooper;
+ }
+ }
+
protected boolean isFinished() {
synchronized (mLock) {
return mFinished;
}
}
- abstract protected boolean isActive();
+ protected abstract boolean isActive();
+
+ protected abstract InputMethodManager getIMM();
public void getTextAfterCursor(int length, int flags, ICharSequenceResultCallback callback) {
dispatchMessage(mH.obtainMessage(DO_GET_TEXT_AFTER_CURSOR, length, flags, callback));
@@ -257,63 +270,100 @@ public abstract class IInputConnectionWrapper extends IInputContext.Stub {
}
void executeMessage(Message msg) {
+ ProtoOutputStream icProto;
switch (msg.what) {
case DO_GET_TEXT_AFTER_CURSOR: {
- final ICharSequenceResultCallback callback = (ICharSequenceResultCallback) msg.obj;
- final InputConnection ic = getInputConnection();
- final CharSequence result;
- if (ic == null || !isActive()) {
- Log.w(TAG, "getTextAfterCursor on inactive InputConnection");
- result = null;
- } else {
- result = ic.getTextAfterCursor(msg.arg1, msg.arg2);
- }
+ Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#getTextAfterCursor");
try {
- callback.onResult(result);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed to return the result to getTextAfterCursor()."
+ final ICharSequenceResultCallback callback =
+ (ICharSequenceResultCallback) msg.obj;
+ final InputConnection ic = getInputConnection();
+ final CharSequence result;
+ if (ic == null || !isActive()) {
+ Log.w(TAG, "getTextAfterCursor on inactive InputConnection");
+ result = null;
+ } else {
+ result = ic.getTextAfterCursor(msg.arg1, msg.arg2);
+ }
+ if (ImeTracing.getInstance().isEnabled()) {
+ icProto = InputConnectionHelper.buildGetTextAfterCursorProto(msg.arg1,
+ msg.arg2, result);
+ ImeTracing.getInstance().triggerClientDump(
+ TAG + "#getTextAfterCursor", getIMM(), icProto);
+ }
+ try {
+ callback.onResult(result);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed to return the result to getTextAfterCursor()."
+ " result=" + result, e);
+ }
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_INPUT);
}
return;
}
case DO_GET_TEXT_BEFORE_CURSOR: {
- final ICharSequenceResultCallback callback = (ICharSequenceResultCallback) msg.obj;
- final InputConnection ic = getInputConnection();
- final CharSequence result;
- if (ic == null || !isActive()) {
- Log.w(TAG, "getTextBeforeCursor on inactive InputConnection");
- result = null;
- } else {
- result = ic.getTextBeforeCursor(msg.arg1, msg.arg2);
- }
+ Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#getTextBeforeCursor");
try {
- callback.onResult(result);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed to return the result to getTextBeforeCursor()."
+ final ICharSequenceResultCallback callback =
+ (ICharSequenceResultCallback) msg.obj;
+ final InputConnection ic = getInputConnection();
+ final CharSequence result;
+ if (ic == null || !isActive()) {
+ Log.w(TAG, "getTextBeforeCursor on inactive InputConnection");
+ result = null;
+ } else {
+ result = ic.getTextBeforeCursor(msg.arg1, msg.arg2);
+ }
+ if (ImeTracing.getInstance().isEnabled()) {
+ icProto = InputConnectionHelper.buildGetTextBeforeCursorProto(msg.arg1,
+ msg.arg2, result);
+ ImeTracing.getInstance().triggerClientDump(
+ TAG + "#getTextBeforeCursor", getIMM(), icProto);
+ }
+ try {
+ callback.onResult(result);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed to return the result to getTextBeforeCursor()."
+ " result=" + result, e);
+ }
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_INPUT);
}
return;
}
case DO_GET_SELECTED_TEXT: {
- final ICharSequenceResultCallback callback = (ICharSequenceResultCallback) msg.obj;
- final InputConnection ic = getInputConnection();
- final CharSequence result;
- if (ic == null || !isActive()) {
- Log.w(TAG, "getSelectedText on inactive InputConnection");
- result = null;
- } else {
- result = ic.getSelectedText(msg.arg1);
- }
+ Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#getSelectedText");
try {
- callback.onResult(result);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed to return the result to getSelectedText()."
- + " result=" + result, e);
+ final ICharSequenceResultCallback callback =
+ (ICharSequenceResultCallback) msg.obj;
+ final InputConnection ic = getInputConnection();
+ final CharSequence result;
+ if (ic == null || !isActive()) {
+ Log.w(TAG, "getSelectedText on inactive InputConnection");
+ result = null;
+ } else {
+ result = ic.getSelectedText(msg.arg1);
+ }
+ if (ImeTracing.getInstance().isEnabled()) {
+ icProto = InputConnectionHelper.buildGetSelectedTextProto(msg.arg1, result);
+ ImeTracing.getInstance().triggerClientDump(
+ TAG + "#getSelectedText", getIMM(), icProto);
+ }
+ try {
+ callback.onResult(result);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed to return the result to getSelectedText()."
+ + " result=" + result, e);
+ }
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_INPUT);
}
return;
}
case DO_GET_SURROUNDING_TEXT: {
final SomeArgs args = (SomeArgs) msg.obj;
+ Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#getSurroundingText");
try {
int beforeLength = (int) args.arg1;
int afterLength = (int) args.arg2;
@@ -328,6 +378,12 @@ public abstract class IInputConnectionWrapper extends IInputContext.Stub {
} else {
result = ic.getSurroundingText(beforeLength, afterLength, flags);
}
+ if (ImeTracing.getInstance().isEnabled()) {
+ icProto = InputConnectionHelper.buildGetSurroundingTextProto(beforeLength,
+ afterLength, flags, result);
+ ImeTracing.getInstance().triggerClientDump(
+ TAG + "#getSurroundingText", getIMM(), icProto);
+ }
try {
callback.onResult(result);
} catch (RemoteException e) {
@@ -335,30 +391,43 @@ public abstract class IInputConnectionWrapper extends IInputContext.Stub {
+ " result=" + result, e);
}
} finally {
+ Trace.traceEnd(Trace.TRACE_TAG_INPUT);
args.recycle();
}
return;
}
case DO_GET_CURSOR_CAPS_MODE: {
- final IIntResultCallback callback = (IIntResultCallback) msg.obj;
- final InputConnection ic = getInputConnection();
- final int result;
- if (ic == null || !isActive()) {
- Log.w(TAG, "getCursorCapsMode on inactive InputConnection");
- result = 0;
- } else {
- result = ic.getCursorCapsMode(msg.arg1);
- }
+ Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#getCursorCapsMode");
try {
- callback.onResult(result);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed to return the result to getCursorCapsMode()."
+ final IIntResultCallback callback = (IIntResultCallback) msg.obj;
+ final InputConnection ic = getInputConnection();
+ final int result;
+ if (ic == null || !isActive()) {
+ Log.w(TAG, "getCursorCapsMode on inactive InputConnection");
+ result = 0;
+ } else {
+ result = ic.getCursorCapsMode(msg.arg1);
+ }
+ if (ImeTracing.getInstance().isEnabled()) {
+ icProto = InputConnectionHelper.buildGetCursorCapsModeProto(msg.arg1,
+ result);
+ ImeTracing.getInstance().triggerClientDump(
+ TAG + "#getCursorCapsMode", getIMM(), icProto);
+ }
+ try {
+ callback.onResult(result);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed to return the result to getCursorCapsMode()."
+ " result=" + result, e);
+ }
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_INPUT);
}
return;
}
case DO_GET_EXTRACTED_TEXT: {
final SomeArgs args = (SomeArgs) msg.obj;
+ Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#getExtractedText");
try {
final ExtractedTextRequest request = (ExtractedTextRequest) args.arg1;
final IExtractedTextResultCallback callback =
@@ -371,6 +440,12 @@ public abstract class IInputConnectionWrapper extends IInputContext.Stub {
} else {
result = ic.getExtractedText(request, msg.arg1);
}
+ if (ImeTracing.getInstance().isEnabled()) {
+ icProto = InputConnectionHelper.buildGetExtractedTextProto(request,
+ msg.arg1, result);
+ ImeTracing.getInstance().triggerClientDump(
+ TAG + "#getExtractedText", getIMM(), icProto);
+ }
try {
callback.onResult(result);
} catch (RemoteException e) {
@@ -378,159 +453,237 @@ public abstract class IInputConnectionWrapper extends IInputContext.Stub {
+ " result=" + result, e);
}
} finally {
+ Trace.traceEnd(Trace.TRACE_TAG_INPUT);
args.recycle();
}
return;
}
case DO_COMMIT_TEXT: {
- InputConnection ic = getInputConnection();
- if (ic == null || !isActive()) {
- Log.w(TAG, "commitText on inactive InputConnection");
- return;
+ Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#commitText");
+ try {
+ InputConnection ic = getInputConnection();
+ if (ic == null || !isActive()) {
+ Log.w(TAG, "commitText on inactive InputConnection");
+ return;
+ }
+ ic.commitText((CharSequence) msg.obj, msg.arg1);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_INPUT);
}
- ic.commitText((CharSequence)msg.obj, msg.arg1);
return;
}
case DO_SET_SELECTION: {
- InputConnection ic = getInputConnection();
- if (ic == null || !isActive()) {
- Log.w(TAG, "setSelection on inactive InputConnection");
- return;
+ Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#setSelection");
+ try {
+ InputConnection ic = getInputConnection();
+ if (ic == null || !isActive()) {
+ Log.w(TAG, "setSelection on inactive InputConnection");
+ return;
+ }
+ ic.setSelection(msg.arg1, msg.arg2);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_INPUT);
}
- ic.setSelection(msg.arg1, msg.arg2);
return;
}
case DO_PERFORM_EDITOR_ACTION: {
- InputConnection ic = getInputConnection();
- if (ic == null || !isActive()) {
- Log.w(TAG, "performEditorAction on inactive InputConnection");
- return;
+ Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#performEditorAction");
+ try {
+ InputConnection ic = getInputConnection();
+ if (ic == null || !isActive()) {
+ Log.w(TAG, "performEditorAction on inactive InputConnection");
+ return;
+ }
+ ic.performEditorAction(msg.arg1);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_INPUT);
}
- ic.performEditorAction(msg.arg1);
return;
}
case DO_PERFORM_CONTEXT_MENU_ACTION: {
- InputConnection ic = getInputConnection();
- if (ic == null || !isActive()) {
- Log.w(TAG, "performContextMenuAction on inactive InputConnection");
- return;
+ Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#performContextMenuAction");
+ try {
+ InputConnection ic = getInputConnection();
+ if (ic == null || !isActive()) {
+ Log.w(TAG, "performContextMenuAction on inactive InputConnection");
+ return;
+ }
+ ic.performContextMenuAction(msg.arg1);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_INPUT);
}
- ic.performContextMenuAction(msg.arg1);
return;
}
case DO_COMMIT_COMPLETION: {
- InputConnection ic = getInputConnection();
- if (ic == null || !isActive()) {
- Log.w(TAG, "commitCompletion on inactive InputConnection");
- return;
+ Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#commitCompletion");
+ try {
+ InputConnection ic = getInputConnection();
+ if (ic == null || !isActive()) {
+ Log.w(TAG, "commitCompletion on inactive InputConnection");
+ return;
+ }
+ ic.commitCompletion((CompletionInfo) msg.obj);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_INPUT);
}
- ic.commitCompletion((CompletionInfo)msg.obj);
return;
}
case DO_COMMIT_CORRECTION: {
- InputConnection ic = getInputConnection();
- if (ic == null || !isActive()) {
- Log.w(TAG, "commitCorrection on inactive InputConnection");
- return;
+ Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#commitCorrection");
+ try {
+ InputConnection ic = getInputConnection();
+ if (ic == null || !isActive()) {
+ Log.w(TAG, "commitCorrection on inactive InputConnection");
+ return;
+ }
+ ic.commitCorrection((CorrectionInfo) msg.obj);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_INPUT);
}
- ic.commitCorrection((CorrectionInfo)msg.obj);
return;
}
case DO_SET_COMPOSING_TEXT: {
- InputConnection ic = getInputConnection();
- if (ic == null || !isActive()) {
- Log.w(TAG, "setComposingText on inactive InputConnection");
- return;
+ Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#setComposingText");
+ try {
+ InputConnection ic = getInputConnection();
+ if (ic == null || !isActive()) {
+ Log.w(TAG, "setComposingText on inactive InputConnection");
+ return;
+ }
+ ic.setComposingText((CharSequence) msg.obj, msg.arg1);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_INPUT);
}
- ic.setComposingText((CharSequence)msg.obj, msg.arg1);
return;
}
case DO_SET_COMPOSING_REGION: {
- InputConnection ic = getInputConnection();
- if (ic == null || !isActive()) {
- Log.w(TAG, "setComposingRegion on inactive InputConnection");
- return;
+ Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#setComposingRegion");
+ try {
+ InputConnection ic = getInputConnection();
+ if (ic == null || !isActive()) {
+ Log.w(TAG, "setComposingRegion on inactive InputConnection");
+ return;
+ }
+ ic.setComposingRegion(msg.arg1, msg.arg2);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_INPUT);
}
- ic.setComposingRegion(msg.arg1, msg.arg2);
return;
}
case DO_FINISH_COMPOSING_TEXT: {
- if (isFinished()) {
- // In this case, #finishComposingText() is guaranteed to be called already.
- // There should be no negative impact if we ignore this call silently.
- if (DEBUG) {
- Log.w(TAG, "Bug 35301295: Redundant finishComposingText.");
+ Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#finishComposingText");
+ try {
+ if (isFinished()) {
+ // In this case, #finishComposingText() is guaranteed to be called already.
+ // There should be no negative impact if we ignore this call silently.
+ if (DEBUG) {
+ Log.w(TAG, "Bug 35301295: Redundant finishComposingText.");
+ }
+ return;
}
- return;
- }
- InputConnection ic = getInputConnection();
- // Note we do NOT check isActive() here, because this is safe
- // for an IME to call at any time, and we need to allow it
- // through to clean up our state after the IME has switched to
- // another client.
- if (ic == null) {
- Log.w(TAG, "finishComposingText on inactive InputConnection");
- return;
+ InputConnection ic = getInputConnection();
+ // Note we do NOT check isActive() here, because this is safe
+ // for an IME to call at any time, and we need to allow it
+ // through to clean up our state after the IME has switched to
+ // another client.
+ if (ic == null) {
+ Log.w(TAG, "finishComposingText on inactive InputConnection");
+ return;
+ }
+ ic.finishComposingText();
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_INPUT);
}
- ic.finishComposingText();
return;
}
case DO_SEND_KEY_EVENT: {
- InputConnection ic = getInputConnection();
- if (ic == null || !isActive()) {
- Log.w(TAG, "sendKeyEvent on inactive InputConnection");
- return;
+ Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#sendKeyEvent");
+ try {
+ InputConnection ic = getInputConnection();
+ if (ic == null || !isActive()) {
+ Log.w(TAG, "sendKeyEvent on inactive InputConnection");
+ return;
+ }
+ ic.sendKeyEvent((KeyEvent) msg.obj);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_INPUT);
}
- ic.sendKeyEvent((KeyEvent)msg.obj);
return;
}
case DO_CLEAR_META_KEY_STATES: {
- InputConnection ic = getInputConnection();
- if (ic == null || !isActive()) {
- Log.w(TAG, "clearMetaKeyStates on inactive InputConnection");
- return;
+ Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#clearMetaKeyStates");
+ try {
+ InputConnection ic = getInputConnection();
+ if (ic == null || !isActive()) {
+ Log.w(TAG, "clearMetaKeyStates on inactive InputConnection");
+ return;
+ }
+ ic.clearMetaKeyStates(msg.arg1);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_INPUT);
}
- ic.clearMetaKeyStates(msg.arg1);
return;
}
case DO_DELETE_SURROUNDING_TEXT: {
- InputConnection ic = getInputConnection();
- if (ic == null || !isActive()) {
- Log.w(TAG, "deleteSurroundingText on inactive InputConnection");
- return;
+ Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#deleteSurroundingText");
+ try {
+ InputConnection ic = getInputConnection();
+ if (ic == null || !isActive()) {
+ Log.w(TAG, "deleteSurroundingText on inactive InputConnection");
+ return;
+ }
+ ic.deleteSurroundingText(msg.arg1, msg.arg2);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_INPUT);
}
- ic.deleteSurroundingText(msg.arg1, msg.arg2);
return;
}
case DO_DELETE_SURROUNDING_TEXT_IN_CODE_POINTS: {
- InputConnection ic = getInputConnection();
- if (ic == null || !isActive()) {
- Log.w(TAG, "deleteSurroundingTextInCodePoints on inactive InputConnection");
- return;
+ Trace.traceBegin(Trace.TRACE_TAG_INPUT,
+ "InputConnection#deleteSurroundingTextInCodePoints");
+ try {
+ InputConnection ic = getInputConnection();
+ if (ic == null || !isActive()) {
+ Log.w(TAG, "deleteSurroundingTextInCodePoints on inactive InputConnection");
+ return;
+ }
+ ic.deleteSurroundingTextInCodePoints(msg.arg1, msg.arg2);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_INPUT);
}
- ic.deleteSurroundingTextInCodePoints(msg.arg1, msg.arg2);
return;
}
case DO_BEGIN_BATCH_EDIT: {
- InputConnection ic = getInputConnection();
- if (ic == null || !isActive()) {
- Log.w(TAG, "beginBatchEdit on inactive InputConnection");
- return;
+ Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#beginBatchEdit");
+ try {
+ InputConnection ic = getInputConnection();
+ if (ic == null || !isActive()) {
+ Log.w(TAG, "beginBatchEdit on inactive InputConnection");
+ return;
+ }
+ ic.beginBatchEdit();
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_INPUT);
}
- ic.beginBatchEdit();
return;
}
case DO_END_BATCH_EDIT: {
- InputConnection ic = getInputConnection();
- if (ic == null || !isActive()) {
- Log.w(TAG, "endBatchEdit on inactive InputConnection");
- return;
+ Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#endBatchEdit");
+ try {
+ InputConnection ic = getInputConnection();
+ if (ic == null || !isActive()) {
+ Log.w(TAG, "endBatchEdit on inactive InputConnection");
+ return;
+ }
+ ic.endBatchEdit();
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_INPUT);
}
- ic.endBatchEdit();
return;
}
case DO_PERFORM_PRIVATE_COMMAND: {
final SomeArgs args = (SomeArgs) msg.obj;
+ Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#performPrivateCommand");
try {
final String action = (String) args.arg1;
final Bundle data = (Bundle) args.arg2;
@@ -541,25 +694,31 @@ public abstract class IInputConnectionWrapper extends IInputContext.Stub {
}
ic.performPrivateCommand(action, data);
} finally {
+ Trace.traceEnd(Trace.TRACE_TAG_INPUT);
args.recycle();
}
return;
}
case DO_REQUEST_UPDATE_CURSOR_ANCHOR_INFO: {
- final IIntResultCallback callback = (IIntResultCallback) msg.obj;
- final InputConnection ic = getInputConnection();
- final boolean result;
- if (ic == null || !isActive()) {
- Log.w(TAG, "requestCursorAnchorInfo on inactive InputConnection");
- result = false;
- } else {
- result = ic.requestCursorUpdates(msg.arg1);
- }
+ Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#requestCursorUpdates");
try {
- callback.onResult(result ? 1 : 0);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed to return the result to requestCursorUpdates()."
- + " result=" + result, e);
+ final IIntResultCallback callback = (IIntResultCallback) msg.obj;
+ final InputConnection ic = getInputConnection();
+ final boolean result;
+ if (ic == null || !isActive()) {
+ Log.w(TAG, "requestCursorAnchorInfo on inactive InputConnection");
+ result = false;
+ } else {
+ result = ic.requestCursorUpdates(msg.arg1);
+ }
+ try {
+ callback.onResult(result ? 1 : 0);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed to return the result to requestCursorUpdates()."
+ + " result=" + result, e);
+ }
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_INPUT);
}
return;
}
@@ -571,6 +730,7 @@ public abstract class IInputConnectionWrapper extends IInputContext.Stub {
if (isFinished()) {
return;
}
+ Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#closeConnection");
try {
InputConnection ic = getInputConnection();
// Note we do NOT check isActive() here, because this is safe
@@ -590,12 +750,14 @@ public abstract class IInputConnectionWrapper extends IInputContext.Stub {
mInputConnection = null;
mFinished = true;
}
+ Trace.traceEnd(Trace.TRACE_TAG_INPUT);
}
return;
}
case DO_COMMIT_CONTENT: {
final int flags = msg.arg1;
SomeArgs args = (SomeArgs) msg.obj;
+ Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#commitContent");
try {
final IIntResultCallback callback = (IIntResultCallback) args.arg3;
final InputConnection ic = getInputConnection();
@@ -620,6 +782,7 @@ public abstract class IInputConnectionWrapper extends IInputContext.Stub {
+ " result=" + result, e);
}
} finally {
+ Trace.traceEnd(Trace.TRACE_TAG_INPUT);
args.recycle();
}
return;
diff --git a/core/java/com/android/internal/view/IInputMethodManager.aidl b/core/java/com/android/internal/view/IInputMethodManager.aidl
index 33abbe82c109..e78ed4e211a7 100644
--- a/core/java/com/android/internal/view/IInputMethodManager.aidl
+++ b/core/java/com/android/internal/view/IInputMethodManager.aidl
@@ -24,6 +24,7 @@ import android.view.inputmethod.EditorInfo;
import com.android.internal.view.InputBindResult;
import com.android.internal.view.IInputContext;
import com.android.internal.view.IInputMethodClient;
+import com.android.internal.inputmethod.IInputBindResultResultCallback;
/**
* Public interface to the global input method manager, used by all client
@@ -48,14 +49,15 @@ interface IInputMethodManager {
// If windowToken is null, this just does startInput(). Otherwise this reports that a window
// has gained focus, and if 'attribute' is non-null then also does startInput.
// @NonNull
- InputBindResult startInputOrWindowGainedFocus(
+ void startInputOrWindowGainedFocus(
/* @StartInputReason */ int startInputReason,
in IInputMethodClient client, in IBinder windowToken,
/* @StartInputFlags */ int startInputFlags,
/* @android.view.WindowManager.LayoutParams.SoftInputModeFlags */ int softInputMode,
int windowFlags, in EditorInfo attribute, IInputContext inputContext,
/* @InputConnectionInspector.MissingMethodFlags */ int missingMethodFlags,
- int unverifiedTargetSdkVersion);
+ int unverifiedTargetSdkVersion,
+ in IInputBindResultResultCallback inputBindResult);
void showInputMethodPickerFromClient(in IInputMethodClient client,
int auxiliarySubtypeMode);
diff --git a/core/java/com/android/internal/view/InputConnectionWrapper.java b/core/java/com/android/internal/view/InputConnectionWrapper.java
index 8c763a6efe54..b70348a95384 100644
--- a/core/java/com/android/internal/view/InputConnectionWrapper.java
+++ b/core/java/com/android/internal/view/InputConnectionWrapper.java
@@ -24,6 +24,9 @@ import android.inputmethodservice.AbstractInputMethodService;
import android.os.Bundle;
import android.os.Handler;
import android.os.RemoteException;
+import android.util.imetracing.ImeTracing;
+import android.util.imetracing.InputConnectionHelper;
+import android.util.proto.ProtoOutputStream;
import android.view.KeyEvent;
import android.view.inputmethod.CompletionInfo;
import android.view.inputmethod.CorrectionInfo;
@@ -87,8 +90,18 @@ public class InputConnectionWrapper implements InputConnection {
} catch (RemoteException e) {
return null;
}
- return Completable.getResultOrNull(
+ CharSequence result = Completable.getResultOrNull(
value, TAG, "getTextAfterCursor()", mCancellationGroup, MAX_WAIT_TIME_MILLIS);
+
+ final AbstractInputMethodService inputMethodService = mInputMethodService.get();
+ if (inputMethodService != null && ImeTracing.getInstance().isEnabled()) {
+ ProtoOutputStream icProto = InputConnectionHelper.buildGetTextAfterCursorProto(length,
+ flags, result);
+ ImeTracing.getInstance().triggerServiceDump(TAG + "#getTextAfterCursor",
+ inputMethodService, icProto);
+ }
+
+ return result;
}
/**
@@ -107,8 +120,18 @@ public class InputConnectionWrapper implements InputConnection {
} catch (RemoteException e) {
return null;
}
- return Completable.getResultOrNull(
+ CharSequence result = Completable.getResultOrNull(
value, TAG, "getTextBeforeCursor()", mCancellationGroup, MAX_WAIT_TIME_MILLIS);
+
+ final AbstractInputMethodService inputMethodService = mInputMethodService.get();
+ if (inputMethodService != null && ImeTracing.getInstance().isEnabled()) {
+ ProtoOutputStream icProto = InputConnectionHelper.buildGetTextBeforeCursorProto(length,
+ flags, result);
+ ImeTracing.getInstance().triggerServiceDump(TAG + "#getTextBeforeCursor",
+ inputMethodService, icProto);
+ }
+
+ return result;
}
@AnyThread
@@ -127,8 +150,18 @@ public class InputConnectionWrapper implements InputConnection {
} catch (RemoteException e) {
return null;
}
- return Completable.getResultOrNull(
+ CharSequence result = Completable.getResultOrNull(
value, TAG, "getSelectedText()", mCancellationGroup, MAX_WAIT_TIME_MILLIS);
+
+ final AbstractInputMethodService inputMethodService = mInputMethodService.get();
+ if (inputMethodService != null && ImeTracing.getInstance().isEnabled()) {
+ ProtoOutputStream icProto = InputConnectionHelper.buildGetSelectedTextProto(flags,
+ result);
+ ImeTracing.getInstance().triggerServiceDump(TAG + "#getSelectedText",
+ inputMethodService, icProto);
+ }
+
+ return result;
}
/**
@@ -161,8 +194,18 @@ public class InputConnectionWrapper implements InputConnection {
} catch (RemoteException e) {
return null;
}
- return Completable.getResultOrNull(
+ SurroundingText result = Completable.getResultOrNull(
value, TAG, "getSurroundingText()", mCancellationGroup, MAX_WAIT_TIME_MILLIS);
+
+ final AbstractInputMethodService inputMethodService = mInputMethodService.get();
+ if (inputMethodService != null && ImeTracing.getInstance().isEnabled()) {
+ ProtoOutputStream icProto = InputConnectionHelper.buildGetSurroundingTextProto(
+ beforeLength, afterLength, flags, result);
+ ImeTracing.getInstance().triggerServiceDump(TAG + "#getSurroundingText",
+ inputMethodService, icProto);
+ }
+
+ return result;
}
@AnyThread
@@ -177,8 +220,18 @@ public class InputConnectionWrapper implements InputConnection {
} catch (RemoteException e) {
return 0;
}
- return Completable.getResultOrZero(
+ int result = Completable.getResultOrZero(
value, TAG, "getCursorCapsMode()", mCancellationGroup, MAX_WAIT_TIME_MILLIS);
+
+ final AbstractInputMethodService inputMethodService = mInputMethodService.get();
+ if (inputMethodService != null && ImeTracing.getInstance().isEnabled()) {
+ ProtoOutputStream icProto = InputConnectionHelper.buildGetCursorCapsModeProto(
+ reqModes, result);
+ ImeTracing.getInstance().triggerServiceDump(TAG + "#getCursorCapsMode",
+ inputMethodService, icProto);
+ }
+
+ return result;
}
@AnyThread
@@ -193,8 +246,18 @@ public class InputConnectionWrapper implements InputConnection {
} catch (RemoteException e) {
return null;
}
- return Completable.getResultOrNull(
+ ExtractedText result = Completable.getResultOrNull(
value, TAG, "getExtractedText()", mCancellationGroup, MAX_WAIT_TIME_MILLIS);
+
+ final AbstractInputMethodService inputMethodService = mInputMethodService.get();
+ if (inputMethodService != null && ImeTracing.getInstance().isEnabled()) {
+ ProtoOutputStream icProto = InputConnectionHelper.buildGetExtractedTextProto(
+ request, flags, result);
+ ImeTracing.getInstance().triggerServiceDump(TAG + "#getExtractedText",
+ inputMethodService, icProto);
+ }
+
+ return result;
}
@AnyThread
diff --git a/core/java/com/android/internal/widget/EditableInputConnection.java b/core/java/com/android/internal/widget/EditableInputConnection.java
index ff3543c837eb..6cdf0df17b65 100644
--- a/core/java/com/android/internal/widget/EditableInputConnection.java
+++ b/core/java/com/android/internal/widget/EditableInputConnection.java
@@ -16,20 +16,35 @@
package com.android.internal.widget;
+import static android.view.inputmethod.InputConnectionProto.CURSOR_CAPS_MODE;
+import static android.view.inputmethod.InputConnectionProto.EDITABLE_TEXT;
+import static android.view.inputmethod.InputConnectionProto.SELECTED_TEXT;
+import static android.view.inputmethod.InputConnectionProto.SELECTED_TEXT_END;
+import static android.view.inputmethod.InputConnectionProto.SELECTED_TEXT_START;
+
import android.compat.annotation.UnsupportedAppUsage;
import android.os.Bundle;
import android.text.Editable;
+import android.text.Selection;
import android.text.method.KeyListener;
import android.util.Log;
+import android.util.imetracing.InputConnectionHelper;
+import android.util.proto.ProtoOutputStream;
import android.view.inputmethod.BaseInputConnection;
import android.view.inputmethod.CompletionInfo;
import android.view.inputmethod.CorrectionInfo;
+import android.view.inputmethod.DumpableInputConnection;
import android.view.inputmethod.ExtractedText;
import android.view.inputmethod.ExtractedTextRequest;
import android.view.inputmethod.InputConnection;
import android.widget.TextView;
-public class EditableInputConnection extends BaseInputConnection {
+/**
+ * Base class for an editable InputConnection instance. This is created by {@link TextView} or
+ * {@link EditText}.
+ */
+public class EditableInputConnection extends BaseInputConnection
+ implements DumpableInputConnection {
private static final boolean DEBUG = false;
private static final String TAG = "EditableInputConnection";
@@ -222,4 +237,28 @@ public class EditableInputConnection extends BaseInputConnection {
}
return true;
}
+
+ @Override
+ public void dumpDebug(ProtoOutputStream proto, long fieldId) {
+ final long token = proto.start(fieldId);
+ CharSequence editableText = mTextView.getText();
+ CharSequence selectedText = getSelectedText(0 /* flags */);
+ if (InputConnectionHelper.DUMP_TEXT) {
+ if (editableText != null) {
+ proto.write(EDITABLE_TEXT, editableText.toString());
+ }
+ if (selectedText != null) {
+ proto.write(SELECTED_TEXT, selectedText.toString());
+ }
+ }
+ final Editable content = getEditable();
+ if (content != null) {
+ int start = Selection.getSelectionStart(content);
+ int end = Selection.getSelectionEnd(content);
+ proto.write(SELECTED_TEXT_START, start);
+ proto.write(SELECTED_TEXT_END, end);
+ }
+ proto.write(CURSOR_CAPS_MODE, getCursorCapsMode(0));
+ proto.end(token);
+ }
}
diff --git a/core/java/com/android/internal/widget/LocalImageResolver.java b/core/java/com/android/internal/widget/LocalImageResolver.java
index b4e108faee2d..3f205c785258 100644
--- a/core/java/com/android/internal/widget/LocalImageResolver.java
+++ b/core/java/com/android/internal/widget/LocalImageResolver.java
@@ -16,69 +16,61 @@
package com.android.internal.widget;
-import android.annotation.Nullable;
import android.content.Context;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.graphics.drawable.BitmapDrawable;
+import android.graphics.ImageDecoder;
+import android.graphics.drawable.AnimatedImageDrawable;
import android.graphics.drawable.Drawable;
import android.net.Uri;
-import android.util.Log;
+import android.util.Size;
import java.io.IOException;
-import java.io.InputStream;
-/**
- * A class to extract Bitmaps from a MessagingStyle message.
- */
+/** A class to extract Drawables from a MessagingStyle/ConversationStyle message. */
public class LocalImageResolver {
private static final String TAG = LocalImageResolver.class.getSimpleName();
private static final int MAX_SAFE_ICON_SIZE_PX = 480;
- @Nullable
public static Drawable resolveImage(Uri uri, Context context) throws IOException {
- BitmapFactory.Options onlyBoundsOptions = getBoundsOptionsForImage(uri, context);
- if ((onlyBoundsOptions.outWidth == -1) || (onlyBoundsOptions.outHeight == -1)) {
- return null;
- }
-
- int originalSize =
- (onlyBoundsOptions.outHeight > onlyBoundsOptions.outWidth)
- ? onlyBoundsOptions.outHeight
- : onlyBoundsOptions.outWidth;
-
- double ratio = (originalSize > MAX_SAFE_ICON_SIZE_PX)
- ? (originalSize / MAX_SAFE_ICON_SIZE_PX)
- : 1.0;
-
- BitmapFactory.Options bitmapOptions = new BitmapFactory.Options();
- bitmapOptions.inSampleSize = getPowerOfTwoForSampleRatio(ratio);
- InputStream input = context.getContentResolver().openInputStream(uri);
- Bitmap bitmap = BitmapFactory.decodeStream(input, null, bitmapOptions);
- input.close();
- return new BitmapDrawable(context.getResources(), bitmap);
+ final ImageDecoder.Source source =
+ ImageDecoder.createSource(context.getContentResolver(), uri);
+ final Drawable drawable =
+ ImageDecoder.decodeDrawable(source, LocalImageResolver::onHeaderDecoded);
+ return drawable;
}
- private static BitmapFactory.Options getBoundsOptionsForImage(Uri uri, Context context)
+ public static Drawable resolveImage(Uri uri, Context context, int maxWidth, int maxHeight)
throws IOException {
- BitmapFactory.Options onlyBoundsOptions = new BitmapFactory.Options();
- try (InputStream input = context.getContentResolver().openInputStream(uri)) {
- if (input == null) {
- throw new IllegalArgumentException();
+ final ImageDecoder.Source source =
+ ImageDecoder.createSource(context.getContentResolver(), uri);
+ return ImageDecoder.decodeDrawable(source, (decoder, info, unused) -> {
+ final Size size = info.getSize();
+ if (size.getWidth() > size.getHeight()) {
+ if (size.getWidth() > maxWidth) {
+ final int targetHeight = size.getHeight() * maxWidth / size.getWidth();
+ decoder.setTargetSize(maxWidth, targetHeight);
+ }
+ } else {
+ if (size.getHeight() > maxHeight) {
+ final int targetWidth = size.getWidth() * maxHeight / size.getHeight();
+ decoder.setTargetSize(targetWidth, maxHeight);
+ }
}
- onlyBoundsOptions.inJustDecodeBounds = true;
- BitmapFactory.decodeStream(input, null, onlyBoundsOptions);
- } catch (IllegalArgumentException iae) {
- onlyBoundsOptions.outWidth = -1;
- onlyBoundsOptions.outHeight = -1;
- Log.e(TAG, "error loading image", iae);
- }
- return onlyBoundsOptions;
+ });
}
private static int getPowerOfTwoForSampleRatio(double ratio) {
- int k = Integer.highestOneBit((int) Math.floor(ratio));
+ final int k = Integer.highestOneBit((int) Math.floor(ratio));
return Math.max(1, k);
}
+
+ private static void onHeaderDecoded(ImageDecoder decoder, ImageDecoder.ImageInfo info,
+ ImageDecoder.Source source) {
+ final Size size = info.getSize();
+ final int originalSize = Math.max(size.getHeight(), size.getWidth());
+ final double ratio = (originalSize > MAX_SAFE_ICON_SIZE_PX)
+ ? originalSize * 1f / MAX_SAFE_ICON_SIZE_PX
+ : 1.0;
+ decoder.setTargetSampleSize(getPowerOfTwoForSampleRatio(ratio));
+ }
}
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index b562ef838633..9712b4e794c5 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -311,6 +311,15 @@ public class LockPatternUtils {
return getDevicePolicyManager().getPasswordMinimumMetrics(userId);
}
+ /**
+ * Returns the effective complexity for the user.
+ * @param userId The user to return the complexity for.
+ * @return complexity level for the user.
+ */
+ public @DevicePolicyManager.PasswordComplexity int getRequestedPasswordComplexity(int userId) {
+ return getDevicePolicyManager().getAggregatedPasswordComplexityForUser(userId);
+ }
+
public int getRequestedPasswordQuality(int userId) {
return getDevicePolicyManager().getPasswordQuality(null, userId);
}
diff --git a/core/java/com/android/internal/widget/LockPatternView.java b/core/java/com/android/internal/widget/LockPatternView.java
index 4ddc782aacb4..bad21d28416b 100644
--- a/core/java/com/android/internal/widget/LockPatternView.java
+++ b/core/java/com/android/internal/widget/LockPatternView.java
@@ -1090,6 +1090,20 @@ public class LockPatternView extends View {
}
}
+ /**
+ * Change theme colors
+ * @param regularColor The dot color
+ * @param successColor Color used when pattern is correct
+ * @param errorColor Color used when authentication fails
+ */
+ public void setColors(int regularColor, int successColor, int errorColor) {
+ mRegularColor = regularColor;
+ mErrorColor = errorColor;
+ mSuccessColor = successColor;
+ mPathPaint.setColor(regularColor);
+ invalidate();
+ }
+
private float getCenterXForColumn(int column) {
return mPaddingLeft + column * mSquareWidth + mSquareWidth / 2f;
}
diff --git a/core/jni/android_media_MicrophoneInfo.cpp b/core/jni/android_media_MicrophoneInfo.cpp
index 5bd808b67c57..b70190fc5ec3 100644
--- a/core/jni/android_media_MicrophoneInfo.cpp
+++ b/core/jni/android_media_MicrophoneInfo.cpp
@@ -56,8 +56,8 @@ jint convertMicrophoneInfoFromNative(JNIEnv *env, jobject *jMicrophoneInfo,
jobject jFrequencyResponses = NULL;
jobject jChannelMappings = NULL;
- jDeviceId = env->NewStringUTF(String8(microphoneInfo->getDeviceId()).string());
- jAddress = env->NewStringUTF(String8(microphoneInfo->getAddress()).string());
+ jDeviceId = env->NewStringUTF(microphoneInfo->getDeviceId().c_str());
+ jAddress = env->NewStringUTF(microphoneInfo->getAddress().c_str());
if (microphoneInfo->getGeometricLocation().size() != 3 ||
microphoneInfo->getOrientation().size() != 3) {
jStatus = nativeToJavaStatus(BAD_VALUE);
diff --git a/core/proto/OWNERS b/core/proto/OWNERS
index 5eeeb048e6d6..748b4b4f5743 100644
--- a/core/proto/OWNERS
+++ b/core/proto/OWNERS
@@ -26,17 +26,7 @@ hyunyoungs@google.com
# Graphics stats
jreck@google.com
-# Temporary Block to assist in migration
-# Bug: 143080132
-per-file *enums.proto = baligh@google.com, yro@google.com, jeffreyhuang@google.com
-per-file *media_output_enum.proto = baligh@google.com, yro@google.com, jeffreyhuang@google.com
-per-file *networkcapabilities.proto = baligh@google.com, yro@google.com, jeffreyhuang@google.com
-per-file *data_stall_event.proto = baligh@google.com, yro@google.com, jeffreyhuang@google.com
-per-file *procstats_enum.proto = baligh@google.com, yro@google.com, jeffreyhuang@google.com
-per-file *usb.proto = baligh@google.com, yro@google.com, jeffreyhuang@google.com
-per-file *network_stack.proto = baligh@google.com, yro@google.com, jeffreyhuang@google.com
-per-file *tethering.proto = baligh@google.com, yro@google.com, jeffreyhuang@google.com
-per-file *dns_resolver.proto = baligh@google.com, yro@google.com, jeffreyhuang@google.com
-per-file *device_policy.proto = baligh@google.com, yro@google.com, jeffreyhuang@google.com
-per-file *launcher.proto = baligh@google.com, yro@google.com, jeffreyhuang@google.com
-per-file *mediametrics.proto = baligh@google.com, yro@google.com, jeffreyhuang@google.com
+# Accessibility
+pweaver@google.com
+hongmingjin@google.com
+cbrower@google.com
diff --git a/core/proto/android/inputmethodservice/inputmethodservice.proto b/core/proto/android/inputmethodservice/inputmethodservice.proto
index e5d171361695..1f68fb4b513d 100644
--- a/core/proto/android/inputmethodservice/inputmethodservice.proto
+++ b/core/proto/android/inputmethodservice/inputmethodservice.proto
@@ -18,6 +18,7 @@ syntax = "proto2";
import "frameworks/base/core/proto/android/inputmethodservice/softinputwindow.proto";
import "frameworks/base/core/proto/android/view/inputmethod/editorinfo.proto";
+import "frameworks/base/core/proto/android/view/inputmethod/inputconnection.proto";
package android.inputmethodservice;
@@ -51,6 +52,7 @@ message InputMethodServiceProto {
optional int32 status_icon = 25;
optional InsetsProto last_computed_insets = 26;
optional string settings_observer = 27;
+ optional .android.view.inputmethod.InputConnectionCallProto input_connection_call = 28;
message InsetsProto {
optional int32 content_top_insets = 1;
diff --git a/core/proto/android/view/inputmethod/inputconnection.proto b/core/proto/android/view/inputmethod/inputconnection.proto
new file mode 100644
index 000000000000..d1f257ff2c5c
--- /dev/null
+++ b/core/proto/android/view/inputmethod/inputconnection.proto
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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";
+
+import "frameworks/base/core/proto/android/privacy.proto";
+
+package android.view.inputmethod;
+
+option java_multiple_files = true;
+
+/**
+ * Represents a {@link android.view.inputmethod.InputConnection} object.
+ */
+message InputConnectionProto {
+ optional string editable_text = 1 [(.android.privacy).dest = DEST_LOCAL];
+ optional string selected_text = 2 [(.android.privacy).dest = DEST_LOCAL];
+ optional int32 selected_text_start = 3;
+ optional int32 selected_text_end = 4;
+ optional int32 cursor_caps_mode = 5;
+}
+
+/**
+ * Shows information about parameters and result for method calls to
+ * {@link android.view.inputmethod.InputConnection}.
+ */
+message InputConnectionCallProto {
+ oneof method_call {
+ GetTextBeforeCursor get_text_before_cursor = 1;
+ GetTextAfterCursor get_text_after_cursor = 2;
+ GetSelectedText get_selected_text = 3;
+ GetSurroundingText get_surrounding_text = 4;
+ GetCursorCapsMode get_cursor_caps_mode = 5;
+ GetExtractedText get_extracted_text = 6;
+ }
+
+ message GetTextBeforeCursor {
+ optional int32 length = 1;
+ optional int32 flags = 2;
+ optional string result = 3 [(.android.privacy).dest = DEST_LOCAL];
+ }
+
+ message GetTextAfterCursor {
+ optional int32 length = 1;
+ optional int32 flags = 2;
+ optional string result = 3 [(.android.privacy).dest = DEST_LOCAL];
+ }
+
+ message GetSelectedText {
+ optional int32 flags = 1;
+ optional string result = 2 [(.android.privacy).dest = DEST_LOCAL];
+ }
+
+ message GetSurroundingText {
+ optional int32 before_length = 1;
+ optional int32 after_length = 2;
+ optional int32 flags = 3;
+ optional SurroundingText result = 4;
+
+ message SurroundingText {
+ optional string text = 1 [(.android.privacy).dest = DEST_LOCAL];
+ optional int32 selection_start = 2;
+ optional int32 selection_end = 3;
+ optional int32 offset = 4;
+ }
+ }
+
+ message GetCursorCapsMode {
+ optional int32 req_modes = 1;
+ optional int32 result = 2;
+ }
+
+ message GetExtractedText {
+ optional ExtractedTextRequest request = 1;
+ optional int32 flags = 2;
+ optional string result = 3 [(.android.privacy).dest = DEST_LOCAL];
+
+ message ExtractedTextRequest {
+ optional int32 token = 1;
+ optional int32 flags = 2;
+ optional int32 hint_max_lines = 3;
+ optional int32 hint_max_chars = 4;
+ }
+ }
+} \ No newline at end of file
diff --git a/core/proto/android/view/inputmethod/inputmethodeditortrace.proto b/core/proto/android/view/inputmethod/inputmethodeditortrace.proto
index 5c0f341cb9e4..8e4377ca124c 100644
--- a/core/proto/android/view/inputmethod/inputmethodeditortrace.proto
+++ b/core/proto/android/view/inputmethod/inputmethodeditortrace.proto
@@ -24,6 +24,7 @@ import "frameworks/base/core/proto/android/view/viewrootimpl.proto";
import "frameworks/base/core/proto/android/view/insetscontroller.proto";
import "frameworks/base/core/proto/android/view/imeinsetssourceconsumer.proto";
import "frameworks/base/core/proto/android/view/inputmethod/editorinfo.proto";
+import "frameworks/base/core/proto/android/view/inputmethod/inputconnection.proto";
import "frameworks/base/core/proto/android/view/imefocuscontroller.proto";
import "frameworks/base/core/proto/android/server/inputmethod/inputmethodmanagerservice.proto";
@@ -70,6 +71,8 @@ message InputMethodClientsTraceProto {
optional ImeInsetsSourceConsumerProto ime_insets_source_consumer = 5;
optional EditorInfoProto editor_info = 6;
optional ImeFocusControllerProto ime_focus_controller = 7;
+ optional InputConnectionProto input_connection = 8;
+ optional InputConnectionCallProto input_connection_call = 9;
}
}
diff --git a/core/proto/android/view/windowlayoutparams.proto b/core/proto/android/view/windowlayoutparams.proto
index 4bb56f8acfa4..062485d304c3 100644
--- a/core/proto/android/view/windowlayoutparams.proto
+++ b/core/proto/android/view/windowlayoutparams.proto
@@ -35,7 +35,7 @@ message WindowLayoutParamsProto {
optional int32 height = 5;
optional float horizontal_margin = 6;
optional float vertical_margin = 7;
- optional int32 gravity = 8;
+ optional int32 gravity = 8 [(.android.typedef) = "android.view.Gravity.GravityFlags"];
optional int32 soft_input_mode = 9 [(.android.typedef) = "android.view.WindowManager.LayoutParams.SoftInputModeFlags"];
optional .android.graphics.PixelFormatProto.Format format = 10;
optional int32 window_animations = 11;
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 11a821468aa1..62d0a6b0a26f 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -120,6 +120,12 @@
<protected-broadcast android:name="android.app.action.EXIT_DESK_MODE" />
<protected-broadcast android:name="android.app.action.NEXT_ALARM_CLOCK_CHANGED" />
+ <protected-broadcast android:name="android.app.action.USER_ADDED" />
+ <protected-broadcast android:name="android.app.action.USER_REMOVED" />
+ <protected-broadcast android:name="android.app.action.USER_STARTED" />
+ <protected-broadcast android:name="android.app.action.USER_STOPPED" />
+ <protected-broadcast android:name="android.app.action.USER_SWITCHED" />
+
<protected-broadcast android:name="android.app.action.BUGREPORT_SHARING_DECLINED" />
<protected-broadcast android:name="android.app.action.BUGREPORT_FAILED" />
<protected-broadcast android:name="android.app.action.BUGREPORT_SHARE" />
@@ -1809,6 +1815,16 @@
<permission android:name="android.permission.WIFI_UPDATE_USABILITY_STATS_SCORE"
android:protectionLevel="signature|privileged" />
+ <!-- @SystemApi @hide Allows system APK to update Wifi/Cellular coex channels to avoid.
+ <p>Not for use by third-party applications. -->
+ <permission android:name="android.permission.WIFI_UPDATE_COEX_UNSAFE_CHANNELS"
+ android:protectionLevel="signature" />
+
+ <!-- @SystemApi @hide Allows applications to access Wifi/Cellular coex channels being avoided.
+ <p>Not for use by third-party applications. -->
+ <permission android:name="android.permission.WIFI_ACCESS_COEX_UNSAFE_CHANNELS"
+ android:protectionLevel="signature|privileged" />
+
<!-- ======================================= -->
<!-- Permissions for short range, peripheral networks -->
<!-- ======================================= -->
@@ -3104,6 +3120,12 @@
<permission android:name="android.permission.DUMP"
android:protectionLevel="signature|privileged|development" />
+ <!-- Allows an application to start tracing for InputMethod and WindowManager.
+ <p>Not for use by third-party applications.
+ @hide -->
+ <permission android:name="android.permission.CONTROL_UI_TRACING"
+ android:protectionLevel="signature|privileged|development" />
+
<!-- Allows an application to read the low-level system log files.
<p>Not for use by third-party applications, because
Log entries can contain the user's private information. -->
@@ -4190,6 +4212,14 @@
<permission android:name="android.permission.FACTORY_TEST"
android:protectionLevel="signature" />
+ <!-- @hide @TestApi Allows an application to broadcast the intent {@link
+ android.content.Intent#ACTION_CLOSE_SYSTEM_DIALOGS}.
+ <p>Not for use by third-party applications.
+ -->
+ <permission android:name="android.permission.BROADCAST_CLOSE_SYSTEM_DIALOGS"
+ android:protectionLevel="signature|recents" />
+ <uses-permission android:name="android.permission.BROADCAST_CLOSE_SYSTEM_DIALOGS" />
+
<!-- Allows an application to broadcast a notification that an application
package has been removed.
<p>Not for use by third-party applications.
@@ -5225,7 +5255,8 @@
<attribution android:tag="TwilightService" android:label="@string/twilight_service"/>
<!-- Attribution for the Offline LocationTimeZoneProvider, used to detect time zone using
on-device data -->
- <attribution android:tag="OfflineLocationTimeZoneProvider" android:label="@string/offline_location_time_zone_detection_service"/>
+ <attribution android:tag="OfflineLocationTimeZoneProvider"
+ android:label="@string/offline_location_time_zone_detection_service_attribution"/>
<application android:process="system"
android:persistent="true"
diff --git a/core/res/res/layout/notification_template_header.xml b/core/res/res/layout/notification_template_header.xml
index b0ee12a520d9..88998f2167a8 100644
--- a/core/res/res/layout/notification_template_header.xml
+++ b/core/res/res/layout/notification_template_header.xml
@@ -26,6 +26,18 @@
android:theme="@style/Theme.DeviceDefault.Notification"
>
+ <ImageView
+ android:id="@+id/left_icon"
+ android:layout_width="@dimen/notification_left_icon_size"
+ android:layout_height="@dimen/notification_left_icon_size"
+ android:layout_gravity="center_vertical|start"
+ android:layout_marginStart="@dimen/notification_left_icon_start"
+ android:background="@drawable/notification_large_icon_outline"
+ android:importantForAccessibility="no"
+ android:scaleType="centerCrop"
+ android:visibility="gone"
+ />
+
<com.android.internal.widget.CachingIconView
android:id="@+id/icon"
android:layout_width="@dimen/notification_icon_circle_size"
diff --git a/core/res/res/layout/notification_template_material_base.xml b/core/res/res/layout/notification_template_material_base.xml
index 69d4a12f4d69..000638475a10 100644
--- a/core/res/res/layout/notification_template_material_base.xml
+++ b/core/res/res/layout/notification_template_material_base.xml
@@ -23,6 +23,18 @@
android:tag="base"
>
+ <ImageView
+ android:id="@+id/left_icon"
+ android:layout_width="@dimen/notification_left_icon_size"
+ android:layout_height="@dimen/notification_left_icon_size"
+ android:layout_gravity="center_vertical|start"
+ android:layout_marginStart="@dimen/notification_left_icon_start"
+ android:background="@drawable/notification_large_icon_outline"
+ android:importantForAccessibility="no"
+ android:scaleType="centerCrop"
+ android:visibility="gone"
+ />
+
<com.android.internal.widget.CachingIconView
android:id="@+id/icon"
android:layout_width="@dimen/notification_icon_circle_size"
@@ -34,7 +46,7 @@
/>
<LinearLayout
- android:id="@+id/notification_standard_view_column"
+ android:id="@+id/notification_headerless_view_column"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
diff --git a/core/res/res/values-night/colors.xml b/core/res/res/values-night/colors.xml
index 39cdce9cc46b..29f2b6f14b57 100644
--- a/core/res/res/values-night/colors.xml
+++ b/core/res/res/values-night/colors.xml
@@ -26,9 +26,6 @@
<color name="notification_default_color_dark">#ddffffff</color>
- <!-- The background color of a notification card. -->
- <color name="notification_material_background_color">@color/black</color>
-
<color name="chooser_row_divider">@color/list_divider_color_dark</color>
<color name="chooser_gradient_background">@color/loading_gradient_background_color_dark</color>
<color name="chooser_gradient_highlight">@color/loading_gradient_highlight_color_dark</color>
diff --git a/core/res/res/values-night/values.xml b/core/res/res/values-night/values.xml
index 4e6b712f1f5d..952cdd08451c 100644
--- a/core/res/res/values-night/values.xml
+++ b/core/res/res/values-night/values.xml
@@ -25,18 +25,12 @@
<item name="colorControlNormal">?attr/textColorPrimary</item>
<item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item>
<item name="forceDarkAllowed">false</item>
-
- <!-- QS panel background -->
- <item name="colorBackgroundFloating">@color/black</item>
-
- <!-- volume background -->
- <item name="panelColorBackground">@color/material_grey_800</item>
</style>
<style name="Theme.DeviceDefault.QuickSettings.Dialog" parent="Theme.DeviceDefault.Dialog" />
<style name="TextAppearance.Material.Notification">
- <item name="textColor">@color/notification_secondary_text_color_dark</item>
+ <item name="textColor">?attr/textColorPrimary</item>
<item name="textSize">@dimen/notification_text_size</item>
</style>
</resources> \ No newline at end of file
diff --git a/core/res/res/values/colors.xml b/core/res/res/values/colors.xml
index 1242c6dc8217..0079d8cd0276 100644
--- a/core/res/res/values/colors.xml
+++ b/core/res/res/values/colors.xml
@@ -143,8 +143,6 @@
<color name="notification_default_color_dark">@color/primary_text_default_material_light</color>
<color name="notification_default_color_light">#a3202124</color>
- <color name="notification_material_background_color">#ffffffff</color>
-
<color name="notification_default_color">#757575</color> <!-- Gray 600 -->
<color name="notification_action_button_text_color">@color/notification_default_color</color>
diff --git a/core/res/res/values/colors_device_defaults.xml b/core/res/res/values/colors_device_defaults.xml
index 7a8f411992ce..310ca893ac39 100644
--- a/core/res/res/values/colors_device_defaults.xml
+++ b/core/res/res/values/colors_device_defaults.xml
@@ -37,10 +37,10 @@
<color name="accent_device_default_dark">@color/accent_material_dark</color>
<color name="accent_device_default">@color/accent_device_default_light</color>
- <color name="background_device_default_dark">@color/background_material_dark</color>
- <color name="background_device_default_light">@color/background_material_light</color>
- <color name="background_floating_device_default_dark">@color/background_floating_material_dark</color>
- <color name="background_floating_device_default_light">@color/background_floating_material_light</color>
+ <color name="background_device_default_dark">#1A1A1A</color>
+ <color name="background_device_default_light">#F2F2F2</color>
+ <color name="background_floating_device_default_dark">#0D0D0D</color>
+ <color name="background_floating_device_default_light">#CCCCCC</color>
<!-- Error color -->
<color name="error_color_device_default_dark">@color/error_color_material_dark</color>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index c9f140df68cb..37c3adbe5fcc 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1559,6 +1559,14 @@
<!-- Class name of WallpaperManagerService. -->
<string name="config_wallpaperManagerServiceName" translatable="false">com.android.server.wallpaper.WallpaperManagerService</string>
+ <!-- Specifies priority of automatic time sources. Suggestions from higher entries in the list
+ take precedence over lower ones.
+ See com.android.server.timedetector.TimeDetectorStrategy for available sources. -->
+ <string-array name="config_autoTimeSourcesPriority">
+ <item>telephony</item>
+ <item>network</item>
+ </string-array>
+
<!-- Enables the TimeZoneRuleManager service. This is the global switch for the updateable time
zone update mechanism. -->
<bool name="config_enableUpdateableTimeZoneRules">false</bool>
@@ -4239,6 +4247,35 @@
If non-positive, then the refresh rate is unchanged even if thresholds are configured. -->
<integer name="config_defaultRefreshRateInZone">0</integer>
+ <!-- The display uses different gamma curves for different refresh rates. It's hard for panel
+ vendor to tune the curves to have exact same brightness for different refresh rate. So
+ flicker could be observed at switch time. The issue can be observed on the screen with
+ even full white content at the high brightness. To prevent flickering, we support fixed
+ refresh rates if the display and ambient brightness are equal to or above the provided
+ thresholds. You can define multiple threshold levels as higher brightness environments
+ may have lower display brightness requirements for the flickering is visible. And the
+ high brightness environment could have higher threshold.
+ For example, fixed refresh rate if
+ display brightness >= disp0 && ambient brightness >= amb0
+ || display brightness >= disp1 && ambient brightness >= amb1 -->
+ <integer-array translatable="false" name="config_highDisplayBrightnessThresholdsOfFixedRefreshRate">
+ <!--
+ <item>disp0</item>
+ <item>disp1</item>
+ -->
+ </integer-array>
+
+ <integer-array translatable="false" name="config_highAmbientBrightnessThresholdsOfFixedRefreshRate">
+ <!--
+ <item>amb0</item>
+ <item>amb1</item>
+ -->
+ </integer-array>
+
+ <!-- Default refresh rate in the high zone defined by brightness and ambient thresholds.
+ If non-positive, then the refresh rate is unchanged even if thresholds are configured. -->
+ <integer name="config_fixedRefreshRateInHighZone">0</integer>
+
<!-- The type of the light sensor to be used by the display framework for things like
auto-brightness. If unset, then it just gets the default sensor of type TYPE_LIGHT. -->
<string name="config_displayLightSensorType" translatable="false" />
@@ -4522,4 +4559,7 @@
<!-- If true, hide the display cutout with display area -->
<bool name="config_hideDisplayCutoutWithDisplayArea">false</bool>
+
+ <!-- Indicates that default fitness tracker app needs to request sensor and location permissions. -->
+ <bool name="config_trackerAppNeedsPermissions">false</bool>
</resources>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 19591f6a666f..4bcabff109ea 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -714,6 +714,10 @@
<dimen name="notification_right_icon_headerless_margin">12dp</dimen>
<!-- The top margin of the right icon in the "big" notification states -->
<dimen name="notification_right_icon_big_margin_top">16dp</dimen>
+ <!-- The size of the left icon -->
+ <dimen name="notification_left_icon_size">@dimen/notification_icon_circle_size</dimen>
+ <!-- The left padding of the left icon -->
+ <dimen name="notification_left_icon_start">@dimen/notification_icon_circle_start</dimen>
<!-- The alpha of a disabled notification button -->
<item type="dimen" format="float" name="notification_action_disabled_alpha">0.5</item>
diff --git a/core/res/res/values/ids.xml b/core/res/res/values/ids.xml
index f77c6f99c063..a12d2a951460 100644
--- a/core/res/res/values/ids.xml
+++ b/core/res/res/values/ids.xml
@@ -194,6 +194,12 @@
<!-- A tag used to save the index where the custom view is stored -->
<item type="id" name="notification_custom_view_index_tag" />
+ <!-- A tag used to store the margin end for this view when the right icon is visible -->
+ <item type="id" name="tag_margin_end_when_icon_gone" />
+
+ <!-- A tag used to store the margin end for this view when the right icon is gone -->
+ <item type="id" name="tag_margin_end_when_icon_visible" />
+
<!-- Marks the "copy to clipboard" button in the ChooserActivity -->
<item type="id" name="chooser_copy_button" />
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 8e3a0cbdd10c..89b986b8fcb8 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -433,9 +433,12 @@
<string name="sensor_notification_service">Sensor Notification Service</string>
<!-- Attribution for Twilight service. [CHAR LIMIT=NONE]-->
<string name="twilight_service">Twilight Service</string>
- <!-- Attribution for Offline LocationTimeZoneDetector service, i.e. one capable of performing
- time zone lookup using geo-spacial information held on the device. [CHAR LIMIT=NONE]-->
- <string name="offline_location_time_zone_detection_service">Offline Time Zone Detection Service</string>
+ <!-- Attribution for the Offline LocationTimeZoneProvider service, i.e. the service capable of
+ performing time zone detection using time zone geospatial information held on the device.
+ This text is shown in UIs related to an application name to help users and developers to
+ understand which sub-unit of an application is requesting permissions and using power.
+ [CHAR LIMIT=NONE]-->
+ <string name="offline_location_time_zone_detection_service_attribution">Time Zone Detector (No connectivity)</string>
<!-- Factory reset warning dialog strings--> <skip />
<!-- Shows up in the dialog's title to warn about an impeding factory reset. [CHAR LIMIT=NONE] -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 40aae9e4e085..e96439250696 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -218,7 +218,7 @@
<java-symbol type="id" name="inbox_text6" />
<java-symbol type="id" name="status_bar_latest_event_content" />
<java-symbol type="id" name="notification_main_column" />
- <java-symbol type="id" name="notification_standard_view_column" />
+ <java-symbol type="id" name="notification_headerless_view_column" />
<java-symbol type="id" name="sms_short_code_confirm_message" />
<java-symbol type="id" name="sms_short_code_detail_layout" />
<java-symbol type="id" name="sms_short_code_detail_message" />
@@ -2166,6 +2166,7 @@
<java-symbol type="string" name="config_defaultNetworkScorerPackageName" />
<java-symbol type="string" name="config_persistentDataPackageName" />
<java-symbol type="string" name="config_deviceConfiguratorPackageName" />
+ <java-symbol type="array" name="config_autoTimeSourcesPriority" />
<java-symbol type="bool" name="config_enableGeolocationTimeZoneDetection" />
<java-symbol type="bool" name="config_enablePrimaryLocationTimeZoneOverlay" />
<java-symbol type="string" name="config_primaryLocationTimeZoneProviderPackageName" />
@@ -3002,7 +3003,6 @@
<java-symbol type="string" name="usb_mtp_launch_notification_description" />
<java-symbol type="color" name="notification_action_list" />
- <java-symbol type="color" name="notification_material_background_color" />
<!-- Resolver target actions -->
<java-symbol type="array" name="resolver_target_actions_pin" />
@@ -3070,6 +3070,8 @@
<java-symbol type="dimen" name="notification_media_image_margin_end" />
<java-symbol type="id" name="notification_action_list_margin_target" />
<java-symbol type="dimen" name="notification_action_disabled_alpha" />
+ <java-symbol type="id" name="tag_margin_end_when_icon_visible" />
+ <java-symbol type="id" name="tag_margin_end_when_icon_gone" />
<!-- Override Wake Key Behavior When Screen is Off -->
<java-symbol type="bool" name="config_wakeOnDpadKeyPress" />
@@ -3811,6 +3813,11 @@
<java-symbol type="array" name="config_brightnessThresholdsOfPeakRefreshRate" />
<java-symbol type="array" name="config_ambientThresholdsOfPeakRefreshRate" />
+ <!-- For fixed refresh rate displays in high brightness-->
+ <java-symbol type="integer" name="config_fixedRefreshRateInHighZone" />
+ <java-symbol type="array" name="config_highDisplayBrightnessThresholdsOfFixedRefreshRate" />
+ <java-symbol type="array" name="config_highAmbientBrightnessThresholdsOfFixedRefreshRate" />
+
<!-- For Auto-Brightness -->
<java-symbol type="string" name="config_displayLightSensorType" />
@@ -4103,4 +4110,7 @@
<java-symbol type="string" name="window_magnification_prompt_content" />
<java-symbol type="string" name="turn_on_magnification_settings_action" />
<java-symbol type="string" name="dismiss_action" />
+
+ <java-symbol type="bool" name="config_trackerAppNeedsPermissions"/>
+
</resources>
diff --git a/core/res/res/values/themes_device_defaults.xml b/core/res/res/values/themes_device_defaults.xml
index 1afaf4f7f184..c0731c82bff3 100644
--- a/core/res/res/values/themes_device_defaults.xml
+++ b/core/res/res/values/themes_device_defaults.xml
@@ -215,8 +215,10 @@ easier.
<item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
<item name="colorAccent">@color/accent_device_default_dark</item>
<item name="colorError">@color/error_color_device_default_dark</item>
+ <item name="colorBackground">@color/background_device_default_dark</item>
<item name="colorBackgroundFloating">@color/background_floating_device_default_dark</item>
<item name="colorPopupBackground">?attr/colorBackgroundFloating</item>
+ <item name="panelColorBackground">?attr/colorBackgroundFloating</item>
</style>
<style name="Theme.DeviceDefault" parent="Theme.DeviceDefaultBase" />
@@ -943,8 +945,10 @@ easier.
<item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
<item name="colorAccent">@color/accent_device_default_light</item>
<item name="colorError">@color/error_color_device_default_light</item>
+ <item name="colorBackground">@color/background_device_default_light</item>
<item name="colorBackgroundFloating">@color/background_floating_device_default_light</item>
<item name="colorPopupBackground">?attr/colorBackgroundFloating</item>
+ <item name="panelColorBackground">?attr/colorBackgroundFloating</item>
</style>
<!-- Variant of the DeviceDefault (light) theme that has a solid (opaque) action bar with an
@@ -1517,9 +1521,6 @@ easier.
<!-- Toolbar attributes -->
<item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
-
- <!-- volume background -->
- <item name="panelColorBackground">@color/primary_material_light</item>
</style>
<style name="Theme.DeviceDefault.QuickSettings.Dialog" parent="Theme.DeviceDefault.Light.Dialog">
diff --git a/core/res/res/xml/config_user_types.xml b/core/res/res/xml/config_user_types.xml
index 5fd8a95af64d..71dfc551ccc1 100644
--- a/core/res/res/xml/config_user_types.xml
+++ b/core/res/res/xml/config_user_types.xml
@@ -40,7 +40,7 @@ The following example modifies two AOSP user types (the FULL user android.os.use
and the PROFILE user android.os.usertype.profile.MANAGED) and creates a new PROFILE user type
(com.example.profilename):
-<user-types>
+<user-types version="0">
<full-type name="android.os.usertype.full.SECONDARY" >
<default-restrictions no_sms="true" />
</full-type>
@@ -65,6 +65,11 @@ and the PROFILE user android.os.usertype.profile.MANAGED) and creates a new PROF
<profile-type
name="com.example.profilename"
max-allowed-per-parent="2" />
+
+ <change-user-type
+ from="android.os.usertype.profile.MANAGED"
+ to="com.example.profilename"
+ whenVersionLeq="1" />
</user-types>
Mandatory attributes:
@@ -93,6 +98,10 @@ If this file is updated, the properties of any pre-existing user types will be u
Note, however, that default-restrictions refers to the restrictions applied at the time of user
creation; therefore, the active restrictions of any pre-existing users will not be updated.
+The 'change-user-type' tag should be used in conjunction with the 'version' property of
+'user-types'. It defines a type change for all pre-existing users of 'from' type to the new 'to'
+type, if the former 'user-type's version of device is less than or equal to 'whenVersionLeq'.
+
-->
<user-types>
</user-types>
diff --git a/core/tests/coretests/src/android/app/people/PeopleSpaceTileTest.java b/core/tests/coretests/src/android/app/people/PeopleSpaceTileTest.java
index 27584a597cc8..7552ec404c13 100644
--- a/core/tests/coretests/src/android/app/people/PeopleSpaceTileTest.java
+++ b/core/tests/coretests/src/android/app/people/PeopleSpaceTileTest.java
@@ -21,11 +21,18 @@ import static com.google.common.truth.Truth.assertThat;
import static junit.framework.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.when;
import android.app.Notification;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.LauncherApps;
import android.content.pm.ShortcutInfo;
+import android.graphics.Color;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
import android.net.Uri;
import android.os.UserHandle;
@@ -38,26 +45,37 @@ import androidx.test.runner.AndroidJUnit4;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
@RunWith(AndroidJUnit4.class)
@SmallTest
public class PeopleSpaceTileTest {
private Context mContext;
+ private final Drawable mDrawable = new ColorDrawable(Color.BLUE);
+ private final Icon mIcon = PeopleSpaceTile.convertDrawableToIcon(mDrawable);
+
+ @Mock
+ private LauncherApps mLauncherApps;
@Before
public void setUp() {
mContext = InstrumentationRegistry.getContext();
+ MockitoAnnotations.initMocks(this);
+ when(mLauncherApps.getShortcutIconDrawable(any(), eq(0))).thenReturn(mDrawable);
}
@Test
public void testId() {
PeopleSpaceTile tile = new PeopleSpaceTile.Builder(
- new ShortcutInfo.Builder(mContext, "123").build()).build();
+ new ShortcutInfo.Builder(mContext, "123").build(), mLauncherApps).build();
assertThat(tile.getId()).isEqualTo("123");
- tile = new PeopleSpaceTile.Builder(new ShortcutInfo.Builder(mContext, "123").build()).setId(
- "5").build();
+ tile = new PeopleSpaceTile
+ .Builder(new ShortcutInfo.Builder(mContext, "123").build(), mLauncherApps)
+ .setId("5")
+ .build();
assertThat(tile.getId()).isEqualTo("5");
tile = new PeopleSpaceTile.Builder("12", null, null, null).build();
@@ -67,11 +85,13 @@ public class PeopleSpaceTileTest {
@Test
public void testUserName() {
PeopleSpaceTile tile = new PeopleSpaceTile.Builder(
- new ShortcutInfo.Builder(mContext, "123").build()).build();
+ new ShortcutInfo.Builder(mContext, "123").build(), mLauncherApps).build();
assertThat(tile.getUserName()).isNull();
- tile = new PeopleSpaceTile.Builder(
- new ShortcutInfo.Builder(mContext, "123").build()).setUserName("Name 1").build();
+ tile = new PeopleSpaceTile
+ .Builder(new ShortcutInfo.Builder(mContext, "123").build(), mLauncherApps)
+ .setUserName("Name 1")
+ .build();
assertThat(tile.getUserName()).isEqualTo("Name 1");
tile = new PeopleSpaceTile.Builder(null, "Name 2", null, null).build();
@@ -81,21 +101,19 @@ public class PeopleSpaceTileTest {
@Test
public void testUserIcon() {
PeopleSpaceTile tile = new PeopleSpaceTile.Builder(
- new ShortcutInfo.Builder(mContext, "123").build()).setUserIcon(
- Icon.createWithResource(mContext, 1)).build();
- assertThat(tile.getUserIcon().toString()).isEqualTo(
- Icon.createWithResource(mContext, 1).toString());
+ new ShortcutInfo.Builder(mContext, "123").build(), mLauncherApps).setUserIcon(
+ mIcon).build();
+ assertThat(tile.getUserIcon().toString()).isEqualTo(mIcon.toString());
- tile = new PeopleSpaceTile.Builder("12", null, Icon.createWithResource(mContext, 2),
+ tile = new PeopleSpaceTile.Builder("12", null, mIcon,
null).build();
- assertThat(tile.getUserIcon().toString()).isEqualTo(
- Icon.createWithResource(mContext, 2).toString());
+ assertThat(tile.getUserIcon().toString()).isEqualTo(mIcon.toString());
}
@Test
public void testContactUri() {
PeopleSpaceTile tile = new PeopleSpaceTile.Builder(
- new ShortcutInfo.Builder(mContext, "123").build()).setContactUri(
+ new ShortcutInfo.Builder(mContext, "123").build(), mLauncherApps).setContactUri(
Uri.parse("test")).build();
assertThat(tile.getContactUri()).isEqualTo(Uri.parse("test"));
@@ -103,8 +121,10 @@ public class PeopleSpaceTileTest {
@Test
public void testUid() {
- PeopleSpaceTile tile = new PeopleSpaceTile.Builder(
- new ShortcutInfo.Builder(mContext, "123").build()).setUid(42).build();
+ PeopleSpaceTile tile = new PeopleSpaceTile
+ .Builder(new ShortcutInfo.Builder(mContext, "123").build(), mLauncherApps)
+ .setUid(42)
+ .build();
assertThat(tile.getUid()).isEqualTo(42);
}
@@ -112,12 +132,12 @@ public class PeopleSpaceTileTest {
@Test
public void testPackageName() {
PeopleSpaceTile tile = new PeopleSpaceTile.Builder(
- new ShortcutInfo.Builder(mContext, "123").build()).build();
+ new ShortcutInfo.Builder(mContext, "123").build(), mLauncherApps).build();
// Automatically added by creating a ShortcutInfo.
assertThat(tile.getPackageName()).isEqualTo("com.android.frameworks.coretests");
tile = new PeopleSpaceTile.Builder(
- new ShortcutInfo.Builder(mContext, "123").build()).setPackageName(
+ new ShortcutInfo.Builder(mContext, "123").build(), mLauncherApps).setPackageName(
"package.name").build();
assertThat(tile.getPackageName()).isEqualTo("package.name");
@@ -129,36 +149,39 @@ public class PeopleSpaceTileTest {
@Test
public void testLastInteractionTimestamp() {
PeopleSpaceTile tile = new PeopleSpaceTile.Builder(
- new ShortcutInfo.Builder(mContext, "123").build()).build();
+ new ShortcutInfo.Builder(mContext, "123").build(), mLauncherApps).build();
assertThat(tile.getLastInteractionTimestamp()).isEqualTo(0L);
- tile = new PeopleSpaceTile.Builder(
- new ShortcutInfo.Builder(mContext, "123").build()).setLastInteractionTimestamp(
- 7L).build();
+ tile = new PeopleSpaceTile
+ .Builder(new ShortcutInfo.Builder(mContext, "123").build(), mLauncherApps)
+ .setLastInteractionTimestamp(7L)
+ .build();
assertThat(tile.getLastInteractionTimestamp()).isEqualTo(7L);
}
@Test
public void testImportantConversation() {
PeopleSpaceTile tile = new PeopleSpaceTile.Builder(
- new ShortcutInfo.Builder(mContext, "123").build()).build();
+ new ShortcutInfo.Builder(mContext, "123").build(), mLauncherApps).build();
assertFalse(tile.isImportantConversation());
- tile = new PeopleSpaceTile.Builder(
- new ShortcutInfo.Builder(mContext, "123").build()).setIsImportantConversation(
- true).build();
+ tile = new PeopleSpaceTile
+ .Builder(new ShortcutInfo.Builder(mContext, "123").build(), mLauncherApps)
+ .setIsImportantConversation(true)
+ .build();
assertTrue(tile.isImportantConversation());
}
@Test
public void testHiddenConversation() {
PeopleSpaceTile tile = new PeopleSpaceTile.Builder(
- new ShortcutInfo.Builder(mContext, "123").build()).build();
+ new ShortcutInfo.Builder(mContext, "123").build(), mLauncherApps).build();
assertFalse(tile.isHiddenConversation());
- tile = new PeopleSpaceTile.Builder(
- new ShortcutInfo.Builder(mContext, "123").build()).setIsHiddenConversation(
- true).build();
+ tile = new PeopleSpaceTile
+ .Builder(new ShortcutInfo.Builder(mContext, "123").build(), mLauncherApps)
+ .setIsHiddenConversation(true)
+ .build();
assertTrue(tile.isHiddenConversation());
}
@@ -168,8 +191,10 @@ public class PeopleSpaceTileTest {
StatusBarNotification sbn = new StatusBarNotification("pkg" /* pkg */, "pkg" /* opPkg */,
1 /* id */, "" /* tag */, 0 /* uid */, 0 /* initialPid */, 0 /* score */,
notification, UserHandle.CURRENT, 0 /* postTime */);
- PeopleSpaceTile tile = new PeopleSpaceTile.Builder(
- new ShortcutInfo.Builder(mContext, "123").build()).setNotification(sbn).build();
+ PeopleSpaceTile tile = new PeopleSpaceTile
+ .Builder(new ShortcutInfo.Builder(mContext, "123").build(), mLauncherApps)
+ .setNotification(sbn)
+ .build();
assertThat(tile.getNotification()).isEqualTo(sbn);
}
@@ -177,11 +202,13 @@ public class PeopleSpaceTileTest {
@Test
public void testIntent() {
PeopleSpaceTile tile = new PeopleSpaceTile.Builder(
- new ShortcutInfo.Builder(mContext, "123").build()).build();
+ new ShortcutInfo.Builder(mContext, "123").build(), mLauncherApps).build();
assertThat(tile.getIntent()).isNull();
- tile = new PeopleSpaceTile.Builder(
- new ShortcutInfo.Builder(mContext, "123").build()).setIntent(new Intent()).build();
+ tile = new PeopleSpaceTile
+ .Builder(new ShortcutInfo.Builder(mContext, "123").build(), mLauncherApps)
+ .setIntent(new Intent())
+ .build();
assertThat(tile.getIntent().toString()).isEqualTo(new Intent().toString());
tile = new PeopleSpaceTile.Builder("12", null, null, new Intent()).build();
diff --git a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
index 5871e2e04687..7e992989426d 100644
--- a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
+++ b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
@@ -52,6 +52,7 @@ import android.os.Parcelable;
import android.os.PersistableBundle;
import android.os.RemoteCallback;
import android.os.RemoteException;
+import android.os.SharedMemory;
import android.platform.test.annotations.Presubmit;
import android.view.DisplayAdjustments.FixedRotationAdjustments;
import android.view.DisplayCutout;
@@ -440,7 +441,8 @@ public class TransactionParcelTests {
IUiAutomationConnection iUiAutomationConnection, int i, boolean b, boolean b1,
boolean b2, boolean b3, Configuration configuration,
CompatibilityInfo compatibilityInfo, Map map, Bundle bundle1, String s1,
- AutofillOptions ao, ContentCaptureOptions co, long[] disableCompatChanges)
+ AutofillOptions ao, ContentCaptureOptions co, long[] disableCompatChanges,
+ SharedMemory serializedSystemFontMap)
throws RemoteException {
}
diff --git a/core/tests/coretests/src/android/widget/NumberPickerTest.java b/core/tests/coretests/src/android/widget/NumberPickerTest.java
new file mode 100644
index 000000000000..cab7c89f4ca1
--- /dev/null
+++ b/core/tests/coretests/src/android/widget/NumberPickerTest.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.widget;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.platform.test.annotations.Presubmit;
+import android.view.View;
+import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.accessibility.AccessibilityNodeProvider;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+@Presubmit
+public class NumberPickerTest {
+ @Test
+ public void testAccessibilityFocusedProperty() {
+ final int virtualViewIdIncrement = 1;
+ final int VirtualViewIdInput = 2;
+ final int VirtualViewIdDecrement = 3;
+ final NumberPicker np =
+ new NumberPicker(InstrumentationRegistry.getInstrumentation().getContext());
+ final AccessibilityNodeProvider provider = np.getAccessibilityNodeProvider();
+
+ AccessibilityNodeInfo info = provider.createAccessibilityNodeInfo(View.NO_ID);
+ assertFalse(info.isAccessibilityFocused());
+ info.recycle();
+ provider.performAction(View.NO_ID, AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS, null);
+ info = provider.createAccessibilityNodeInfo(View.NO_ID);
+ assertTrue(info.isAccessibilityFocused());
+ info.recycle();
+
+ info = provider.createAccessibilityNodeInfo(virtualViewIdIncrement);
+ assertFalse(info.isAccessibilityFocused());
+ info.recycle();
+ provider.performAction(
+ virtualViewIdIncrement,
+ AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS,
+ null
+ );
+ info = provider.createAccessibilityNodeInfo(virtualViewIdIncrement);
+ assertTrue(info.isAccessibilityFocused());
+ info.recycle();
+
+ info = provider.createAccessibilityNodeInfo(VirtualViewIdInput);
+ assertFalse(info.isAccessibilityFocused());
+ info.recycle();
+ provider.performAction(
+ VirtualViewIdInput,
+ AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS,
+ null
+ );
+ info = provider.createAccessibilityNodeInfo(VirtualViewIdInput);
+ assertTrue(info.isAccessibilityFocused());
+ info.recycle();
+
+ info = provider.createAccessibilityNodeInfo(VirtualViewIdDecrement);
+ assertFalse(info.isAccessibilityFocused());
+ info.recycle();
+ provider.performAction(
+ VirtualViewIdDecrement,
+ AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS,
+ null
+ );
+ info = provider.createAccessibilityNodeInfo(VirtualViewIdDecrement);
+ assertTrue(info.isAccessibilityFocused());
+ info.recycle();
+ }
+}
diff --git a/core/tests/coretests/src/android/widget/TextViewOnReceiveContentTest.java b/core/tests/coretests/src/android/widget/TextViewOnReceiveContentTest.java
index 7b9283b41ff0..9978648ee32e 100644
--- a/core/tests/coretests/src/android/widget/TextViewOnReceiveContentTest.java
+++ b/core/tests/coretests/src/android/widget/TextViewOnReceiveContentTest.java
@@ -16,11 +16,11 @@
package android.widget;
-import static android.view.OnReceiveContentListener.Payload.SOURCE_AUTOFILL;
-import static android.view.OnReceiveContentListener.Payload.SOURCE_CLIPBOARD;
-import static android.view.OnReceiveContentListener.Payload.SOURCE_DRAG_AND_DROP;
-import static android.view.OnReceiveContentListener.Payload.SOURCE_INPUT_METHOD;
-import static android.view.OnReceiveContentListener.Payload.SOURCE_PROCESS_TEXT;
+import static android.view.ContentInfo.SOURCE_AUTOFILL;
+import static android.view.ContentInfo.SOURCE_CLIPBOARD;
+import static android.view.ContentInfo.SOURCE_DRAG_AND_DROP;
+import static android.view.ContentInfo.SOURCE_INPUT_METHOD;
+import static android.view.ContentInfo.SOURCE_PROCESS_TEXT;
import static android.widget.espresso.TextViewActions.clickOnTextAtIndex;
import static androidx.test.espresso.Espresso.onView;
@@ -41,7 +41,7 @@ import android.content.ClipData;
import android.content.ClipDescription;
import android.net.Uri;
import android.os.Bundle;
-import android.view.OnReceiveContentListener;
+import android.view.ContentInfo;
import android.view.inputmethod.InputConnection;
import android.view.inputmethod.InputConnectionWrapper;
import android.view.inputmethod.InputContentInfo;
@@ -133,8 +133,8 @@ public class TextViewOnReceiveContentTest {
// InputConnection.commitContent.
ClipDescription description = new ClipDescription("", new String[] {"image/gif"});
ClipData clip = new ClipData(description, new ClipData.Item(SAMPLE_CONTENT_URI));
- OnReceiveContentListener.Payload payload =
- new OnReceiveContentListener.Payload.Builder(clip, SOURCE_AUTOFILL).build();
+ ContentInfo payload =
+ new ContentInfo.Builder(clip, SOURCE_AUTOFILL).build();
mDefaultReceiver.onReceiveContent(mEditText, payload);
verify(ic.mMock, times(1))
.commitContent(any(InputContentInfo.class), eq(0), eq(null));
@@ -155,8 +155,8 @@ public class TextViewOnReceiveContentTest {
// Invoke the listener and assert that the InputConnection is not invoked.
ClipDescription description = new ClipDescription("", new String[] {"image/gif"});
ClipData clip = new ClipData(description, new ClipData.Item(SAMPLE_CONTENT_URI));
- OnReceiveContentListener.Payload payload =
- new OnReceiveContentListener.Payload.Builder(clip, SOURCE_AUTOFILL).build();
+ ContentInfo payload =
+ new ContentInfo.Builder(clip, SOURCE_AUTOFILL).build();
mDefaultReceiver.onReceiveContent(mEditText, payload);
verifyZeroInteractions(ic.mMock);
}
@@ -176,20 +176,20 @@ public class TextViewOnReceiveContentTest {
// trigger calls to InputConnection.commitContent.
ClipDescription description = new ClipDescription("", new String[] {"image/gif"});
ClipData clip = new ClipData(description, new ClipData.Item(SAMPLE_CONTENT_URI));
- OnReceiveContentListener.Payload payload =
- new OnReceiveContentListener.Payload.Builder(clip, SOURCE_CLIPBOARD).build();
+ ContentInfo payload =
+ new ContentInfo.Builder(clip, SOURCE_CLIPBOARD).build();
mDefaultReceiver.onReceiveContent(mEditText, payload);
verifyZeroInteractions(ic.mMock);
- payload = new OnReceiveContentListener.Payload.Builder(clip, SOURCE_INPUT_METHOD).build();
+ payload = new ContentInfo.Builder(clip, SOURCE_INPUT_METHOD).build();
mDefaultReceiver.onReceiveContent(mEditText, payload);
verifyZeroInteractions(ic.mMock);
- payload = new OnReceiveContentListener.Payload.Builder(clip, SOURCE_DRAG_AND_DROP).build();
+ payload = new ContentInfo.Builder(clip, SOURCE_DRAG_AND_DROP).build();
mDefaultReceiver.onReceiveContent(mEditText, payload);
verifyZeroInteractions(ic.mMock);
- payload = new OnReceiveContentListener.Payload.Builder(clip, SOURCE_PROCESS_TEXT).build();
+ payload = new ContentInfo.Builder(clip, SOURCE_PROCESS_TEXT).build();
mDefaultReceiver.onReceiveContent(mEditText, payload);
verifyZeroInteractions(ic.mMock);
}
diff --git a/core/tests/hdmitests/Android.bp b/core/tests/hdmitests/Android.bp
index 2194d4b030ce..4755e0ea5259 100644
--- a/core/tests/hdmitests/Android.bp
+++ b/core/tests/hdmitests/Android.bp
@@ -19,6 +19,7 @@ android_test {
static_libs: [
"androidx.test.rules",
"frameworks-base-testutils",
+ "guava-android-testlib",
"truth-prebuilt",
],
libs: ["android.test.runner"],
diff --git a/core/tests/hdmitests/src/android/hardware/hdmi/HdmiDeviceInfoTest.java b/core/tests/hdmitests/src/android/hardware/hdmi/HdmiDeviceInfoTest.java
new file mode 100755
index 000000000000..4c0de629c464
--- /dev/null
+++ b/core/tests/hdmitests/src/android/hardware/hdmi/HdmiDeviceInfoTest.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.hdmi;
+
+import androidx.test.filters.SmallTest;
+
+import com.google.common.testing.EqualsTester;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Tests for {@link HdmiDeviceInfo} */
+@RunWith(JUnit4.class)
+@SmallTest
+public class HdmiDeviceInfoTest {
+
+ @Test
+ public void testEquals() {
+ int logicalAddr = 0x00;
+ int phyAddr = 0x1000;
+ int portId = 1;
+ int deviceType = 0;
+ int vendorId = 0x123456;
+ String displayName = "test device";
+ int powerStatus = HdmiControlManager.POWER_STATUS_TRANSIENT_TO_STANDBY;
+ int deviceId = 3;
+ int adopterId = 2;
+
+ new EqualsTester()
+ .addEqualityGroup(new HdmiDeviceInfo())
+ .addEqualityGroup(
+ new HdmiDeviceInfo(phyAddr, portId), new HdmiDeviceInfo(phyAddr, portId))
+ .addEqualityGroup(
+ new HdmiDeviceInfo(phyAddr, portId, adopterId, deviceId),
+ new HdmiDeviceInfo(phyAddr, portId, adopterId, deviceId))
+ .addEqualityGroup(
+ new HdmiDeviceInfo(
+ logicalAddr, phyAddr, portId, deviceType, vendorId, displayName),
+ new HdmiDeviceInfo(
+ logicalAddr, phyAddr, portId, deviceType, vendorId, displayName))
+ .addEqualityGroup(
+ new HdmiDeviceInfo(
+ logicalAddr,
+ phyAddr,
+ portId,
+ deviceType,
+ vendorId,
+ displayName,
+ powerStatus),
+ new HdmiDeviceInfo(
+ logicalAddr,
+ phyAddr,
+ portId,
+ deviceType,
+ vendorId,
+ displayName,
+ powerStatus))
+ .testEquals();
+ }
+}
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 8406fdf99360..1fb63f04ccf5 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -322,6 +322,7 @@ applications that come with the platform
<permission name="android.permission.DELETE_CACHE_FILES"/>
<permission name="android.permission.DELETE_PACKAGES"/>
<permission name="android.permission.DUMP"/>
+ <permission name="android.permission.CONTROL_UI_TRACING"/>
<permission name="android.permission.ACTIVITY_EMBEDDING"/>
<permission name="android.permission.FORCE_STOP_PACKAGES"/>
<permission name="android.permission.GET_APP_OPS_STATS"/>
diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index a52eca7e0d73..6bcab8a34e2c 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -2749,6 +2749,12 @@
"group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "1105210816": {
+ "message": "Skipping config check in destroyed state %s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_CONFIGURATION",
+ "at": "com\/android\/server\/wm\/ActivityRecord.java"
+ },
"1112047265": {
"message": "finishDrawingWindow: %s mDrawState=%s",
"level": "DEBUG",
diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java
index 36ef0a48fa20..24987daf87b5 100644
--- a/graphics/java/android/graphics/Typeface.java
+++ b/graphics/java/android/graphics/Typeface.java
@@ -81,6 +81,9 @@ public class Typeface {
private static String TAG = "Typeface";
+ /** @hide */
+ public static final boolean ENABLE_LAZY_TYPEFACE_INITIALIZATION = false;
+
private static final NativeAllocationRegistry sRegistry =
NativeAllocationRegistry.createMalloced(
Typeface.class.getClassLoader(), nativeGetReleaseFunc());
@@ -1329,7 +1332,9 @@ public class Typeface {
}
static {
- loadPreinstalledSystemFontMap();
+ if (!ENABLE_LAZY_TYPEFACE_INITIALIZATION) {
+ loadPreinstalledSystemFontMap();
+ }
}
@Override
diff --git a/keystore/java/android/security/AppUriAuthenticationPolicy.java b/keystore/java/android/security/AppUriAuthenticationPolicy.java
index 30f5a94ca0c8..0244ce97c0d4 100644
--- a/keystore/java/android/security/AppUriAuthenticationPolicy.java
+++ b/keystore/java/android/security/AppUriAuthenticationPolicy.java
@@ -28,8 +28,10 @@ import org.xmlpull.v1.XmlSerializer;
import java.io.IOException;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.Map;
import java.util.Objects;
+import java.util.Set;
/**
* The app-URI authentication policy is set by the credential management app. This policy determines
@@ -223,4 +225,17 @@ public final class AppUriAuthenticationPolicy implements Parcelable {
}
}
+ /**
+ * Get the set of aliases found in the policy.
+ *
+ * @hide
+ */
+ public Set<String> getAliases() {
+ Set<String> aliases = new HashSet<>();
+ for (UrisToAliases appsToUris : mAppToUris.values()) {
+ aliases.addAll(appsToUris.getUrisToAliases().values());
+ }
+ return aliases;
+ }
+
}
diff --git a/keystore/java/android/security/IKeyChainService.aidl b/keystore/java/android/security/IKeyChainService.aidl
index 97da3cc6f80f..add52fa5b436 100644
--- a/keystore/java/android/security/IKeyChainService.aidl
+++ b/keystore/java/android/security/IKeyChainService.aidl
@@ -18,6 +18,8 @@ package android.security;
import android.content.pm.StringParceledListSlice;
import android.security.keymaster.KeymasterCertificateChain;
import android.security.keystore.ParcelableKeyGenParameterSpec;
+import android.security.AppUriAuthenticationPolicy;
+import android.net.Uri;
/**
* Caller is required to ensure that {@link KeyStore#unlock
@@ -46,6 +48,7 @@ interface IKeyChainService {
boolean installKeyPair(
in byte[] privateKey, in byte[] userCert, in byte[] certChain, String alias, int uid);
boolean removeKeyPair(String alias);
+ boolean containsKeyPair(String alias);
// APIs used by Settings
boolean deleteCaCertificate(String alias);
@@ -55,6 +58,13 @@ interface IKeyChainService {
boolean containsCaAlias(String alias);
byte[] getEncodedCaCertificate(String alias, boolean includeDeletedSystem);
List<String> getCaCertificateChainAliases(String rootAlias, boolean includeDeletedSystem);
+ void setCredentialManagementApp(String packageName, in AppUriAuthenticationPolicy policy);
+ void updateCredentialManagementAppPolicy(in AppUriAuthenticationPolicy policy);
+ boolean hasCredentialManagementApp();
+ String getCredentialManagementAppPackageName();
+ AppUriAuthenticationPolicy getCredentialManagementAppPolicy();
+ String getPredefinedAliasForPackageAndUri(String packageName, in Uri uri);
+ void removeCredentialManagementApp();
// APIs used by KeyChainActivity
void setGrant(int uid, String alias, boolean value);
diff --git a/libs/WindowManager/Shell/Android.bp b/libs/WindowManager/Shell/Android.bp
index 39e32c694d2e..856c9c2484f3 100644
--- a/libs/WindowManager/Shell/Android.bp
+++ b/libs/WindowManager/Shell/Android.bp
@@ -125,9 +125,10 @@ android_library {
"protolog-lib",
"SettingsLib",
"WindowManager-Shell-proto",
+ "jsr330"
],
kotlincflags: ["-Xjvm-default=enable"],
manifest: "AndroidManifest.xml",
min_sdk_version: "26",
-} \ No newline at end of file
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/animation/FlingAnimationUtils.java b/libs/WindowManager/Shell/src/com/android/wm/shell/animation/FlingAnimationUtils.java
index 357f777e1270..176c620fa119 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/animation/FlingAnimationUtils.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/animation/FlingAnimationUtils.java
@@ -23,6 +23,8 @@ import android.view.ViewPropertyAnimator;
import android.view.animation.Interpolator;
import android.view.animation.PathInterpolator;
+import javax.inject.Inject;
+
/**
* Utility class to calculate general fling animation when the finger is released.
*/
@@ -368,6 +370,7 @@ public class FlingAnimationUtils {
float mX2;
float mY2;
+ @Inject
public Builder(DisplayMetrics displayMetrics) {
mDisplayMetrics = displayMetrics;
reset();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPair.java b/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPair.java
index f199072f7bca..d3032f83fc1c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPair.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPair.java
@@ -136,13 +136,6 @@ class AppPair implements ShellTaskOrganizer.TaskListener {
mAppPairLayout = null;
}
- void setVisible(boolean visible) {
- if (mAppPairLayout == null) {
- return;
- }
- mAppPairLayout.setDividerVisibility(visible);
- }
-
@Override
public void onTaskAppeared(ActivityManager.RunningTaskInfo taskInfo, SurfaceControl leash) {
if (mRootTaskInfo == null || taskInfo.taskId == mRootTaskInfo.taskId) {
@@ -160,32 +153,41 @@ class AppPair implements ShellTaskOrganizer.TaskListener {
if (mTaskLeash1 == null || mTaskLeash2 == null) return;
- setVisible(true);
+ mAppPairLayout.init();
final SurfaceControl dividerLeash = mAppPairLayout.getDividerLeash();
final Rect dividerBounds = mAppPairLayout.getDividerBounds();
// TODO: Is there more we need to do here?
- mSyncQueue.runInSync(t -> t
- .setPosition(mTaskLeash1, mTaskInfo1.positionInParent.x,
- mTaskInfo1.positionInParent.y)
- .setPosition(mTaskLeash2, mTaskInfo2.positionInParent.x,
- mTaskInfo2.positionInParent.y)
- .setLayer(dividerLeash, Integer.MAX_VALUE)
- .setPosition(dividerLeash, dividerBounds.left, dividerBounds.top)
- .show(mRootTaskLeash)
- .show(dividerLeash)
- .show(mTaskLeash1)
- .show(mTaskLeash2));
+ mSyncQueue.runInSync(t -> {
+ t.setPosition(mTaskLeash1, mTaskInfo1.positionInParent.x,
+ mTaskInfo1.positionInParent.y)
+ .setPosition(mTaskLeash2, mTaskInfo2.positionInParent.x,
+ mTaskInfo2.positionInParent.y)
+ .setLayer(dividerLeash, Integer.MAX_VALUE)
+ .setPosition(dividerLeash, dividerBounds.left, dividerBounds.top)
+ .show(mRootTaskLeash)
+ .show(mTaskLeash1)
+ .show(mTaskLeash2);
+ });
}
@Override
public void onTaskInfoChanged(ActivityManager.RunningTaskInfo taskInfo) {
if (taskInfo.taskId == getRootTaskId()) {
+ if (mRootTaskInfo.isVisible != taskInfo.isVisible) {
+ mSyncQueue.runInSync(t -> {
+ if (taskInfo.isVisible) {
+ t.show(mRootTaskLeash);
+ } else {
+ t.hide(mRootTaskLeash);
+ }
+ });
+ }
mRootTaskInfo = taskInfo;
if (mAppPairLayout != null
&& mAppPairLayout.updateConfiguration(mRootTaskInfo.configuration)) {
- // Update bounds when there is root bounds or orientation changed.
+ // Update bounds when root bounds or its orientation changed.
final WindowContainerTransaction wct = new WindowContainerTransaction();
final SurfaceControl dividerLeash = mAppPairLayout.getDividerLeash();
final Rect dividerBounds = mAppPairLayout.getDividerBounds();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPairLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPairLayout.java
index f8703f7ec0bc..8c8655e1ff1f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPairLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPairLayout.java
@@ -16,7 +16,6 @@
package com.android.wm.shell.apppairs;
-import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
import static android.view.WindowManager.LayoutParams.FLAG_SLIPPERY;
@@ -45,21 +44,18 @@ import com.android.wm.shell.R;
/**
* Records and handles layout of a pair of apps.
*/
-// TODO(172704238): add tests
final class AppPairLayout {
private static final String DIVIDER_WINDOW_TITLE = "AppPairDivider";
- private final Context mContext;
- private final AppPairWindowManager mAppPairWindowManager;
- private final SurfaceControlViewHost mViewHost;
-
+ private final Display mDisplay;
private final int mDividerWindowWidth;
private final int mDividerWindowInsets;
+ private final AppPairWindowManager mAppPairWindowManager;
- private boolean mIsLandscape;
+ private Context mContext;
private Rect mRootBounds;
private DIVIDE_POLICY mDividePolicy;
- private DividerView mDividerView;
+ private SurfaceControlViewHost mViewHost;
private SurfaceControl mDividerLeash;
AppPairLayout(
@@ -68,7 +64,7 @@ final class AppPairLayout {
Configuration configuration,
SurfaceControl rootLeash) {
mContext = context.createConfigurationContext(configuration);
- mIsLandscape = isLandscape(configuration);
+ mDisplay = display;
mRootBounds = configuration.windowConfiguration.getBounds();
mDividerWindowWidth = mContext.getResources().getDimensionPixelSize(
com.android.internal.R.dimen.docked_stack_divider_thickness);
@@ -76,26 +72,22 @@ final class AppPairLayout {
com.android.internal.R.dimen.docked_stack_divider_insets);
mAppPairWindowManager = new AppPairWindowManager(configuration, rootLeash);
- mViewHost = new SurfaceControlViewHost(mContext, display, mAppPairWindowManager);
mDividePolicy = DIVIDE_POLICY.MIDDLE;
- mDividePolicy.update(mIsLandscape, mRootBounds, mDividerWindowWidth, mDividerWindowInsets);
+ mDividePolicy.update(mRootBounds, mDividerWindowWidth, mDividerWindowInsets);
}
boolean updateConfiguration(Configuration configuration) {
mAppPairWindowManager.setConfiguration(configuration);
final Rect rootBounds = configuration.windowConfiguration.getBounds();
- final boolean isLandscape = isLandscape(configuration);
- if (mIsLandscape == isLandscape && isIdenticalBounds(mRootBounds, rootBounds)) {
+ if (isIdenticalBounds(mRootBounds, rootBounds)) {
return false;
}
- mIsLandscape = isLandscape;
+ mContext = mContext.createConfigurationContext(configuration);
mRootBounds = rootBounds;
- mDividePolicy.update(mIsLandscape, mRootBounds, mDividerWindowWidth, mDividerWindowInsets);
- mViewHost.relayout(
- mDividePolicy.mDividerBounds.width(),
- mDividePolicy.mDividerBounds.height());
- // TODO(172704238): handle divider bar rotation.
+ mDividePolicy.update(mRootBounds, mDividerWindowWidth, mDividerWindowInsets);
+ release();
+ init();
return true;
}
@@ -116,22 +108,19 @@ final class AppPairLayout {
}
void release() {
- if (mViewHost == null) return;
+ if (mViewHost == null) {
+ return;
+ }
mViewHost.release();
+ mDividerLeash = null;
+ mViewHost = null;
}
- void setDividerVisibility(boolean visible) {
- if (mDividerView == null) {
- initDivider();
- }
- if (visible) {
- mDividerView.show();
- } else {
- mDividerView.hide();
+ void init() {
+ if (mViewHost == null) {
+ mViewHost = new SurfaceControlViewHost(mContext, mDisplay, mAppPairWindowManager);
}
- }
- private void initDivider() {
final DividerView dividerView = (DividerView) LayoutInflater.from(mContext)
.inflate(R.layout.split_divider, null);
@@ -147,14 +136,9 @@ final class AppPairLayout {
lp.privateFlags |= PRIVATE_FLAG_NO_MOVE_ANIMATION;
mViewHost.setView(dividerView, lp);
- mDividerView = dividerView;
mDividerLeash = mAppPairWindowManager.getSurfaceControl(mViewHost.getWindowToken());
}
- private static boolean isLandscape(Configuration configuration) {
- return configuration.orientation == ORIENTATION_LANDSCAPE;
- }
-
private static boolean isIdenticalBounds(Rect bounds1, Rect bounds2) {
return bounds1.left == bounds2.left && bounds1.top == bounds2.top
&& bounds1.right == bounds2.right && bounds1.bottom == bounds2.bottom;
@@ -167,8 +151,7 @@ final class AppPairLayout {
enum DIVIDE_POLICY {
MIDDLE;
- void update(boolean isLandscape, Rect rootBounds, int dividerWindowWidth,
- int dividerWindowInsets) {
+ void update(Rect rootBounds, int dividerWindowWidth, int dividerWindowInsets) {
final int dividerOffset = dividerWindowWidth / 2;
final int boundsOffset = dividerOffset - dividerWindowInsets;
@@ -179,7 +162,7 @@ final class AppPairLayout {
switch (this) {
case MIDDLE:
default:
- if (isLandscape) {
+ if (isLandscape(rootBounds)) {
mDividerBounds.left = rootBounds.width() / 2 - dividerOffset;
mDividerBounds.right = rootBounds.width() / 2 + dividerOffset;
mBounds1.left = rootBounds.width() / 2 + boundsOffset;
@@ -193,6 +176,10 @@ final class AppPairLayout {
}
}
+ private boolean isLandscape(Rect bounds) {
+ return bounds.width() > bounds.height();
+ }
+
Rect mDividerBounds;
Rect mBounds1;
Rect mBounds2;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPairs.java b/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPairs.java
index af06764145e3..ef3e3e0220e7 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPairs.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPairs.java
@@ -36,6 +36,4 @@ public interface AppPairs {
void dump(@NonNull PrintWriter pw, String prefix);
/** Called when the shell organizer has been registered. */
void onOrganizerRegistered();
- /** Called when the visibility of the keyguard changes. */
- void onKeyguardVisibilityChanged(boolean showing);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPairsController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPairsController.java
index 925a4f36d5e6..f2f09820639a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPairsController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPairsController.java
@@ -16,8 +16,6 @@
package com.android.wm.shell.apppairs;
-import static android.app.ActivityTaskManager.INVALID_TASK_ID;
-
import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_TASK_ORG;
import android.app.ActivityManager;
@@ -30,15 +28,13 @@ import com.android.internal.protolog.common.ProtoLog;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.SyncTransactionQueue;
-import com.android.wm.shell.common.TaskStackListenerCallback;
-import com.android.wm.shell.common.TaskStackListenerImpl;
import java.io.PrintWriter;
/**
* Class manages app-pairs multitasking mode and implements the main interface {@link AppPairs}.
*/
-public class AppPairsController implements AppPairs, TaskStackListenerCallback {
+public class AppPairsController implements AppPairs {
private static final String TAG = AppPairsController.class.getSimpleName();
private final ShellTaskOrganizer mTaskOrganizer;
@@ -48,14 +44,12 @@ public class AppPairsController implements AppPairs, TaskStackListenerCallback {
// Active app-pairs mapped by root task id key.
private final SparseArray<AppPair> mActiveAppPairs = new SparseArray<>();
private final DisplayController mDisplayController;
- private int mForegroundTaskId = INVALID_TASK_ID;
public AppPairsController(ShellTaskOrganizer organizer, SyncTransactionQueue syncQueue,
- DisplayController displayController, TaskStackListenerImpl taskStackListener) {
+ DisplayController displayController) {
mTaskOrganizer = organizer;
mSyncQueue = syncQueue;
mDisplayController = displayController;
- taskStackListener.addListener(this);
}
@Override
@@ -71,27 +65,6 @@ public class AppPairsController implements AppPairs, TaskStackListenerCallback {
}
@Override
- public void onTaskMovedToFront(int taskId) {
- mForegroundTaskId = INVALID_TASK_ID;
- for (int i = mActiveAppPairs.size() - 1; i >= 0; --i) {
- final AppPair candidate = mActiveAppPairs.valueAt(i);
- final boolean containForegroundTask = candidate.contains(taskId);
- candidate.setVisible(containForegroundTask);
- if (containForegroundTask) {
- mForegroundTaskId = candidate.getRootTaskId();
- }
- }
- }
-
- @Override
- public void onKeyguardVisibilityChanged(boolean showing) {
- if (mForegroundTaskId == INVALID_TASK_ID) {
- return;
- }
- mActiveAppPairs.get(mForegroundTaskId).setVisible(!showing);
- }
-
- @Override
public boolean pair(int taskId1, int taskId2) {
final ActivityManager.RunningTaskInfo task1 = mTaskOrganizer.getRunningTaskInfo(taskId1);
final ActivityManager.RunningTaskInfo task2 = mTaskOrganizer.getRunningTaskInfo(taskId2);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java
index 8a547b4477fd..7b3b5dbfa51c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java
@@ -18,12 +18,10 @@ package com.android.wm.shell.draganddrop;
import static android.app.ActivityTaskManager.INVALID_TASK_ID;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.content.ClipDescription.EXTRA_ACTIVITY_OPTIONS;
import static android.content.ClipDescription.EXTRA_PENDING_INTENT;
-import static android.content.ClipDescription.MIMETYPE_APPLICATION_ACTIVITY;
import static android.content.ClipDescription.MIMETYPE_APPLICATION_SHORTCUT;
import static android.content.ClipDescription.MIMETYPE_APPLICATION_TASK;
import static android.content.Intent.EXTRA_PACKAGE_NAME;
@@ -78,7 +76,7 @@ public class DragAndDropPolicy {
private static final String TAG = DragAndDropPolicy.class.getSimpleName();
private final Context mContext;
- private final IActivityTaskManager mIActivityTaskManager;
+ private final ActivityTaskManager mActivityTaskManager;
private final Starter mStarter;
private final SplitScreen mSplitScreen;
private final ArrayList<DragAndDropPolicy.Target> mTargets = new ArrayList<>();
@@ -86,15 +84,15 @@ public class DragAndDropPolicy {
private DragSession mSession;
public DragAndDropPolicy(Context context, SplitScreen splitScreen) {
- this(context, ActivityTaskManager.getService(), splitScreen,
+ this(context, ActivityTaskManager.getInstance(), splitScreen,
new DefaultStarter(context, splitScreen));
}
@VisibleForTesting
- DragAndDropPolicy(Context context, IActivityTaskManager activityTaskManager,
+ DragAndDropPolicy(Context context, ActivityTaskManager activityTaskManager,
SplitScreen splitScreen, Starter starter) {
mContext = context;
- mIActivityTaskManager = activityTaskManager;
+ mActivityTaskManager = activityTaskManager;
mSplitScreen = splitScreen;
mStarter = starter;
}
@@ -103,7 +101,7 @@ public class DragAndDropPolicy {
* Starts a new drag session with the given initial drag data.
*/
void start(DisplayLayout displayLayout, ClipData data) {
- mSession = new DragSession(mContext, mIActivityTaskManager, displayLayout, data);
+ mSession = new DragSession(mContext, mActivityTaskManager, displayLayout, data);
// TODO(b/169894807): Also update the session data with task stack changes
mSession.update();
}
@@ -271,7 +269,7 @@ public class DragAndDropPolicy {
*/
private static class DragSession {
private final Context mContext;
- private final IActivityTaskManager mIActivityTaskManager;
+ private final ActivityTaskManager mActivityTaskManager;
private final ClipData mInitialDragData;
final DisplayLayout displayLayout;
@@ -285,10 +283,10 @@ public class DragAndDropPolicy {
boolean dragItemSupportsSplitscreen;
boolean isPhone;
- DragSession(Context context, IActivityTaskManager activityTaskManager,
+ DragSession(Context context, ActivityTaskManager activityTaskManager,
DisplayLayout dispLayout, ClipData data) {
mContext = context;
- mIActivityTaskManager = activityTaskManager;
+ mActivityTaskManager = activityTaskManager;
mInitialDragData = data;
displayLayout = dispLayout;
}
@@ -298,19 +296,14 @@ public class DragAndDropPolicy {
*/
void update() {
- try {
- List<ActivityManager.RunningTaskInfo> tasks =
- mIActivityTaskManager.getFilteredTasks(1,
- false /* filterOnlyVisibleRecents */);
- if (!tasks.isEmpty()) {
- final ActivityManager.RunningTaskInfo task = tasks.get(0);
- runningTaskWinMode = task.getWindowingMode();
- runningTaskActType = task.getActivityType();
- runningTaskId = task.taskId;
- runningTaskIsResizeable = task.isResizeable;
- }
- } catch (RemoteException e) {
- // Fall through
+ List<ActivityManager.RunningTaskInfo> tasks =
+ mActivityTaskManager.getTasks(1, false /* filterOnlyVisibleRecents */);
+ if (!tasks.isEmpty()) {
+ final ActivityManager.RunningTaskInfo task = tasks.get(0);
+ runningTaskWinMode = task.getWindowingMode();
+ runningTaskActType = task.getActivityType();
+ runningTaskId = task.taskId;
+ runningTaskIsResizeable = task.isResizeable;
}
final ActivityInfo info = mInitialDragData.getItemAt(0).getActivityInfo();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutOrganizer.java
index 090d2270817b..4e62ea6e7233 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutOrganizer.java
@@ -272,8 +272,9 @@ class HideDisplayCutoutOrganizer extends DisplayAreaOrganizer {
@VisibleForTesting
void applyBoundsAndOffsets(WindowContainerToken token, SurfaceControl leash,
WindowContainerTransaction wct, SurfaceControl.Transaction t) {
- wct.setBounds(token, mCurrentDisplayBounds.isEmpty() ? null : mCurrentDisplayBounds);
+ wct.setBounds(token, mCurrentDisplayBounds);
t.setPosition(leash, mOffsetX, mOffsetY);
+ t.setWindowCrop(leash, mCurrentDisplayBounds.width(), mCurrentDisplayBounds.height());
}
@VisibleForTesting
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/letterbox/LetterboxTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/letterbox/LetterboxTaskListener.java
index 061d3f86b669..6e87f131ed95 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/letterbox/LetterboxTaskListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/letterbox/LetterboxTaskListener.java
@@ -107,6 +107,7 @@ public class LetterboxTaskListener implements ShellTaskOrganizer.TaskListener {
transaction.setWindowCrop(leash, crop);
}
+ // TODO(b/173440321): Correct presentation of letterboxed activities in One-handed mode.
private void resolveTaskPositionAndCrop(
ActivityManager.RunningTaskInfo taskInfo,
Point positionInParent,
@@ -125,15 +126,18 @@ public class LetterboxTaskListener implements ShellTaskOrganizer.TaskListener {
final Rect activityBounds = taskInfo.letterboxActivityBounds;
Insets insets = getInsets();
+ Rect displayBoundsWithInsets =
+ new Rect(mWindowManager.getMaximumWindowMetrics().getBounds());
+ displayBoundsWithInsets.inset(insets);
Rect taskBoundsWithInsets = new Rect(taskBounds);
- applyInsets(taskBoundsWithInsets, insets, taskInfo.parentBounds);
+ taskBoundsWithInsets.intersect(displayBoundsWithInsets);
Rect activityBoundsWithInsets = new Rect(activityBounds);
- applyInsets(activityBoundsWithInsets, insets, taskInfo.parentBounds);
+ activityBoundsWithInsets.intersect(displayBoundsWithInsets);
Rect parentBoundsWithInsets = new Rect(parentBounds);
- applyInsets(parentBoundsWithInsets, insets, parentBounds);
+ parentBoundsWithInsets.intersect(displayBoundsWithInsets);
// Crop need to be in the task coordinates.
crop.set(activityBoundsWithInsets);
@@ -217,10 +221,4 @@ public class LetterboxTaskListener implements ShellTaskOrganizer.TaskListener {
| WindowInsets.Type.displayCutout());
}
- private void applyInsets(Rect innerBounds, Insets insets, Rect outerBounds) {
- Rect outerBoundsWithInsets = new Rect(outerBounds);
- outerBoundsWithInsets.inset(insets);
- innerBounds.intersect(outerBoundsWithInsets);
- }
-
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipController.java
index 56e97b91c9d2..a99ef6342c0d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipController.java
@@ -36,7 +36,6 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ParceledListSlice;
import android.content.res.Configuration;
-import android.content.res.Resources;
import android.graphics.Rect;
import android.os.Debug;
import android.os.Handler;
@@ -59,13 +58,14 @@ import com.android.wm.shell.pip.PipTaskOrganizer;
import java.util.ArrayList;
import java.util.List;
+import java.util.Objects;
/**
* Manages the picture-in-picture (PIP) UI and states.
*/
public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallback {
- private static final String TAG = "PipController";
- static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+ private static final String TAG = "TvPipController";
+ static final boolean DEBUG = false;
/**
* Unknown or invalid state
@@ -117,9 +117,6 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac
private int mResumeResizePinnedStackRunnableState = STATE_NO_PIP;
private final Handler mHandler = new Handler();
private List<Listener> mListeners = new ArrayList<>();
- private Rect mPipBounds;
- private Rect mDefaultPipBounds = new Rect();
- private Rect mMenuModePipBounds;
private int mLastOrientation = Configuration.ORIENTATION_UNDEFINED;
private int mPipTaskId = TASK_ID_NO_PIP;
private int mPinnedStackId = INVALID_STACK_ID;
@@ -187,11 +184,11 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac
if (mImeVisible != imeVisible) {
if (imeVisible) {
// Save the IME height adjustment, and offset to not occlude the IME
- mPipBounds.offset(0, -imeHeight);
+ mPipBoundsState.getNormalBounds().offset(0, -imeHeight);
mImeHeightAdjustment = imeHeight;
} else {
// Apply the inverse adjustment when the IME is hidden
- mPipBounds.offset(0, mImeHeightAdjustment);
+ mPipBoundsState.getNormalBounds().offset(0, mImeHeightAdjustment);
}
mImeVisible = imeVisible;
resizePinnedStack(STATE_PIP);
@@ -206,10 +203,6 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac
mTmpDisplayInfo.copyFrom(mPipBoundsState.getDisplayInfo());
mPipBoundsAlgorithm.getInsetBounds(mTmpInsetBounds);
- mPipBounds.set(mPipBoundsAlgorithm.getNormalBounds());
- if (mDefaultPipBounds.isEmpty()) {
- mDefaultPipBounds.set(mPipBoundsAlgorithm.getDefaultBounds());
- }
});
}
@@ -302,14 +295,10 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac
return;
}
- Resources res = mContext.getResources();
- mMenuModePipBounds = Rect.unflattenFromString(res.getString(
- R.string.pip_menu_bounds));
+ final Rect menuBounds = Rect.unflattenFromString(
+ mContext.getResources().getString(R.string.pip_menu_bounds));
+ mPipBoundsState.setExpandedBounds(menuBounds);
- // Reset the PIP bounds and apply. PIP bounds can be changed by two reasons.
- // 1. Configuration changed due to the language change (RTL <-> RTL)
- // 2. SystemUI restarts after the crash
- mPipBounds = mDefaultPipBounds;
resizePinnedStack(getPinnedTaskInfo() == null ? STATE_NO_PIP : STATE_PIP);
}
@@ -379,16 +368,22 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac
}
private void onActivityPinned(String packageName) {
- if (DEBUG) Log.d(TAG, "onActivityPinned()");
-
- RootTaskInfo taskInfo = getPinnedTaskInfo();
+ final RootTaskInfo taskInfo = getPinnedTaskInfo();
+ if (DEBUG) Log.d(TAG, "onActivityPinned, task=" + taskInfo);
if (taskInfo == null) {
Log.w(TAG, "Cannot find pinned stack");
return;
}
- if (DEBUG) Log.d(TAG, "PINNED_STACK:" + taskInfo);
+
+ // At this point PipBoundsState knows the correct aspect ratio for this pinned task, so we
+ // use PipBoundsAlgorithm to calculate the normal bounds for the task (PipBoundsAlgorithm
+ // will query PipBoundsState for the aspect ratio) and pass the bounds over to the
+ // PipBoundsState.
+ mPipBoundsState.setNormalBounds(mPipBoundsAlgorithm.getNormalBounds());
+
mPinnedStackId = taskInfo.taskId;
mPipTaskId = taskInfo.childTaskIds[taskInfo.childTaskIds.length - 1];
+
// Set state to STATE_PIP so we show it when the pinned stack animation ends.
mState = STATE_PIP;
mPipMediaController.onActivityPinned();
@@ -434,8 +429,7 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac
}
}
if (getState() == STATE_PIP) {
- if (mPipBounds != mDefaultPipBounds) {
- mPipBounds = mDefaultPipBounds;
+ if (!Objects.equals(mPipBoundsState.getBounds(), mPipBoundsState.getNormalBounds())) {
resizePinnedStack(STATE_PIP);
}
}
@@ -509,11 +503,11 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac
}
break;
case STATE_PIP_MENU:
- newBounds = mMenuModePipBounds;
+ newBounds = mPipBoundsState.getExpandedBounds();
break;
case STATE_PIP: // fallthrough
default:
- newBounds = mPipBounds;
+ newBounds = mPipBoundsState.getNormalBounds();
break;
}
if (newBounds != null) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
index 07af289c4f35..6d6c76139c87 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
@@ -506,7 +506,7 @@ public class SplitScreenController implements SplitScreen,
// Try fetching the top running task.
final List<RunningTaskInfo> runningTasks =
- ActivityTaskManager.getService().getTasks(1 /* maxNum */);
+ ActivityTaskManager.getInstance().getTasks(1 /* maxNum */);
if (runningTasks == null || runningTasks.isEmpty()) {
return false;
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTest.kt
index 2fc6944a3a5f..ced99de21a46 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTest.kt
@@ -16,6 +16,7 @@
package com.android.wm.shell.flicker.apppairs
+import android.platform.test.annotations.Presubmit
import android.os.SystemClock
import android.util.Log
import android.view.Surface
@@ -43,6 +44,7 @@ import java.io.IOException
* Test AppPairs launch.
* To run this test: `atest WMShellFlickerTests:AppPairsTest`
*/
+@Presubmit
@RequiresDevice
@RunWith(Parameterized::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt
index 6c4e65818e49..6b44ce6ace0c 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt
@@ -16,6 +16,7 @@
package com.android.wm.shell.flicker.pip
+import android.platform.test.annotations.Presubmit
import android.view.Surface
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.dsl.FlickerBuilder
@@ -36,6 +37,7 @@ import org.junit.runners.Parameterized
* Test Pip launch.
* To run this test: `atest WMShellFlickerTests:PipKeyboardTest`
*/
+@Presubmit
@RequiresDevice
@RunWith(Parameterized::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenTest.kt
index a0056dfc0948..c61a0f171714 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenTest.kt
@@ -16,6 +16,7 @@
package com.android.wm.shell.flicker.splitscreen
+import android.platform.test.annotations.Presubmit
import android.view.Surface
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.dsl.FlickerBuilder
@@ -38,6 +39,7 @@ import org.junit.runners.Parameterized
* Test SplitScreen launch.
* To run this test: `atest WMShellFlickerTests:EnterSplitScreenTest`
*/
+@Presubmit
@RequiresDevice
@RunWith(Parameterized::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/ExitSplitScreenTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/ExitSplitScreenTest.kt
index 32e112dbd598..bf9286980b9a 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/ExitSplitScreenTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/ExitSplitScreenTest.kt
@@ -16,6 +16,7 @@
package com.android.wm.shell.flicker.splitscreen
+import android.platform.test.annotations.Presubmit
import android.util.Rational
import android.view.Surface
import androidx.test.filters.FlakyTest
@@ -40,6 +41,7 @@ import org.junit.runners.Parameterized
* Test exit SplitScreen mode.
* To run this test: `atest WMShellFlickerTests:ExitSplitScreenTest`
*/
+@Presubmit
@RequiresDevice
@RunWith(Parameterized::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/OpenAppToSplitScreenTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/OpenAppToSplitScreenTest.kt
index 1e328a8dae40..c85561d96091 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/OpenAppToSplitScreenTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/OpenAppToSplitScreenTest.kt
@@ -17,7 +17,7 @@
package com.android.wm.shell.flicker.splitscreen
import android.platform.test.annotations.Presubmit
-import androidx.test.filters.FlakyTest
+import android.view.Surface
import androidx.test.filters.RequiresDevice
import androidx.test.platform.app.InstrumentationRegistry
import com.android.server.wm.flicker.DOCKED_STACK_DIVIDER
@@ -54,7 +54,6 @@ import org.junit.runners.Parameterized
@RequiresDevice
@RunWith(Parameterized::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-@FlakyTest(bugId = 161435597)
class OpenAppToSplitScreenTest(
testName: String,
flickerSpec: Flicker
@@ -67,7 +66,8 @@ class OpenAppToSplitScreenTest(
val testApp = StandardAppHelper(instrumentation,
"com.android.wm.shell.flicker.testapp", "SimpleApp")
- return FlickerTestRunnerFactory(instrumentation)
+ // b/161435597 causes the test not to work on 90 degrees
+ return FlickerTestRunnerFactory(instrumentation, listOf(Surface.ROTATION_0))
.buildTest { configuration ->
withTestName {
buildTestTag("appToSplitScreen", testApp, configuration)
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenRotateOneLaunchedAppTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenRotateOneLaunchedAppTest.kt
new file mode 100644
index 000000000000..d2371bd766f5
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenRotateOneLaunchedAppTest.kt
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.wm.shell.flicker.splitscreen
+
+import androidx.test.filters.FlakyTest
+import android.view.Surface
+import androidx.test.filters.RequiresDevice
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.server.wm.flicker.Flicker
+import com.android.server.wm.flicker.FlickerTestRunner
+import com.android.server.wm.flicker.FlickerTestRunnerFactory
+import com.android.server.wm.flicker.helpers.StandardAppHelper
+import com.android.server.wm.flicker.startRotation
+import com.android.server.wm.flicker.endRotation
+import com.android.server.wm.flicker.helpers.buildTestTag
+import com.android.server.wm.flicker.helpers.exitSplitScreen
+import com.android.server.wm.flicker.helpers.isInSplitScreen
+import com.android.server.wm.flicker.helpers.launchSplitScreen
+import com.android.server.wm.flicker.helpers.setRotation
+import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
+import com.android.server.wm.flicker.repetitions
+import org.junit.FixMethodOrder
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test open app to split screen.
+ * To run this test: `atest WMShellFlickerTests:SplitScreenRotateOneLaunchedAppTest`
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@FlakyTest
+class SplitScreenRotateOneLaunchedAppTest(
+ testName: String,
+ flickerSpec: Flicker
+) : FlickerTestRunner(testName, flickerSpec) {
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): Collection<Array<Any>> {
+ val instrumentation = InstrumentationRegistry.getInstrumentation()
+ val testApp = StandardAppHelper(instrumentation,
+ "com.android.wm.shell.flicker.testapp", "SimpleApp")
+
+ return FlickerTestRunnerFactory(instrumentation, repetitions = 3)
+ .buildTest { configuration ->
+ withTestName {
+ buildTestTag("splitScreenRotateOneApp", testApp, configuration)
+ }
+ repeat { configuration.repetitions }
+ setup {
+ test {
+ device.wakeUpAndGoToHomeScreen()
+ testApp.open()
+ device.launchSplitScreen()
+ device.waitForIdle()
+ }
+ eachRun {
+ this.setRotation(configuration.startRotation)
+ }
+ }
+ teardown {
+ eachRun {
+ setRotation(Surface.ROTATION_0)
+ }
+ test {
+ testApp.exit()
+ if (device.isInSplitScreen()) {
+ device.exitSplitScreen()
+ }
+ }
+ }
+ transitions {
+ this.setRotation(configuration.endRotation)
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenRotateTwoLaunchedAppTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenRotateTwoLaunchedAppTest.kt
new file mode 100644
index 000000000000..67346424acd2
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenRotateTwoLaunchedAppTest.kt
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.wm.shell.flicker.splitscreen
+
+import androidx.test.filters.FlakyTest
+import android.view.Surface
+import androidx.test.filters.RequiresDevice
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.server.wm.flicker.Flicker
+import com.android.server.wm.flicker.FlickerTestRunner
+import com.android.server.wm.flicker.FlickerTestRunnerFactory
+import com.android.server.wm.flicker.helpers.StandardAppHelper
+import com.android.server.wm.flicker.startRotation
+import com.android.server.wm.flicker.endRotation
+import com.android.server.wm.flicker.helpers.buildTestTag
+import com.android.server.wm.flicker.helpers.exitSplitScreen
+import com.android.server.wm.flicker.helpers.reopenAppFromOverview
+import com.android.server.wm.flicker.helpers.isInSplitScreen
+import com.android.server.wm.flicker.helpers.launchSplitScreen
+import com.android.server.wm.flicker.helpers.setRotation
+import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
+import com.android.server.wm.flicker.repetitions
+import org.junit.FixMethodOrder
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test open app to split screen.
+ * To run this test: `atest WMShellFlickerTests:SplitScreenRotateTwoLaunchedAppTest`
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@FlakyTest
+class SplitScreenRotateTwoLaunchedAppTest(
+ testName: String,
+ flickerSpec: Flicker
+) : FlickerTestRunner(testName, flickerSpec) {
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): Collection<Array<Any>> {
+ val instrumentation = InstrumentationRegistry.getInstrumentation()
+ val testApp = StandardAppHelper(instrumentation,
+ "com.android.wm.shell.flicker.testapp", "SimpleApp")
+ val secondaryApp = StandardAppHelper(instrumentation,
+ "com.android.wm.shell.flicker.testapp",
+ "SplitScreenSecondaryApp")
+
+ return FlickerTestRunnerFactory(instrumentation, repetitions = 3)
+ .buildTest { configuration ->
+ withTestName {
+ buildTestTag("splitScreenRotateTwoApps", testApp, configuration)
+ }
+ repeat { configuration.repetitions }
+ setup {
+ test {
+ device.wakeUpAndGoToHomeScreen()
+ testApp.open()
+ device.pressHome()
+ secondaryApp.open()
+ device.pressHome()
+ device.launchSplitScreen()
+ device.reopenAppFromOverview()
+ device.waitForIdle()
+ }
+ eachRun {
+ this.setRotation(configuration.startRotation)
+ }
+ }
+ teardown {
+ eachRun {
+ setRotation(Surface.ROTATION_0)
+ }
+ test {
+ testApp.exit()
+ secondaryApp.exit()
+ if (device.isInSplitScreen()) {
+ device.exitSplitScreen()
+ }
+ }
+ }
+ transitions {
+ this.setRotation(configuration.endRotation)
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairLayoutTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairLayoutTests.java
new file mode 100644
index 000000000000..c9d32c4b1f76
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairLayoutTests.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.wm.shell.apppairs;
+
+import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
+import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.res.Configuration;
+import android.graphics.Rect;
+import android.view.Display;
+import android.view.SurfaceControl;
+
+import androidx.test.annotation.UiThreadTest;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import com.android.wm.shell.ShellTestCase;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+/** Tests for {@link AppPairLayout} */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class AppPairLayoutTests extends ShellTestCase {
+ @Mock SurfaceControl mSurfaceControl;
+ private Display mDisplay;
+ private Configuration mConfiguration;
+ private AppPairLayout mAppPairLayout;
+
+ @Before
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+ mConfiguration = getConfiguration(false);
+ mDisplay = mContext.getDisplay();
+ mAppPairLayout = new AppPairLayout(mContext, mDisplay, mConfiguration, mSurfaceControl);
+ }
+
+ @After
+ @UiThreadTest
+ public void tearDown() {
+ mAppPairLayout.release();
+ }
+
+ @Test
+ @UiThreadTest
+ public void testUpdateConfiguration() {
+ assertThat(mAppPairLayout.updateConfiguration(getConfiguration(false))).isFalse();
+ assertThat(mAppPairLayout.updateConfiguration(getConfiguration(true))).isTrue();
+ }
+
+ @Test
+ @UiThreadTest
+ public void testInitRelease() {
+ mAppPairLayout.init();
+ assertThat(mAppPairLayout.getDividerLeash()).isNotNull();
+ mAppPairLayout.release();
+ assertThat(mAppPairLayout.getDividerLeash()).isNull();
+ }
+
+ private static Configuration getConfiguration(boolean isLandscape) {
+ final Configuration configuration = new Configuration();
+ configuration.unset();
+ configuration.orientation = isLandscape ? ORIENTATION_LANDSCAPE : ORIENTATION_PORTRAIT;
+ configuration.windowConfiguration.setBounds(
+ new Rect(0, 0, isLandscape ? 2160 : 1080, isLandscape ? 1080 : 2160));
+ return configuration;
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairTests.java
index 754f73246c86..f12648a7f709 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairTests.java
@@ -34,7 +34,6 @@ import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.ShellTestCase;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.SyncTransactionQueue;
-import com.android.wm.shell.common.TaskStackListenerImpl;
import org.junit.After;
import org.junit.Before;
@@ -52,7 +51,6 @@ public class AppPairTests extends ShellTestCase {
@Mock private SyncTransactionQueue mSyncQueue;
@Mock private ShellTaskOrganizer mTaskOrganizer;
@Mock private DisplayController mDisplayController;
- @Mock private TaskStackListenerImpl mTaskStackListener;
@Before
public void setUp() {
@@ -60,8 +58,7 @@ public class AppPairTests extends ShellTestCase {
mController = new TestAppPairsController(
mTaskOrganizer,
mSyncQueue,
- mDisplayController,
- mTaskStackListener);
+ mDisplayController);
when(mDisplayController.getDisplayContext(anyInt())).thenReturn(mContext);
when(mDisplayController.getDisplay(anyInt())).thenReturn(
mContext.getSystemService(DisplayManager.class).getDisplay(DEFAULT_DISPLAY));
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairsControllerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairsControllerTests.java
index 6d441ab898ec..f8c68d2018da 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairsControllerTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairsControllerTests.java
@@ -34,7 +34,6 @@ import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.ShellTestCase;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.SyncTransactionQueue;
-import com.android.wm.shell.common.TaskStackListenerImpl;
import org.junit.After;
import org.junit.Before;
@@ -52,7 +51,6 @@ public class AppPairsControllerTests extends ShellTestCase {
@Mock private SyncTransactionQueue mSyncQueue;
@Mock private ShellTaskOrganizer mTaskOrganizer;
@Mock private DisplayController mDisplayController;
- @Mock private TaskStackListenerImpl mTaskStackListener;
@Before
public void setUp() {
@@ -60,8 +58,7 @@ public class AppPairsControllerTests extends ShellTestCase {
mController = new TestAppPairsController(
mTaskOrganizer,
mSyncQueue,
- mDisplayController,
- mTaskStackListener);
+ mDisplayController);
mPool = mController.getPool();
when(mDisplayController.getDisplayContext(anyInt())).thenReturn(mContext);
when(mDisplayController.getDisplay(anyInt())).thenReturn(
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairsPoolTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairsPoolTests.java
index d3dbbfe37985..8ece913de53f 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairsPoolTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairsPoolTests.java
@@ -24,7 +24,6 @@ import androidx.test.filters.SmallTest;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.SyncTransactionQueue;
-import com.android.wm.shell.common.TaskStackListenerImpl;
import org.junit.After;
import org.junit.Before;
@@ -42,7 +41,6 @@ public class AppPairsPoolTests {
@Mock private SyncTransactionQueue mSyncQueue;
@Mock private ShellTaskOrganizer mTaskOrganizer;
@Mock private DisplayController mDisplayController;
- @Mock private TaskStackListenerImpl mTaskStackListener;
@Before
public void setUp() {
@@ -50,8 +48,7 @@ public class AppPairsPoolTests {
mController = new TestAppPairsController(
mTaskOrganizer,
mSyncQueue,
- mDisplayController,
- mTaskStackListener);
+ mDisplayController);
mPool = mController.getPool();
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/TestAppPairsController.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/TestAppPairsController.java
index e61cc91c394b..be0963628933 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/TestAppPairsController.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/TestAppPairsController.java
@@ -19,14 +19,13 @@ package com.android.wm.shell.apppairs;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.SyncTransactionQueue;
-import com.android.wm.shell.common.TaskStackListenerImpl;
public class TestAppPairsController extends AppPairsController {
TestAppPairsPool mPool;
public TestAppPairsController(ShellTaskOrganizer organizer, SyncTransactionQueue syncQueue,
- DisplayController displayController, TaskStackListenerImpl taskStackListener) {
- super(organizer, syncQueue, displayController, taskStackListener);
+ DisplayController displayController) {
+ super(organizer, syncQueue, displayController);
mPool = new TestAppPairsPool(this);
setPairsPool(mPool);
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java
index fad1f057267a..92d4bee7cfc2 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java
@@ -42,7 +42,7 @@ import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
import android.app.ActivityManager;
-import android.app.IActivityTaskManager;
+import android.app.ActivityTaskManager;
import android.app.PendingIntent;
import android.content.ClipData;
import android.content.ClipDescription;
@@ -69,7 +69,6 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import java.util.ArrayList;
@@ -88,7 +87,7 @@ public class DragAndDropPolicyTest {
private Context mContext;
@Mock
- private IActivityTaskManager mIActivityTaskManager;
+ private ActivityTaskManager mActivityTaskManager;
@Mock
private SplitScreen mSplitScreen;
@@ -134,7 +133,7 @@ public class DragAndDropPolicyTest {
return null;
}).when(mSplitScreen).registerInSplitScreenListener(any());
- mPolicy = new DragAndDropPolicy(mContext, mIActivityTaskManager, mSplitScreen, mStarter);
+ mPolicy = new DragAndDropPolicy(mContext, mActivityTaskManager, mSplitScreen, mStarter);
mActivityClipData = createClipData(MIMETYPE_APPLICATION_ACTIVITY);
mNonResizeableActivityClipData = createClipData(MIMETYPE_APPLICATION_ACTIVITY);
setClipDataResizeable(mNonResizeableActivityClipData, false);
@@ -188,9 +187,9 @@ public class DragAndDropPolicyTest {
return info;
}
- private void setRunningTask(ActivityManager.RunningTaskInfo task) throws RemoteException {
- doReturn(Collections.singletonList(task)).when(mIActivityTaskManager)
- .getFilteredTasks(anyInt(), anyBoolean());
+ private void setRunningTask(ActivityManager.RunningTaskInfo task) {
+ doReturn(Collections.singletonList(task)).when(mActivityTaskManager)
+ .getTasks(anyInt(), anyBoolean());
}
private void setClipDataResizeable(ClipData data, boolean resizeable) {
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/letterbox/LetterboxTaskListenerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/letterbox/LetterboxTaskListenerTest.java
index 0f719afd08b3..fc0e20b553d3 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/letterbox/LetterboxTaskListenerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/letterbox/LetterboxTaskListenerTest.java
@@ -96,6 +96,7 @@ public final class LetterboxTaskListenerTest extends ShellTestCase {
mLetterboxTaskListener.onTaskAppeared(
createTaskInfo(
/* taskId */ 1,
+ /* maxBounds= */ new Rect(0, 0, 200, 100), // equal to parent bounds
/* parentBounds */ new Rect(0, 0, 200, 100),
/* activityBounds */ new Rect(75, 0, 125, 75),
/* taskBounds */ new Rect(50, 0, 125, 100)),
@@ -109,6 +110,7 @@ public final class LetterboxTaskListenerTest extends ShellTestCase {
mLetterboxTaskListener.onTaskInfoChanged(
createTaskInfo(
/* taskId */ 1,
+ /* maxBounds= */ new Rect(0, 0, 200, 100), // equal to parent bounds
/* parentBounds */ new Rect(0, 0, 200, 100),
// Activity is offset by 25 to the left
/* activityBounds */ new Rect(50, 0, 100, 75),
@@ -130,6 +132,7 @@ public final class LetterboxTaskListenerTest extends ShellTestCase {
mLetterboxTaskListener.onTaskAppeared(
createTaskInfo(
/* taskId */ 1,
+ /* maxBounds= */ new Rect(0, 0, 200, 100), // equal to parent bounds
/* parentBounds */ new Rect(0, 0, 200, 100),
/* activityBounds */ new Rect(150, 0, 200, 75),
/* taskBounds */ new Rect(125, 0, 200, 100)),
@@ -150,6 +153,7 @@ public final class LetterboxTaskListenerTest extends ShellTestCase {
mLetterboxTaskListener.onTaskAppeared(
createTaskInfo(
/* taskId */ 1,
+ /* maxBounds= */ new Rect(0, 0, 200, 100), // equal to parent bounds
/* parentBounds */ new Rect(0, 0, 200, 100),
/* activityBounds */ new Rect(150, 0, 200, 75),
/* taskBounds */ new Rect(125, 0, 200, 100)),
@@ -170,6 +174,7 @@ public final class LetterboxTaskListenerTest extends ShellTestCase {
mLetterboxTaskListener.onTaskAppeared(
createTaskInfo(
/* taskId */ 1,
+ /* maxBounds= */ new Rect(0, 0, 200, 100), // equal to parent bounds
/* parentBounds */ new Rect(0, 0, 200, 100),
/* activityBounds */ new Rect(50, 0, 100, 75),
/* taskBounds */ new Rect(25, 0, 100, 100)),
@@ -190,6 +195,7 @@ public final class LetterboxTaskListenerTest extends ShellTestCase {
mLetterboxTaskListener.onTaskAppeared(
createTaskInfo(
/* taskId */ 1,
+ /* maxBounds= */ new Rect(0, 0, 100, 150), // equal to parent bounds
/* parentBounds */ new Rect(0, 0, 100, 150),
/* activityBounds */ new Rect(0, 75, 50, 125),
/* taskBounds */ new Rect(0, 50, 100, 125)),
@@ -210,6 +216,7 @@ public final class LetterboxTaskListenerTest extends ShellTestCase {
mLetterboxTaskListener.onTaskAppeared(
createTaskInfo(
/* taskId */ 1,
+ /* maxBounds= */ new Rect(0, 0, 100, 150), // equal to parent bounds
/* parentBounds */ new Rect(0, 0, 100, 150),
/* activityBounds */ new Rect(0, 75, 50, 125),
/* taskBounds */ new Rect(0, 50, 100, 125)),
@@ -230,6 +237,7 @@ public final class LetterboxTaskListenerTest extends ShellTestCase {
mLetterboxTaskListener.onTaskAppeared(
createTaskInfo(
/* taskId */ 1,
+ /* maxBounds= */ new Rect(0, 0, 100, 150), // equal to parent bounds
/* parentBounds */ new Rect(0, 0, 100, 150),
/* activityBounds */ new Rect(0, 75, 50, 125),
/* taskBounds */ new Rect(0, 50, 100, 125)),
@@ -250,6 +258,7 @@ public final class LetterboxTaskListenerTest extends ShellTestCase {
mLetterboxTaskListener.onTaskAppeared(
createTaskInfo(
/* taskId */ 1,
+ /* maxBounds= */ new Rect(0, 0, 200, 125), // equal to parent bounds
/* parentBounds */ new Rect(0, 0, 200, 125),
/* activityBounds */ new Rect(15, 0, 175, 120),
/* taskBounds */ new Rect(0, 0, 100, 125)), // equal to parent bounds
@@ -272,6 +281,7 @@ public final class LetterboxTaskListenerTest extends ShellTestCase {
mLetterboxTaskListener.onTaskAppeared(
createTaskInfo(
/* taskId */ 1,
+ /* maxBounds= */ new Rect(0, 0, 100, 150),
/* parentBounds */ new Rect(0, 75, 100, 225),
/* activityBounds */ new Rect(25, 75, 75, 125),
/* taskBounds */ new Rect(0, 75, 100, 125)),
@@ -285,7 +295,7 @@ public final class LetterboxTaskListenerTest extends ShellTestCase {
public void testOnTaskAppeared_calledSecondTimeWithSameTaskId_throwsException() {
setWindowBoundsAndInsets(new Rect(), Insets.NONE);
RunningTaskInfo taskInfo =
- createTaskInfo(/* taskId */ 1, new Rect(), new Rect(), new Rect());
+ createTaskInfo(/* taskId */ 1, new Rect(), new Rect(), new Rect(), new Rect());
mLetterboxTaskListener.onTaskAppeared(taskInfo, mLeash);
mLetterboxTaskListener.onTaskAppeared(taskInfo, mLeash);
}
@@ -306,11 +316,13 @@ public final class LetterboxTaskListenerTest extends ShellTestCase {
private static RunningTaskInfo createTaskInfo(
int taskId,
+ final Rect maxBounds,
final Rect parentBounds,
final Rect activityBounds,
final Rect taskBounds) {
RunningTaskInfo taskInfo = new RunningTaskInfo();
taskInfo.taskId = taskId;
+ taskInfo.configuration.windowConfiguration.setMaxBounds(maxBounds);
taskInfo.parentBounds = parentBounds;
taskInfo.configuration.windowConfiguration.setBounds(taskBounds);
taskInfo.letterboxActivityBounds = Rect.copyOrNull(activityBounds);
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp
index 4ed5457a2a7f..cd53217d2924 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -429,6 +429,7 @@ cc_defaults {
whole_static_libs: ["libskia"],
srcs: [
+ "canvas/CanvasFrontend.cpp",
"canvas/CanvasOpBuffer.cpp",
"canvas/CanvasOpRasterizer.cpp",
"pipeline/skia/SkiaDisplayList.cpp",
@@ -607,6 +608,7 @@ cc_test {
"tests/unit/CacheManagerTests.cpp",
"tests/unit/CanvasContextTests.cpp",
"tests/unit/CanvasOpTests.cpp",
+ "tests/unit/CanvasFrontendTests.cpp",
"tests/unit/CommonPoolTests.cpp",
"tests/unit/DamageAccumulatorTests.cpp",
"tests/unit/DeferredLayerUpdaterTests.cpp",
diff --git a/libs/hwui/DisplayListOps.in b/libs/hwui/DisplayListOps.in
index 49817925d9b4..c6c4ba8a6493 100644
--- a/libs/hwui/DisplayListOps.in
+++ b/libs/hwui/DisplayListOps.in
@@ -19,7 +19,6 @@ X(Save)
X(Restore)
X(SaveLayer)
X(SaveBehind)
-X(Concat44)
X(Concat)
X(SetMatrix)
X(Scale)
diff --git a/libs/hwui/RecordingCanvas.cpp b/libs/hwui/RecordingCanvas.cpp
index 473dc53dc4bf..a495ec4ac411 100644
--- a/libs/hwui/RecordingCanvas.cpp
+++ b/libs/hwui/RecordingCanvas.cpp
@@ -125,24 +125,18 @@ struct SaveBehind final : Op {
}
};
-struct Concat44 final : Op {
- static const auto kType = Type::Concat44;
- Concat44(const SkM44& m) : matrix(m) {}
- SkM44 matrix;
- void draw(SkCanvas* c, const SkMatrix&) const { c->concat(matrix); }
-};
struct Concat final : Op {
static const auto kType = Type::Concat;
- Concat(const SkMatrix& matrix) : matrix(matrix) {}
- SkMatrix matrix;
+ Concat(const SkM44& matrix) : matrix(matrix) {}
+ SkM44 matrix;
void draw(SkCanvas* c, const SkMatrix&) const { c->concat(matrix); }
};
struct SetMatrix final : Op {
static const auto kType = Type::SetMatrix;
- SetMatrix(const SkMatrix& matrix) : matrix(matrix) {}
- SkMatrix matrix;
+ SetMatrix(const SkM44& matrix) : matrix(matrix) {}
+ SkM44 matrix;
void draw(SkCanvas* c, const SkMatrix& original) const {
- c->setMatrix(SkMatrix::Concat(original, matrix));
+ c->setMatrix(SkM44(original) * matrix);
}
};
struct Scale final : Op {
@@ -569,12 +563,9 @@ void DisplayListData::saveBehind(const SkRect* subset) {
}
void DisplayListData::concat(const SkM44& m) {
- this->push<Concat44>(0, m);
-}
-void DisplayListData::concat(const SkMatrix& matrix) {
- this->push<Concat>(0, matrix);
+ this->push<Concat>(0, m);
}
-void DisplayListData::setMatrix(const SkMatrix& matrix) {
+void DisplayListData::setMatrix(const SkM44& matrix) {
this->push<SetMatrix>(0, matrix);
}
void DisplayListData::scale(SkScalar sx, SkScalar sy) {
@@ -834,10 +825,7 @@ bool RecordingCanvas::onDoSaveBehind(const SkRect* subset) {
void RecordingCanvas::didConcat44(const SkM44& m) {
fDL->concat(m);
}
-void RecordingCanvas::didConcat(const SkMatrix& matrix) {
- fDL->concat(matrix);
-}
-void RecordingCanvas::didSetMatrix(const SkMatrix& matrix) {
+void RecordingCanvas::didSetM44(const SkM44& matrix) {
fDL->setMatrix(matrix);
}
void RecordingCanvas::didScale(SkScalar sx, SkScalar sy) {
diff --git a/libs/hwui/RecordingCanvas.h b/libs/hwui/RecordingCanvas.h
index 63d120c4ca19..4851148cd4d8 100644
--- a/libs/hwui/RecordingCanvas.h
+++ b/libs/hwui/RecordingCanvas.h
@@ -82,8 +82,7 @@ private:
void restore();
void concat(const SkM44&);
- void concat(const SkMatrix&);
- void setMatrix(const SkMatrix&);
+ void setMatrix(const SkM44&);
void scale(SkScalar, SkScalar);
void translate(SkScalar, SkScalar);
void translateZ(SkScalar);
@@ -154,8 +153,7 @@ public:
void onFlush() override;
void didConcat44(const SkM44&) override;
- void didConcat(const SkMatrix&) override;
- void didSetMatrix(const SkMatrix&) override;
+ void didSetM44(const SkM44&) override;
void didScale(SkScalar, SkScalar) override;
void didTranslate(SkScalar, SkScalar) override;
diff --git a/libs/hwui/SaveFlags.h b/libs/hwui/SaveFlags.h
new file mode 100644
index 000000000000..f3579a8e9f19
--- /dev/null
+++ b/libs/hwui/SaveFlags.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <inttypes.h>
+
+// TODO: Move this to an enum class
+namespace android::SaveFlags {
+
+// These must match the corresponding Canvas API constants.
+enum {
+ Matrix = 0x01,
+ Clip = 0x02,
+ HasAlphaLayer = 0x04,
+ ClipToLayer = 0x10,
+
+ // Helper constant
+ MatrixClip = Matrix | Clip,
+};
+typedef uint32_t Flags;
+
+} // namespace android::SaveFlags
diff --git a/libs/hwui/VectorDrawable.cpp b/libs/hwui/VectorDrawable.cpp
index cd908354aea5..6030c36add7a 100644
--- a/libs/hwui/VectorDrawable.cpp
+++ b/libs/hwui/VectorDrawable.cpp
@@ -505,13 +505,11 @@ void Tree::draw(SkCanvas* canvas, const SkRect& bounds, const SkPaint& inPaint)
SkPaint paint = inPaint;
paint.setAlpha(mProperties.getRootAlpha() * 255);
- Bitmap& bitmap = getBitmapUpdateIfDirty();
- SkBitmap skiaBitmap;
- bitmap.getSkBitmap(&skiaBitmap);
+ sk_sp<SkImage> cachedBitmap = getBitmapUpdateIfDirty().makeImage();
int scaledWidth = SkScalarCeilToInt(mProperties.getScaledWidth());
int scaledHeight = SkScalarCeilToInt(mProperties.getScaledHeight());
- canvas->drawBitmapRect(skiaBitmap, SkRect::MakeWH(scaledWidth, scaledHeight), bounds,
+ canvas->drawImageRect(cachedBitmap, SkRect::MakeWH(scaledWidth, scaledHeight), bounds,
&paint, SkCanvas::kFast_SrcRectConstraint);
}
diff --git a/libs/hwui/canvas/CanvasFrontend.cpp b/libs/hwui/canvas/CanvasFrontend.cpp
new file mode 100644
index 000000000000..2c839b0ffc15
--- /dev/null
+++ b/libs/hwui/canvas/CanvasFrontend.cpp
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "CanvasFrontend.h"
+#include "CanvasOps.h"
+#include "CanvasOpBuffer.h"
+
+namespace android::uirenderer {
+
+CanvasStateHelper::CanvasStateHelper(int width, int height) {
+ mInitialBounds = SkIRect::MakeWH(width, height);
+ mSaveStack.emplace_back();
+ mClipStack.emplace_back().setRect(mInitialBounds);
+ mTransformStack.emplace_back();
+ mCurrentClipIndex = 0;
+ mCurrentTransformIndex = 0;
+}
+
+bool CanvasStateHelper::internalSave(SaveEntry saveEntry) {
+ mSaveStack.push_back(saveEntry);
+ if (saveEntry.matrix) {
+ // We need to push before accessing transform() to ensure the reference doesn't move
+ // across vector resizes
+ mTransformStack.emplace_back() = transform();
+ mCurrentTransformIndex += 1;
+ }
+ if (saveEntry.clip) {
+ // We need to push before accessing clip() to ensure the reference doesn't move
+ // across vector resizes
+ mClipStack.emplace_back() = clip();
+ mCurrentClipIndex += 1;
+ return true;
+ }
+ return false;
+}
+
+// Assert that the cast from SkClipOp to SkRegion::Op is valid
+static_assert(static_cast<int>(SkClipOp::kDifference) == SkRegion::Op::kDifference_Op);
+static_assert(static_cast<int>(SkClipOp::kIntersect) == SkRegion::Op::kIntersect_Op);
+static_assert(static_cast<int>(SkClipOp::kUnion_deprecated) == SkRegion::Op::kUnion_Op);
+static_assert(static_cast<int>(SkClipOp::kXOR_deprecated) == SkRegion::Op::kXOR_Op);
+static_assert(static_cast<int>(SkClipOp::kReverseDifference_deprecated) == SkRegion::Op::kReverseDifference_Op);
+static_assert(static_cast<int>(SkClipOp::kReplace_deprecated) == SkRegion::Op::kReplace_Op);
+
+void CanvasStateHelper::internalClipRect(const SkRect& rect, SkClipOp op) {
+ clip().opRect(rect, transform(), mInitialBounds, (SkRegion::Op)op, false);
+}
+
+void CanvasStateHelper::internalClipPath(const SkPath& path, SkClipOp op) {
+ clip().opPath(path, transform(), mInitialBounds, (SkRegion::Op)op, true);
+}
+
+bool CanvasStateHelper::internalRestore() {
+ // Prevent underflows
+ if (saveCount() <= 1) {
+ return false;
+ }
+
+ SaveEntry entry = mSaveStack[mSaveStack.size() - 1];
+ mSaveStack.pop_back();
+ bool needsRestorePropagation = entry.layer;
+ if (entry.matrix) {
+ mTransformStack.pop_back();
+ mCurrentTransformIndex -= 1;
+ }
+ if (entry.clip) {
+ // We need to push before accessing clip() to ensure the reference doesn't move
+ // across vector resizes
+ mClipStack.pop_back();
+ mCurrentClipIndex -= 1;
+ needsRestorePropagation = true;
+ }
+ return needsRestorePropagation;
+}
+
+SkRect CanvasStateHelper::getClipBounds() const {
+ SkIRect ibounds = clip().getBounds();
+
+ if (ibounds.isEmpty()) {
+ return SkRect::MakeEmpty();
+ }
+
+ SkMatrix inverse;
+ // if we can't invert the CTM, we can't return local clip bounds
+ if (!transform().invert(&inverse)) {
+ return SkRect::MakeEmpty();
+ }
+
+ SkRect ret = SkRect::MakeEmpty();
+ inverse.mapRect(&ret, SkRect::Make(ibounds));
+ return ret;
+}
+
+bool CanvasStateHelper::quickRejectRect(float left, float top, float right, float bottom) const {
+ // TODO: Implement
+ return false;
+}
+
+bool CanvasStateHelper::quickRejectPath(const SkPath& path) const {
+ // TODO: Implement
+ return false;
+}
+
+} // namespace android::uirenderer
diff --git a/libs/hwui/canvas/CanvasFrontend.h b/libs/hwui/canvas/CanvasFrontend.h
new file mode 100644
index 000000000000..5fccccb0bb43
--- /dev/null
+++ b/libs/hwui/canvas/CanvasFrontend.h
@@ -0,0 +1,200 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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
+
+// TODO: Can we get the dependencies scoped down more?
+#include "CanvasOps.h"
+#include "CanvasOpBuffer.h"
+#include <SaveFlags.h>
+
+#include <SkRasterClip.h>
+#include <ui/FatVector.h>
+
+#include <optional>
+
+namespace android::uirenderer {
+
+// Exists to avoid forcing all this common logic into the templated class
+class CanvasStateHelper {
+protected:
+ CanvasStateHelper(int width, int height);
+ ~CanvasStateHelper() = default;
+
+ struct SaveEntry {
+ bool clip : 1 = false;
+ bool matrix : 1 = false;
+ bool layer : 1 = false;
+ };
+
+ constexpr SaveEntry saveEntryForLayer() {
+ return {
+ .clip = true,
+ .matrix = true,
+ .layer = true,
+ };
+ }
+
+ constexpr SaveEntry flagsToSaveEntry(SaveFlags::Flags flags) {
+ return SaveEntry {
+ .clip = static_cast<bool>(flags & SaveFlags::Clip),
+ .matrix = static_cast<bool>(flags & SaveFlags::Matrix),
+ .layer = false
+ };
+ }
+
+ bool internalSave(SaveEntry saveEntry);
+ bool internalSave(SaveFlags::Flags flags) {
+ return internalSave(flagsToSaveEntry(flags));
+ }
+ void internalSaveLayer(const SkCanvas::SaveLayerRec& layerRec) {
+ internalSave({
+ .clip = true,
+ .matrix = true,
+ .layer = true
+ });
+ internalClipRect(*layerRec.fBounds, SkClipOp::kIntersect);
+ }
+
+ bool internalRestore();
+
+ void internalClipRect(const SkRect& rect, SkClipOp op);
+ void internalClipPath(const SkPath& path, SkClipOp op);
+
+ SkIRect mInitialBounds;
+ FatVector<SaveEntry, 6> mSaveStack;
+ FatVector<SkMatrix, 6> mTransformStack;
+ FatVector<SkConservativeClip, 6> mClipStack;
+
+ size_t mCurrentTransformIndex;
+ size_t mCurrentClipIndex;
+
+ const SkConservativeClip& clip() const {
+ return mClipStack[mCurrentClipIndex];
+ }
+
+ SkConservativeClip& clip() {
+ return mClipStack[mCurrentClipIndex];
+ }
+
+public:
+ int saveCount() const { return mSaveStack.size(); }
+
+ SkRect getClipBounds() const;
+ bool quickRejectRect(float left, float top, float right, float bottom) const;
+ bool quickRejectPath(const SkPath& path) const;
+
+ const SkMatrix& transform() const {
+ return mTransformStack[mCurrentTransformIndex];
+ }
+
+ SkMatrix& transform() {
+ return mTransformStack[mCurrentTransformIndex];
+ }
+
+ // For compat with existing HWUI Canvas interface
+ void getMatrix(SkMatrix* outMatrix) const {
+ *outMatrix = transform();
+ }
+
+ void setMatrix(const SkMatrix& matrix) {
+ transform() = matrix;
+ }
+
+ void concat(const SkMatrix& matrix) {
+ transform().preConcat(matrix);
+ }
+
+ void rotate(float degrees) {
+ SkMatrix m;
+ m.setRotate(degrees);
+ concat(m);
+ }
+
+ void scale(float sx, float sy) {
+ SkMatrix m;
+ m.setScale(sx, sy);
+ concat(m);
+ }
+
+ void skew(float sx, float sy) {
+ SkMatrix m;
+ m.setSkew(sx, sy);
+ concat(m);
+ }
+
+ void translate(float dx, float dy) {
+ transform().preTranslate(dx, dy);
+ }
+};
+
+// Front-end canvas that handles queries, up-front state, and produces CanvasOp<> output downstream
+template <typename CanvasOpReceiver>
+class CanvasFrontend final : public CanvasStateHelper {
+public:
+ template<class... Args>
+ CanvasFrontend(int width, int height, Args&&... args) : CanvasStateHelper(width, height),
+ mReceiver(std::forward<Args>(args)...) { }
+ ~CanvasFrontend() = default;
+
+ void save(SaveFlags::Flags flags = SaveFlags::MatrixClip) {
+ if (internalSave(flagsToSaveEntry(flags))) {
+ submit<CanvasOpType::Save>({});
+ }
+ }
+
+ void restore() {
+ if (internalRestore()) {
+ submit<CanvasOpType::Restore>({});
+ }
+ }
+
+ template <CanvasOpType T>
+ void draw(CanvasOp<T>&& op) {
+ // The front-end requires going through certain front-doors, which these aren't.
+ static_assert(T != CanvasOpType::Save, "Must use CanvasFrontend::save() call instead");
+ static_assert(T != CanvasOpType::Restore, "Must use CanvasFrontend::restore() call instead");
+
+ if constexpr (T == CanvasOpType::SaveLayer) {
+ internalSaveLayer(op.saveLayerRec);
+ }
+ if constexpr (T == CanvasOpType::SaveBehind) {
+ // Don't use internalSaveLayer as this doesn't apply clipping, it's a "regular" save
+ // But we do want to flag it as a layer, such that restore is Definitely Required
+ internalSave(saveEntryForLayer());
+ }
+ if constexpr (T == CanvasOpType::ClipRect) {
+ internalClipRect(op.rect, op.op);
+ }
+ if constexpr (T == CanvasOpType::ClipPath) {
+ internalClipPath(op.path, op.op);
+ }
+
+ submit(std::move(op));
+ }
+
+ const CanvasOpReceiver& receiver() const { return mReceiver; }
+
+private:
+ CanvasOpReceiver mReceiver;
+
+ template <CanvasOpType T>
+ void submit(CanvasOp<T>&& op) {
+ mReceiver.push_container(CanvasOpContainer(std::move(op), transform()));
+ }
+};
+
+} // namespace android::uirenderer
diff --git a/libs/hwui/canvas/CanvasOpRecorder.cpp b/libs/hwui/canvas/CanvasOpRecorder.cpp
new file mode 100644
index 000000000000..bb968ee84670
--- /dev/null
+++ b/libs/hwui/canvas/CanvasOpRecorder.cpp
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "CanvasOpRecorder.h"
+
+#include "CanvasOpBuffer.h"
+#include "CanvasOps.h"
+
+namespace android::uirenderer {} // namespace android::uirenderer
diff --git a/libs/hwui/canvas/CanvasOpRecorder.h b/libs/hwui/canvas/CanvasOpRecorder.h
new file mode 100644
index 000000000000..7d95bc4785ea
--- /dev/null
+++ b/libs/hwui/canvas/CanvasOpRecorder.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "hwui/Canvas.h"
+#include "CanvasOpBuffer.h"
+
+#include <vector>
+
+namespace android::uirenderer {
+
+// Interop with existing HWUI Canvas
+class CanvasOpRecorder final : /* todo: public Canvas */ {
+public:
+ // Transform ops
+private:
+ struct SaveEntry {
+
+ };
+
+ std::vector<SaveEntry> mSaveStack;
+};
+
+} // namespace android::uirenderer
diff --git a/libs/hwui/hwui/Canvas.h b/libs/hwui/hwui/Canvas.h
index f94bae2746d9..4d67166dd8d2 100644
--- a/libs/hwui/hwui/Canvas.h
+++ b/libs/hwui/hwui/Canvas.h
@@ -18,6 +18,7 @@
#include <cutils/compiler.h>
#include <utils/Functor.h>
+#include <SaveFlags.h>
#include <androidfw/ResourceTypes.h>
#include "Properties.h"
@@ -57,22 +58,6 @@ class SkiaDisplayList;
using DisplayList = skiapipeline::SkiaDisplayList;
}
-namespace SaveFlags {
-
-// These must match the corresponding Canvas API constants.
-enum {
- Matrix = 0x01,
- Clip = 0x02,
- HasAlphaLayer = 0x04,
- ClipToLayer = 0x10,
-
- // Helper constant
- MatrixClip = Matrix | Clip,
-};
-typedef uint32_t Flags;
-
-} // namespace SaveFlags
-
namespace uirenderer {
namespace VectorDrawable {
class Tree;
diff --git a/libs/hwui/tests/unit/CanvasFrontendTests.cpp b/libs/hwui/tests/unit/CanvasFrontendTests.cpp
new file mode 100644
index 000000000000..05b11795d90d
--- /dev/null
+++ b/libs/hwui/tests/unit/CanvasFrontendTests.cpp
@@ -0,0 +1,213 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <canvas/CanvasFrontend.h>
+#include <canvas/CanvasOpBuffer.h>
+#include <canvas/CanvasOps.h>
+#include <canvas/CanvasOpRasterizer.h>
+
+#include <tests/common/CallCountingCanvas.h>
+
+#include "SkPictureRecorder.h"
+#include "SkColor.h"
+#include "SkLatticeIter.h"
+#include "pipeline/skia/AnimatedDrawables.h"
+#include <SkNoDrawCanvas.h>
+
+using namespace android;
+using namespace android::uirenderer;
+using namespace android::uirenderer::test;
+
+class CanvasOpCountingReceiver {
+public:
+ template <CanvasOpType T>
+ void push_container(CanvasOpContainer<T>&& op) {
+ mOpCounts[static_cast<size_t>(T)] += 1;
+ }
+
+ int operator[](CanvasOpType op) const {
+ return mOpCounts[static_cast<size_t>(op)];
+ }
+
+private:
+ std::array<int, static_cast<size_t>(CanvasOpType::COUNT)> mOpCounts;
+};
+
+TEST(CanvasFrontend, saveCount) {
+ SkNoDrawCanvas skiaCanvas(100, 100);
+ CanvasFrontend<CanvasOpCountingReceiver> opCanvas(100, 100);
+ const auto& receiver = opCanvas.receiver();
+
+ EXPECT_EQ(1, skiaCanvas.getSaveCount());
+ EXPECT_EQ(1, opCanvas.saveCount());
+
+ skiaCanvas.save();
+ opCanvas.save(SaveFlags::MatrixClip);
+ EXPECT_EQ(2, skiaCanvas.getSaveCount());
+ EXPECT_EQ(2, opCanvas.saveCount());
+
+ skiaCanvas.restore();
+ opCanvas.restore();
+ EXPECT_EQ(1, skiaCanvas.getSaveCount());
+ EXPECT_EQ(1, opCanvas.saveCount());
+
+ skiaCanvas.restore();
+ opCanvas.restore();
+ EXPECT_EQ(1, skiaCanvas.getSaveCount());
+ EXPECT_EQ(1, opCanvas.saveCount());
+
+ EXPECT_EQ(1, receiver[CanvasOpType::Save]);
+ EXPECT_EQ(1, receiver[CanvasOpType::Restore]);
+}
+
+TEST(CanvasFrontend, transform) {
+ SkNoDrawCanvas skiaCanvas(100, 100);
+ CanvasFrontend<CanvasOpCountingReceiver> opCanvas(100, 100);
+
+ skiaCanvas.translate(10, 10);
+ opCanvas.translate(10, 10);
+ EXPECT_EQ(skiaCanvas.getTotalMatrix(), opCanvas.transform());
+
+ {
+ skiaCanvas.save();
+ opCanvas.save(SaveFlags::Matrix);
+ skiaCanvas.scale(2.0f, 1.125f);
+ opCanvas.scale(2.0f, 1.125f);
+
+ EXPECT_EQ(skiaCanvas.getTotalMatrix(), opCanvas.transform());
+ skiaCanvas.restore();
+ opCanvas.restore();
+ }
+
+ EXPECT_EQ(skiaCanvas.getTotalMatrix(), opCanvas.transform());
+
+ {
+ skiaCanvas.save();
+ opCanvas.save(SaveFlags::Matrix);
+ skiaCanvas.rotate(90.f);
+ opCanvas.rotate(90.f);
+
+ EXPECT_EQ(skiaCanvas.getTotalMatrix(), opCanvas.transform());
+
+ {
+ skiaCanvas.save();
+ opCanvas.save(SaveFlags::Matrix);
+ skiaCanvas.skew(5.0f, 2.25f);
+ opCanvas.skew(5.0f, 2.25f);
+
+ EXPECT_EQ(skiaCanvas.getTotalMatrix(), opCanvas.transform());
+ skiaCanvas.restore();
+ opCanvas.restore();
+ }
+
+ skiaCanvas.restore();
+ opCanvas.restore();
+ }
+
+ EXPECT_EQ(skiaCanvas.getTotalMatrix(), opCanvas.transform());
+}
+
+TEST(CanvasFrontend, drawOpTransform) {
+ CanvasFrontend<CanvasOpBuffer> opCanvas(100, 100);
+ const auto& receiver = opCanvas.receiver();
+
+ auto makeDrawRect = [] {
+ return CanvasOp<CanvasOpType::DrawRect>{
+ .rect = SkRect::MakeWH(50, 50),
+ .paint = SkPaint(SkColors::kBlack),
+ };
+ };
+
+ opCanvas.draw(makeDrawRect());
+
+ opCanvas.translate(10, 10);
+ opCanvas.draw(makeDrawRect());
+
+ opCanvas.save();
+ opCanvas.scale(2.0f, 4.0f);
+ opCanvas.draw(makeDrawRect());
+ opCanvas.restore();
+
+ opCanvas.save();
+ opCanvas.translate(20, 15);
+ opCanvas.draw(makeDrawRect());
+ opCanvas.save();
+ opCanvas.rotate(90.f);
+ opCanvas.draw(makeDrawRect());
+ opCanvas.restore();
+ opCanvas.restore();
+
+ // Validate the results
+ std::vector<SkMatrix> transforms;
+ transforms.reserve(5);
+ receiver.for_each([&](auto op) {
+ // Filter for the DrawRect calls; ignore the save & restores
+ // (TODO: Add a filtered for_each variant to OpBuffer?)
+ if (op->type() == CanvasOpType::DrawRect) {
+ transforms.push_back(op->transform());
+ }
+ });
+
+ EXPECT_EQ(transforms.size(), 5);
+
+ {
+ // First result should be identity
+ const auto& result = transforms[0];
+ EXPECT_EQ(SkMatrix::kIdentity_Mask, result.getType());
+ EXPECT_EQ(SkMatrix::I(), result);
+ }
+
+ {
+ // Should be translate 10, 10
+ const auto& result = transforms[1];
+ EXPECT_EQ(SkMatrix::kTranslate_Mask, result.getType());
+ SkMatrix m;
+ m.setTranslate(10, 10);
+ EXPECT_EQ(m, result);
+ }
+
+ {
+ // Should be translate 10, 10 + scale 2, 4
+ const auto& result = transforms[2];
+ EXPECT_EQ(SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask, result.getType());
+ SkMatrix m;
+ m.setTranslate(10, 10);
+ m.preScale(2.0f, 4.0f);
+ EXPECT_EQ(m, result);
+ }
+
+ {
+ // Should be translate 10, 10 + translate 20, 15
+ const auto& result = transforms[3];
+ EXPECT_EQ(SkMatrix::kTranslate_Mask, result.getType());
+ SkMatrix m;
+ m.setTranslate(30, 25);
+ EXPECT_EQ(m, result);
+ }
+
+ {
+ // Should be translate 10, 10 + translate 20, 15 + rotate 90
+ const auto& result = transforms[4];
+ EXPECT_EQ(SkMatrix::kTranslate_Mask | SkMatrix::kAffine_Mask | SkMatrix::kScale_Mask,
+ result.getType());
+ SkMatrix m;
+ m.setTranslate(30, 25);
+ m.preRotate(90.f);
+ EXPECT_EQ(m, result);
+ }
+} \ No newline at end of file
diff --git a/libs/hwui/tests/unit/CanvasOpTests.cpp b/libs/hwui/tests/unit/CanvasOpTests.cpp
index b15c3221dd60..f186e55ec2e3 100644
--- a/libs/hwui/tests/unit/CanvasOpTests.cpp
+++ b/libs/hwui/tests/unit/CanvasOpTests.cpp
@@ -16,6 +16,7 @@
#include <gtest/gtest.h>
+#include <canvas/CanvasFrontend.h>
#include <canvas/CanvasOpBuffer.h>
#include <canvas/CanvasOps.h>
#include <canvas/CanvasOpRasterizer.h>
@@ -26,6 +27,7 @@
#include "SkColor.h"
#include "SkLatticeIter.h"
#include "pipeline/skia/AnimatedDrawables.h"
+#include <SkNoDrawCanvas.h>
using namespace android;
using namespace android::uirenderer;
@@ -78,6 +80,21 @@ struct MockOp<MockTypes::Lifecycle> {
using MockBuffer = OpBuffer<MockTypes, MockOpContainer>;
+class CanvasOpCountingReceiver {
+public:
+ template <CanvasOpType T>
+ void push_container(CanvasOpContainer<T>&& op) {
+ mOpCounts[static_cast<size_t>(T)] += 1;
+ }
+
+ int operator[](CanvasOpType op) const {
+ return mOpCounts[static_cast<size_t>(op)];
+ }
+
+private:
+ std::array<int, static_cast<size_t>(CanvasOpType::COUNT)> mOpCounts;
+};
+
template<typename T>
static int countItems(const T& t) {
int count = 0;
@@ -614,4 +631,35 @@ TEST(CanvasOp, immediateRendering) {
rasterizer.draw(op);
EXPECT_EQ(1, canvas->drawRectCount);
EXPECT_EQ(1, canvas->sumTotalDrawCalls());
+}
+
+TEST(CanvasOp, frontendSaveCount) {
+ SkNoDrawCanvas skiaCanvas(100, 100);
+ CanvasFrontend<CanvasOpCountingReceiver> opCanvas(100, 100);
+ const auto& receiver = opCanvas.receiver();
+
+ EXPECT_EQ(1, skiaCanvas.getSaveCount());
+ EXPECT_EQ(1, opCanvas.saveCount());
+
+ skiaCanvas.save();
+ opCanvas.save(SaveFlags::MatrixClip);
+ EXPECT_EQ(2, skiaCanvas.getSaveCount());
+ EXPECT_EQ(2, opCanvas.saveCount());
+
+ skiaCanvas.restore();
+ opCanvas.restore();
+ EXPECT_EQ(1, skiaCanvas.getSaveCount());
+ EXPECT_EQ(1, opCanvas.saveCount());
+
+ skiaCanvas.restore();
+ opCanvas.restore();
+ EXPECT_EQ(1, skiaCanvas.getSaveCount());
+ EXPECT_EQ(1, opCanvas.saveCount());
+
+ EXPECT_EQ(1, receiver[Op::Save]);
+ EXPECT_EQ(1, receiver[Op::Restore]);
+}
+
+TEST(CanvasOp, frontendTransform) {
+
} \ No newline at end of file
diff --git a/libs/hwui/tests/unit/CommonPoolTests.cpp b/libs/hwui/tests/unit/CommonPoolTests.cpp
index da6a2604a4b6..bffdeca4db54 100644
--- a/libs/hwui/tests/unit/CommonPoolTests.cpp
+++ b/libs/hwui/tests/unit/CommonPoolTests.cpp
@@ -54,7 +54,9 @@ TEST(DISABLED_CommonPool, threadCount) {
EXPECT_EQ(0, threads.count(gettid()));
}
-TEST(CommonPool, singleThread) {
+// Disabled since this is flaky. This isn't a necessarily useful functional test, so being
+// disabled isn't that significant. However it may be good to resurrect this somehow.
+TEST(CommonPool, DISABLED_singleThread) {
std::mutex mutex;
std::condition_variable fence;
bool isProcessing = false;
diff --git a/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp b/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp
index accf0f4f2aaa..26bc65915c7a 100644
--- a/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp
+++ b/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp
@@ -1107,26 +1107,26 @@ TEST(ReorderBarrierDrawable, testShadowMatrix) {
EXPECT_EQ(dy, TRANSLATE_Y);
}
- virtual void didSetMatrix(const SkMatrix& matrix) override {
+ virtual void didSetM44(const SkM44& matrix) override {
mDrawCounter++;
// First invocation is EndReorderBarrierDrawable::drawShadow to apply shadow matrix.
// Second invocation is preparing the matrix for an elevated RenderNodeDrawable.
- EXPECT_TRUE(matrix.isIdentity());
+ EXPECT_TRUE(matrix == SkM44());
EXPECT_TRUE(getTotalMatrix().isIdentity());
}
- virtual void didConcat(const SkMatrix& matrix) override {
+ virtual void didConcat44(const SkM44& matrix) override {
mDrawCounter++;
if (mFirstDidConcat) {
// First invocation is EndReorderBarrierDrawable::drawShadow to apply shadow matrix.
mFirstDidConcat = false;
- EXPECT_EQ(SkMatrix::Translate(CASTER_X + TRANSLATE_X, CASTER_Y + TRANSLATE_Y),
+ EXPECT_EQ(SkM44::Translate(CASTER_X + TRANSLATE_X, CASTER_Y + TRANSLATE_Y),
matrix);
EXPECT_EQ(SkMatrix::Translate(CASTER_X + TRANSLATE_X, CASTER_Y + TRANSLATE_Y),
getTotalMatrix());
} else {
// Second invocation is preparing the matrix for an elevated RenderNodeDrawable.
- EXPECT_EQ(SkMatrix::Translate(TRANSLATE_X, TRANSLATE_Y), matrix);
+ EXPECT_EQ(SkM44::Translate(TRANSLATE_X, TRANSLATE_Y), matrix);
EXPECT_EQ(SkMatrix::Translate(TRANSLATE_X, TRANSLATE_Y), getTotalMatrix());
}
}
diff --git a/libs/hwui/tests/unit/RenderNodeTests.cpp b/libs/hwui/tests/unit/RenderNodeTests.cpp
index c19e1ed6ce75..4659a929a9eb 100644
--- a/libs/hwui/tests/unit/RenderNodeTests.cpp
+++ b/libs/hwui/tests/unit/RenderNodeTests.cpp
@@ -264,6 +264,8 @@ TEST(RenderNode, releasedCallback) {
TestUtils::runOnRenderThreadUnmanaged([&] (RenderThread&) {
TestUtils::syncHierarchyPropertiesAndDisplayList(node);
});
+ // Fence on any remaining post'd work
+ TestUtils::runOnRenderThreadUnmanaged([] (RenderThread&) {});
EXPECT_EQ(2, counts.sync);
EXPECT_EQ(1, counts.destroyed);
}
diff --git a/media/java/android/media/metrics/IPlaybackMetricsManager.aidl b/media/java/android/media/metrics/IPlaybackMetricsManager.aidl
index fcb7d608f662..47debe90c854 100644
--- a/media/java/android/media/metrics/IPlaybackMetricsManager.aidl
+++ b/media/java/android/media/metrics/IPlaybackMetricsManager.aidl
@@ -23,5 +23,6 @@ import android.media.metrics.PlaybackMetrics;
* @hide
*/
interface IPlaybackMetricsManager {
- void reportPlaybackMetrics(in PlaybackMetrics metrics, int userId);
+ void reportPlaybackMetrics(in String sessionId, in PlaybackMetrics metrics, int userId);
+ String getSessionId(int userId);
} \ No newline at end of file
diff --git a/media/java/android/media/metrics/PlaybackMetricsManager.java b/media/java/android/media/metrics/PlaybackMetricsManager.java
index 3606f53d7220..d51ff473696d 100644
--- a/media/java/android/media/metrics/PlaybackMetricsManager.java
+++ b/media/java/android/media/metrics/PlaybackMetricsManager.java
@@ -16,6 +16,7 @@
package android.media.metrics;
+import android.annotation.NonNull;
import android.os.RemoteException;
/**
@@ -38,10 +39,24 @@ public class PlaybackMetricsManager {
/**
* Reports playback metrics.
+ * @hide
+ */
+ public void reportPlaybackMetrics(@NonNull String sessionId, PlaybackMetrics metrics) {
+ try {
+ mService.reportPlaybackMetrics(sessionId, metrics, mUserId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Creates a playback session.
*/
- public void reportPlaybackMetrics(PlaybackMetrics metrics) {
+ public PlaybackSession createSession() {
try {
- mService.reportPlaybackMetrics(metrics, mUserId);
+ String id = mService.getSessionId(mUserId);
+ PlaybackSession session = new PlaybackSession(id, this);
+ return session;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/media/java/android/media/metrics/PlaybackSession.java b/media/java/android/media/metrics/PlaybackSession.java
new file mode 100644
index 000000000000..4ad89067952c
--- /dev/null
+++ b/media/java/android/media/metrics/PlaybackSession.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.metrics;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+import com.android.internal.util.AnnotationValidations;
+
+import java.util.Objects;
+
+/**
+ * @hide
+ */
+public final class PlaybackSession implements AutoCloseable {
+ private final @NonNull String mId;
+ private final @NonNull PlaybackMetricsManager mManager;
+ private boolean mClosed = false;
+
+ /**
+ * Creates a new PlaybackSession.
+ *
+ * @hide
+ */
+ public PlaybackSession(@NonNull String id, @NonNull PlaybackMetricsManager manager) {
+ mId = id;
+ mManager = manager;
+ AnnotationValidations.validate(NonNull.class, null, mId);
+ AnnotationValidations.validate(NonNull.class, null, mManager);
+ }
+
+ /**
+ * Reports playback metrics.
+ */
+ public void reportPlaybackMetrics(@NonNull PlaybackMetrics metrics) {
+ mManager.reportPlaybackMetrics(mId, metrics);
+ }
+
+ public @NonNull String getId() {
+ return mId;
+ }
+
+ @Override
+ public boolean equals(@Nullable Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ PlaybackSession that = (PlaybackSession) o;
+ return Objects.equals(mId, that.mId);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mId);
+ }
+
+ @Override
+ public void close() throws Exception {
+ mClosed = true;
+ }
+}
diff --git a/media/java/android/media/tv/tuner/Tuner.java b/media/java/android/media/tv/tuner/Tuner.java
index a9da77230214..c2613716cd07 100644
--- a/media/java/android/media/tv/tuner/Tuner.java
+++ b/media/java/android/media/tv/tuner/Tuner.java
@@ -308,6 +308,7 @@ public class Tuner implements AutoCloseable {
.write(FrameworkStatsLog.TV_TUNER_STATE_CHANGED, mUserId,
FrameworkStatsLog.TV_TUNER_STATE_CHANGED__STATE__UNKNOWN);
}
+ releaseAll();
mHandler.sendMessage(mHandler.obtainMessage(MSG_RESOURCE_LOST));
}
};
@@ -610,7 +611,6 @@ public class Tuner implements AutoCloseable {
break;
}
case MSG_RESOURCE_LOST: {
- releaseAll();
if (mOnResourceLostListener != null
&& mOnResourceLostListenerExecutor != null) {
mOnResourceLostListenerExecutor.execute(
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/InstallInstalling.java b/packages/PackageInstaller/src/com/android/packageinstaller/InstallInstalling.java
index a9c754d3df79..c6c7142c3bd0 100755
--- a/packages/PackageInstaller/src/com/android/packageinstaller/InstallInstalling.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/InstallInstalling.java
@@ -410,7 +410,7 @@ public class InstallInstalling extends AlertActivity {
InstallInstalling.this,
mInstallId,
broadcastIntent,
- PendingIntent.FLAG_UPDATE_CURRENT);
+ PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE);
session.commit(pendingIntent.getIntentSender());
mCancelButton.setEnabled(false);
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstalledNotificationUtils.java b/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstalledNotificationUtils.java
index caf971800ad2..eea12eca1859 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstalledNotificationUtils.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstalledNotificationUtils.java
@@ -243,8 +243,8 @@ class PackageInstalledNotificationUtils {
}
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- return PendingIntent.getActivity(mContext,
- 0 /* request code */, intent, PendingIntent.FLAG_UPDATE_CURRENT);
+ return PendingIntent.getActivity(mContext, 0 /* request code */, intent,
+ PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
}
/**
@@ -260,8 +260,8 @@ class PackageInstalledNotificationUtils {
}
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- return PendingIntent.getActivity(mContext,
- 0 /* request code */, intent, PendingIntent.FLAG_UPDATE_CURRENT);
+ return PendingIntent.getActivity(mContext, 0 /* request code */, intent,
+ PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
}
/**
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/UninstallUninstalling.java b/packages/PackageInstaller/src/com/android/packageinstaller/UninstallUninstalling.java
index c4dceb4fe079..7bf27dfe6420 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/UninstallUninstalling.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/UninstallUninstalling.java
@@ -95,7 +95,8 @@ public class UninstallUninstalling extends Activity implements
broadcastIntent.setPackage(getPackageName());
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, mUninstallId,
- broadcastIntent, PendingIntent.FLAG_UPDATE_CURRENT);
+ broadcastIntent, PendingIntent.FLAG_UPDATE_CURRENT
+ | PendingIntent.FLAG_MUTABLE);
int flags = allUsers ? PackageManager.DELETE_ALL_USERS : 0;
flags |= keepData ? PackageManager.DELETE_KEEP_DATA : 0;
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/wear/PackageInstallerImpl.java b/packages/PackageInstaller/src/com/android/packageinstaller/wear/PackageInstallerImpl.java
index bf4b03c56b79..7e0490a233f9 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/wear/PackageInstallerImpl.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/wear/PackageInstallerImpl.java
@@ -269,7 +269,8 @@ public class PackageInstallerImpl {
// Create a matching PendingIntent and use it to generate the IntentSender
Intent broadcastIntent = new Intent(action);
PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, packageName.hashCode(),
- broadcastIntent, PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_UPDATE_CURRENT);
+ broadcastIntent, PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_UPDATE_CURRENT
+ | PendingIntent.FLAG_MUTABLE);
return pendingIntent.getIntentSender();
}
diff --git a/packages/SettingsLib/res/values-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml
index 2b30e0a61863..41af185da0b7 100644
--- a/packages/SettingsLib/res/values-af/strings.xml
+++ b/packages/SettingsLib/res/values-af/strings.xml
@@ -449,8 +449,7 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"<xliff:g id="TIME">%1$s</xliff:g> oor tot battery gelaai is"</string>
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> tot battery gelaai is"</string>
- <!-- no translation found for power_charging_limited (5902301801611726210) -->
- <skip />
+ <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> – Battery word tydelik beperk"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Onbekend"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Laai"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Laai tans vinnig"</string>
diff --git a/packages/SettingsLib/res/values-am/strings.xml b/packages/SettingsLib/res/values-am/strings.xml
index 0bebfabf2eb9..8e4e402c2e16 100644
--- a/packages/SettingsLib/res/values-am/strings.xml
+++ b/packages/SettingsLib/res/values-am/strings.xml
@@ -449,8 +449,7 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"<xliff:g id="TIME">%1$s</xliff:g> ኃይል እስከሚሞላ ድረስ ይቀራል"</string>
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> ኃይል እስከሚሞላ ድረስ"</string>
- <!-- no translation found for power_charging_limited (5902301801611726210) -->
- <skip />
+ <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> - ባትሪ ለጊዜው ተገድቧል"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"ያልታወቀ"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"ኃይል በመሙላት ላይ"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"ኃይል በፍጥነት በመሙላት ላይ"</string>
diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml
index 6eaf3a98da11..691ec046da02 100644
--- a/packages/SettingsLib/res/values-ar/strings.xml
+++ b/packages/SettingsLib/res/values-ar/strings.xml
@@ -449,8 +449,7 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"<xliff:g id="TIME">%1$s</xliff:g> إلى أن يتم شحن الجهاز بالكامل"</string>
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> إلى أن يتم شحن الجهاز بالكامل"</string>
- <!-- no translation found for power_charging_limited (5902301801611726210) -->
- <skip />
+ <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> - تأثير محدود على البطارية مؤقتًا"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"غير معروف"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"جارٍ الشحن"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"جارٍ الشحن سريعًا"</string>
diff --git a/packages/SettingsLib/res/values-as/strings.xml b/packages/SettingsLib/res/values-as/strings.xml
index e207e1ce4c12..61214e09ba26 100644
--- a/packages/SettingsLib/res/values-as/strings.xml
+++ b/packages/SettingsLib/res/values-as/strings.xml
@@ -449,8 +449,7 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"চাৰ্জ হ’বলৈ <xliff:g id="TIME">%1$s</xliff:g> বাকী আছে"</string>
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> চাৰ্জ হ\'বলৈ"</string>
- <!-- no translation found for power_charging_limited (5902301801611726210) -->
- <skip />
+ <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> - বেটাৰী সাময়িকভাৱে সীমিত কৰা হৈছে"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"অজ্ঞাত"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"চাৰ্জ কৰি থকা হৈছে"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"দ্ৰুততাৰে চাৰ্জ হৈছে"</string>
diff --git a/packages/SettingsLib/res/values-az/strings.xml b/packages/SettingsLib/res/values-az/strings.xml
index ff1209c754d1..db61527a54d8 100644
--- a/packages/SettingsLib/res/values-az/strings.xml
+++ b/packages/SettingsLib/res/values-az/strings.xml
@@ -449,8 +449,7 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"Enerjinin dolmasına <xliff:g id="TIME">%1$s</xliff:g> qalıb"</string>
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - Enerjinin dolmasına <xliff:g id="TIME">%2$s</xliff:g> qalıb"</string>
- <!-- no translation found for power_charging_limited (5902301801611726210) -->
- <skip />
+ <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> - Batareya müvəqqəti məhdudlaşdırılıb"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Naməlum"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Enerji doldurma"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Sürətlə doldurulur"</string>
diff --git a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
index eb099c1926a7..70fb3636b492 100644
--- a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
+++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
@@ -449,8 +449,7 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"Napuniće se za <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> – napuniće se za <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <!-- no translation found for power_charging_limited (5902301801611726210) -->
- <skip />
+ <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> – baterija je trenutno ograničena"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Nepoznato"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Puni se"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Brzo se puni"</string>
diff --git a/packages/SettingsLib/res/values-be/strings.xml b/packages/SettingsLib/res/values-be/strings.xml
index e6e49ab2063c..8a0db8261a71 100644
--- a/packages/SettingsLib/res/values-be/strings.xml
+++ b/packages/SettingsLib/res/values-be/strings.xml
@@ -449,8 +449,7 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"Засталося <xliff:g id="TIME">%1$s</xliff:g> да поўнай зарадкі"</string>
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> да поўнай зарадкі"</string>
- <!-- no translation found for power_charging_limited (5902301801611726210) -->
- <skip />
+ <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> – зарад акумулятара часова абмежаваны"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Невядома"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Зарадка"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Хуткая зарадка"</string>
diff --git a/packages/SettingsLib/res/values-bg/strings.xml b/packages/SettingsLib/res/values-bg/strings.xml
index 251c4dd545c4..27dcf105fd2e 100644
--- a/packages/SettingsLib/res/values-bg/strings.xml
+++ b/packages/SettingsLib/res/values-bg/strings.xml
@@ -449,8 +449,7 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"Оставащо време до пълно зареждане: <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> до пълно зареждане"</string>
- <!-- no translation found for power_charging_limited (5902301801611726210) -->
- <skip />
+ <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> – Батерията е временно ограничена"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Неизвестно"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Зарежда се"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Зарежда се бързо"</string>
diff --git a/packages/SettingsLib/res/values-bn/strings.xml b/packages/SettingsLib/res/values-bn/strings.xml
index 6a99a84358d4..29862e6efd31 100644
--- a/packages/SettingsLib/res/values-bn/strings.xml
+++ b/packages/SettingsLib/res/values-bn/strings.xml
@@ -211,9 +211,9 @@
<string name="adb_wireless_error" msgid="721958772149779856">"সমস্যা"</string>
<string name="adb_wireless_settings" msgid="2295017847215680229">"ওয়্যারলেস ডিবাগিং"</string>
<string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"কোন কোন ডিভাইস উপলভ্য আছে তা দেখে নিয়ে ব্যবহার করার জন্য, ওয়্যারলেস ডিবাগিং চালু করুন"</string>
- <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"QR কোড ব্যবহার করে ডিভাইস যোগ করুন"</string>
+ <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"QR কোড ব্যবহার করে ডিভাইসের সাথে পেয়ার করুন"</string>
<string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"QR কোড স্ক্যানার ব্যবহার করে নতুন ডিভাইস যোগ করুন"</string>
- <string name="adb_pair_method_code_title" msgid="1122590300445142904">"যোগ করার কোড ব্যবহার করে ডিভাইস যোগ করুন"</string>
+ <string name="adb_pair_method_code_title" msgid="1122590300445142904">"পেয়ারিং কোড ব্যবহার করে ডিভাইসের সাথে পেয়ার করুন"</string>
<string name="adb_pair_method_code_summary" msgid="6370414511333685185">"ছয় সংখ্যার কোড ব্যবহার করে নতুন ডিভাইস যোগ করুন"</string>
<string name="adb_paired_devices_title" msgid="5268997341526217362">"যোগ করা ডিভাইস"</string>
<string name="adb_wireless_device_connected_summary" msgid="3039660790249148713">"এখন কানেক্ট রয়েছে"</string>
@@ -222,16 +222,16 @@
<string name="adb_device_fingerprint_title_format" msgid="291504822917843701">"ডিভাইসে আঙ্গুলের ছাপ: <xliff:g id="FINGERPRINT_PARAM">%1$s</xliff:g>"</string>
<string name="adb_wireless_connection_failed_title" msgid="664211177427438438">"কানেক্ট করা যায়নি"</string>
<string name="adb_wireless_connection_failed_message" msgid="9213896700171602073">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>টি সঠিক নেটওয়ার্কে কানেক্ট আছে কিনা দেখে নিন"</string>
- <string name="adb_pairing_device_dialog_title" msgid="7141739231018530210">"ডিভাইসের সাথে যোগ করুন"</string>
- <string name="adb_pairing_device_dialog_pairing_code_label" msgid="3639239786669722731">"ওয়াই-ফাই যোগ করার কোড"</string>
- <string name="adb_pairing_device_dialog_failed_title" msgid="3426758947882091735">"যোগ করা যায়নি"</string>
+ <string name="adb_pairing_device_dialog_title" msgid="7141739231018530210">"ডিভাইসের সাথে পেয়ার করুন"</string>
+ <string name="adb_pairing_device_dialog_pairing_code_label" msgid="3639239786669722731">"ওয়াই-ফাইয়ের সাথে পেয়ার করার কোড"</string>
+ <string name="adb_pairing_device_dialog_failed_title" msgid="3426758947882091735">"পেয়ার করা যায়নি"</string>
<string name="adb_pairing_device_dialog_failed_msg" msgid="6611097519661997148">"ডিভাইসটি একই নেটওয়ার্কে কানেক্ট আছে কিনা দেখে নিন।"</string>
- <string name="adb_wireless_qrcode_summary" msgid="8051414549011801917">"QR কোড স্ক্যান করে ওয়াই-ফাই ব্যবহার করে ডিভাইস যোগ করুন"</string>
+ <string name="adb_wireless_qrcode_summary" msgid="8051414549011801917">"QR কোড স্ক্যান করে ওয়াই-ফাই ব্যবহার করে ডিভাইসের সাথে পেয়ার করুন"</string>
<string name="adb_wireless_verifying_qrcode_text" msgid="6123192424916029207">"ডিভাইস যোগ করা হচ্ছে…"</string>
<string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"ডিভাইস যোগ করা যায়নি। এটি দুটি কারণে হয়ে থাকে - QR কোডটি সঠিক নয় বা ডিভাইসটি একই নেটওয়ার্কে কানেক্ট করা নেই।"</string>
<string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"IP অ্যাড্রেস ও পোর্ট"</string>
<string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"QR কোড স্ক্যান করুন"</string>
- <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"QR কোড স্ক্যান করে ওয়াই-ফাইয়ের সাহায্যে ডিভাইস যোগ করুন"</string>
+ <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"QR কোড স্ক্যান করে ওয়াই-ফাই ব্যবহার করে ডিভাইসের সাথে পেয়ার করুন"</string>
<string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"একটি ওয়াই-ফাই নেটওয়ার্কের সাথে কানেক্ট করুন"</string>
<string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, debug, dev"</string>
<string name="bugreport_in_power" msgid="8664089072534638709">"ত্রুটি প্রতিবেদনের শর্টকাট"</string>
@@ -449,8 +449,7 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"সম্পূর্ণ চার্জ হতে <xliff:g id="TIME">%1$s</xliff:g> বাকি আছে"</string>
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g>-এ সম্পূর্ণ চার্জ হয়ে যাবে"</string>
- <!-- no translation found for power_charging_limited (5902301801611726210) -->
- <skip />
+ <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> - ব্যাটারি কিছুক্ষণের জন্য সীমিত করা হয়েছে"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"অজানা"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"চার্জ হচ্ছে"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"দ্রুত চার্জ হচ্ছে"</string>
diff --git a/packages/SettingsLib/res/values-bs/strings.xml b/packages/SettingsLib/res/values-bs/strings.xml
index aeb7f2ecc567..4704ec8db79a 100644
--- a/packages/SettingsLib/res/values-bs/strings.xml
+++ b/packages/SettingsLib/res/values-bs/strings.xml
@@ -449,8 +449,7 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"Napunit će se za <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> – napunit će se za <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <!-- no translation found for power_charging_limited (5902301801611726210) -->
- <skip />
+ <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> – Baterija je privremeno ograničena"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Nepoznato"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Punjenje"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Brzo punjenje"</string>
diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml
index df4c99e20505..5d04963d9b4a 100644
--- a/packages/SettingsLib/res/values-ca/strings.xml
+++ b/packages/SettingsLib/res/values-ca/strings.xml
@@ -66,7 +66,7 @@
<string name="bluetooth_disconnected" msgid="7739366554710388701">"Desconnectat"</string>
<string name="bluetooth_disconnecting" msgid="7638892134401574338">"S\'està desconnectant..."</string>
<string name="bluetooth_connecting" msgid="5871702668260192755">"S\'està connectant…"</string>
- <string name="bluetooth_connected" msgid="8065345572198502293">"<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g> connectat"</string>
+ <string name="bluetooth_connected" msgid="8065345572198502293">"<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g> Connectat"</string>
<string name="bluetooth_pairing" msgid="4269046942588193600">"S\'està vinculant..."</string>
<string name="bluetooth_connected_no_headset" msgid="2224101138659967604">"<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g> connectat (sense accés al telèfon)"</string>
<string name="bluetooth_connected_no_a2dp" msgid="8566874395813947092">"<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g> connectat (sense contingut multimèdia)"</string>
@@ -449,8 +449,7 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g>: <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"<xliff:g id="TIME">%1$s</xliff:g> per completar la càrrega"</string>
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g>: <xliff:g id="TIME">%2$s</xliff:g> per completar la càrrega"</string>
- <!-- no translation found for power_charging_limited (5902301801611726210) -->
- <skip />
+ <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g>: bateria limitada temporalment"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Desconegut"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"S\'està carregant"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Carregant ràpidament"</string>
diff --git a/packages/SettingsLib/res/values-cs/strings.xml b/packages/SettingsLib/res/values-cs/strings.xml
index e563ca5a03f8..a99a4dabbc60 100644
--- a/packages/SettingsLib/res/values-cs/strings.xml
+++ b/packages/SettingsLib/res/values-cs/strings.xml
@@ -449,8 +449,7 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"Do nabití zbývá: <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> do nabití"</string>
- <!-- no translation found for power_charging_limited (5902301801611726210) -->
- <skip />
+ <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> – Baterie dočasně omezena"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Neznámé"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Nabíjí se"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Rychlé nabíjení"</string>
diff --git a/packages/SettingsLib/res/values-da/strings.xml b/packages/SettingsLib/res/values-da/strings.xml
index 8a3d054c3ae8..c90155eb2b68 100644
--- a/packages/SettingsLib/res/values-da/strings.xml
+++ b/packages/SettingsLib/res/values-da/strings.xml
@@ -449,8 +449,7 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"Opladet om <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> – opladet om <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <!-- no translation found for power_charging_limited (5902301801611726210) -->
- <skip />
+ <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> – Batteriet er midlertidigt begrænset"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Ukendt"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Oplader"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Oplader hurtigt"</string>
diff --git a/packages/SettingsLib/res/values-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml
index 624b299a96c3..b5b9fc480607 100644
--- a/packages/SettingsLib/res/values-de/strings.xml
+++ b/packages/SettingsLib/res/values-de/strings.xml
@@ -399,12 +399,9 @@
<string name="inactive_app_inactive_summary" msgid="3161222402614236260">"Inaktiv. Zum Wechseln tippen."</string>
<string name="inactive_app_active_summary" msgid="8047630990208722344">"Aktiv. Zum Wechseln tippen."</string>
<string name="standby_bucket_summary" msgid="5128193447550429600">"Standby-Status der App:<xliff:g id="BUCKET"> %s</xliff:g>"</string>
- <!-- no translation found for transcode_settings_title (2581975870429850549) -->
- <skip />
- <!-- no translation found for transcode_enable_all (9102460144086871903) -->
- <skip />
- <!-- no translation found for transcode_skip_apps (8249721984597390142) -->
- <skip />
+ <string name="transcode_settings_title" msgid="2581975870429850549">"Einstellungen für Medientranscodierung"</string>
+ <string name="transcode_enable_all" msgid="9102460144086871903">"Transcodierung deaktivieren"</string>
+ <string name="transcode_skip_apps" msgid="8249721984597390142">"Transcodierung für Apps aktivieren"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"Aktive Dienste"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"Momentan ausgeführte Dienste anzeigen und steuern"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView-Implementierung"</string>
@@ -452,8 +449,7 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"Noch <xliff:g id="TIME">%1$s</xliff:g> bis zur Aufladung"</string>
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> bis zur Aufladung"</string>
- <!-- no translation found for power_charging_limited (5902301801611726210) -->
- <skip />
+ <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> – Akku vorübergehend eingeschränkt"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Unbekannt"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Wird aufgeladen"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Schnelles Aufladen"</string>
diff --git a/packages/SettingsLib/res/values-el/strings.xml b/packages/SettingsLib/res/values-el/strings.xml
index 7ea90506ac06..203ec40c5a42 100644
--- a/packages/SettingsLib/res/values-el/strings.xml
+++ b/packages/SettingsLib/res/values-el/strings.xml
@@ -449,8 +449,7 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"Απομένουν <xliff:g id="TIME">%1$s</xliff:g> για ολοκλήρωση της φόρτισης"</string>
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> για την ολοκλήρωση της φόρτισης"</string>
- <!-- no translation found for power_charging_limited (5902301801611726210) -->
- <skip />
+ <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> - Η μπαταρία περιορίστηκε προσωρινά."</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Άγνωστο"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Φόρτιση"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Ταχεία φόρτιση"</string>
diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml
index 7affb5c89dfc..08ff55099c9c 100644
--- a/packages/SettingsLib/res/values-es-rUS/strings.xml
+++ b/packages/SettingsLib/res/values-es-rUS/strings.xml
@@ -196,7 +196,7 @@
<string name="choose_profile" msgid="343803890897657450">"Elegir perfil"</string>
<string name="category_personal" msgid="6236798763159385225">"Personal"</string>
<string name="category_work" msgid="4014193632325996115">"Trabajo"</string>
- <string name="development_settings_title" msgid="140296922921597393">"Opciones para programadores"</string>
+ <string name="development_settings_title" msgid="140296922921597393">"Opciones para desarrolladores"</string>
<string name="development_settings_enable" msgid="4285094651288242183">"Activar opciones para programador"</string>
<string name="development_settings_summary" msgid="8718917813868735095">"Establecer opciones para desarrollar aplicaciones"</string>
<string name="development_settings_not_available" msgid="355070198089140951">"Las opciones de programador no están disponibles para este usuario."</string>
@@ -449,8 +449,7 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g>: <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"<xliff:g id="TIME">%1$s</xliff:g> para completar la carga"</string>
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> para completar la carga"</string>
- <!-- no translation found for power_charging_limited (5902301801611726210) -->
- <skip />
+ <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> - Batería limitada temporalmente"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Desconocido"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Cargando"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Cargando rápido"</string>
diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml
index ccdc1c443fbd..6f6a1a1c9b17 100644
--- a/packages/SettingsLib/res/values-es/strings.xml
+++ b/packages/SettingsLib/res/values-es/strings.xml
@@ -449,8 +449,7 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"<xliff:g id="TIME">%1$s</xliff:g> hasta cargarse completamente"</string>
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> (<xliff:g id="TIME">%2$s</xliff:g> hasta cargarse completamente)"</string>
- <!-- no translation found for power_charging_limited (5902301801611726210) -->
- <skip />
+ <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g>: batería limitada temporalmente"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Desconocido"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Cargando"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Cargando rápidamente"</string>
diff --git a/packages/SettingsLib/res/values-et/strings.xml b/packages/SettingsLib/res/values-et/strings.xml
index 852d6df7d31e..9d6326e45706 100644
--- a/packages/SettingsLib/res/values-et/strings.xml
+++ b/packages/SettingsLib/res/values-et/strings.xml
@@ -449,8 +449,7 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"Täislaadimiseni on jäänud <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> täislaadimiseni"</string>
- <!-- no translation found for power_charging_limited (5902301801611726210) -->
- <skip />
+ <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> – akutase on ajutiselt piiratud"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Tundmatu"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Laadimine"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Kiirlaadimine"</string>
diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml
index 6b6b9b63df65..01afa1706e3e 100644
--- a/packages/SettingsLib/res/values-eu/strings.xml
+++ b/packages/SettingsLib/res/values-eu/strings.xml
@@ -449,8 +449,7 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"<xliff:g id="TIME">%1$s</xliff:g> guztiz kargatu arte"</string>
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> guztiz kargatu arte"</string>
- <!-- no translation found for power_charging_limited (5902301801611726210) -->
- <skip />
+ <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g>: bateria mugatuta egongo da aldi batez"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Ezezaguna"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Kargatzen"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Bizkor kargatzen"</string>
diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml
index af1e55be67c5..dd7ab9672e96 100644
--- a/packages/SettingsLib/res/values-fa/strings.xml
+++ b/packages/SettingsLib/res/values-fa/strings.xml
@@ -449,8 +449,7 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - ‏<xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"<xliff:g id="TIME">%1$s</xliff:g> مانده تا شارژ کامل"</string>
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> تا شارژ کامل"</string>
- <!-- no translation found for power_charging_limited (5902301801611726210) -->
- <skip />
+ <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> - باتری موقتاً محدود شده است"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"ناشناس"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"در حال شارژ شدن"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"درحال شارژ شدن سریع"</string>
diff --git a/packages/SettingsLib/res/values-fi/strings.xml b/packages/SettingsLib/res/values-fi/strings.xml
index 8e819efe3557..b86b02d8c25f 100644
--- a/packages/SettingsLib/res/values-fi/strings.xml
+++ b/packages/SettingsLib/res/values-fi/strings.xml
@@ -449,8 +449,7 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"<xliff:g id="TIME">%1$s</xliff:g> jäljellä täyteen lataukseen"</string>
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> täyteen lataukseen"</string>
- <!-- no translation found for power_charging_limited (5902301801611726210) -->
- <skip />
+ <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> – Akun käyttöä rajoitettu tilapäisesti"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Tuntematon"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Ladataan"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Nopea lataus"</string>
diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml
index 4754d15b5a52..0bca1dba1aa4 100644
--- a/packages/SettingsLib/res/values-fr-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml
@@ -449,8 +449,7 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"<xliff:g id="TIME">%1$s</xliff:g> jusqu\'à la charge complète"</string>
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> : <xliff:g id="TIME">%2$s</xliff:g> jusqu\'à la charge complète"</string>
- <!-- no translation found for power_charging_limited (5902301801611726210) -->
- <skip />
+ <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> – Pile limitée temporairement"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Inconnu"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Charge en cours…"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Recharge rapide"</string>
diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml
index a3863f596067..ebde43ba52a2 100644
--- a/packages/SettingsLib/res/values-fr/strings.xml
+++ b/packages/SettingsLib/res/values-fr/strings.xml
@@ -449,8 +449,7 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"<xliff:g id="TIME">%1$s</xliff:g> jusqu\'à ce que la batterie soit chargée"</string>
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> jusqu\'à la charge complète"</string>
- <!-- no translation found for power_charging_limited (5902301801611726210) -->
- <skip />
+ <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> - Batterie limitée temporairement"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Inconnu"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Batterie en charge"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Charge rapide"</string>
diff --git a/packages/SettingsLib/res/values-gl/strings.xml b/packages/SettingsLib/res/values-gl/strings.xml
index 81e79e4a27a9..b040817b2801 100644
--- a/packages/SettingsLib/res/values-gl/strings.xml
+++ b/packages/SettingsLib/res/values-gl/strings.xml
@@ -449,8 +449,7 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"<xliff:g id="TIME">%1$s</xliff:g> para completar a carga"</string>
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g>: <xliff:g id="TIME">%2$s</xliff:g> para completar a carga"</string>
- <!-- no translation found for power_charging_limited (5902301801611726210) -->
- <skip />
+ <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> (batería limitada temporalmente)"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Descoñecido"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Cargando"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Cargando rapidamente"</string>
diff --git a/packages/SettingsLib/res/values-gu/strings.xml b/packages/SettingsLib/res/values-gu/strings.xml
index 9bf09704a4f5..c1bd7cac30a6 100644
--- a/packages/SettingsLib/res/values-gu/strings.xml
+++ b/packages/SettingsLib/res/values-gu/strings.xml
@@ -399,12 +399,9 @@
<string name="inactive_app_inactive_summary" msgid="3161222402614236260">"નિષ્ક્રિય. ટોગલ કરવા માટે ટૅપ કરો."</string>
<string name="inactive_app_active_summary" msgid="8047630990208722344">"સક્રિય. ટોગલ કરવા માટે ટૅપ કરો."</string>
<string name="standby_bucket_summary" msgid="5128193447550429600">"ઍપ સ્ટૅન્ડબાયની સ્થિતિ:<xliff:g id="BUCKET"> %s</xliff:g>"</string>
- <!-- no translation found for transcode_settings_title (2581975870429850549) -->
- <skip />
- <!-- no translation found for transcode_enable_all (9102460144086871903) -->
- <skip />
- <!-- no translation found for transcode_skip_apps (8249721984597390142) -->
- <skip />
+ <string name="transcode_settings_title" msgid="2581975870429850549">"મીડિયાનું ફૉર્મેટ બદલવાની પ્રક્રિયાના સેટિંગ"</string>
+ <string name="transcode_enable_all" msgid="9102460144086871903">"ફૉર્મેટ બદલવાની પ્રક્રિયા બંધ કરો"</string>
+ <string name="transcode_skip_apps" msgid="8249721984597390142">"ઍપ માટે ફૉર્મેટ બદલવાની પ્રક્રિયા ચાલુ કરો"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"ચાલુ સેવાઓ"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"હાલમાં ચાલતી સેવાઓ જુઓ અને નિયંત્રિત કરો"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView અમલીકરણ"</string>
@@ -452,8 +449,7 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"ચાર્જ થવામાં <xliff:g id="TIME">%1$s</xliff:g> બાકી છે"</string>
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - ચાર્જ થવા માટે <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <!-- no translation found for power_charging_limited (5902301801611726210) -->
- <skip />
+ <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> - બૅટરીનો વપરાશ હંગામી રૂપે મર્યાદિત છે"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"અજાણ્યું"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"ચાર્જ થઈ રહ્યું છે"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"ઝડપથી ચાર્જ થાય છે"</string>
diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml
index 151b861cbd3b..d9153a1ab542 100644
--- a/packages/SettingsLib/res/values-hi/strings.xml
+++ b/packages/SettingsLib/res/values-hi/strings.xml
@@ -449,8 +449,7 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"चार्ज पूरा होने में <xliff:g id="TIME">%1$s</xliff:g> बचा है"</string>
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> में पूरा चार्ज हो जाएगा"</string>
- <!-- no translation found for power_charging_limited (5902301801611726210) -->
- <skip />
+ <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> - कुछ समय के लिए, बैटरी का सीमित इस्तेमाल होगा"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"अज्ञात"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"चार्ज हो रही है"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"तेज़ चार्ज हो रही है"</string>
diff --git a/packages/SettingsLib/res/values-hr/strings.xml b/packages/SettingsLib/res/values-hr/strings.xml
index d37879f6e153..b51e096ca6b7 100644
--- a/packages/SettingsLib/res/values-hr/strings.xml
+++ b/packages/SettingsLib/res/values-hr/strings.xml
@@ -449,8 +449,7 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"Napunit će se za <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> – napunit će se za <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <!-- no translation found for power_charging_limited (5902301801611726210) -->
- <skip />
+ <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> – Baterija je privremeno ograničena"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Nepoznato"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Punjenje"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Brzo punjenje"</string>
diff --git a/packages/SettingsLib/res/values-hu/strings.xml b/packages/SettingsLib/res/values-hu/strings.xml
index 4ac5308474c5..33770fc1bdd8 100644
--- a/packages/SettingsLib/res/values-hu/strings.xml
+++ b/packages/SettingsLib/res/values-hu/strings.xml
@@ -449,8 +449,7 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"<xliff:g id="TIME">%1$s</xliff:g> van hátra a feltöltésből"</string>
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> a feltöltésig"</string>
- <!-- no translation found for power_charging_limited (5902301801611726210) -->
- <skip />
+ <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> – Akkumulátor ideiglenesen korlátozva"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Ismeretlen"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Töltés"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Gyorstöltés"</string>
diff --git a/packages/SettingsLib/res/values-hy/strings.xml b/packages/SettingsLib/res/values-hy/strings.xml
index b0734fdee27e..06d70f854f27 100644
--- a/packages/SettingsLib/res/values-hy/strings.xml
+++ b/packages/SettingsLib/res/values-hy/strings.xml
@@ -449,8 +449,7 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"<xliff:g id="TIME">%1$s</xliff:g> մինչև լիցքավորումը"</string>
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> մինչև լիցքավորումը"</string>
- <!-- no translation found for power_charging_limited (5902301801611726210) -->
- <skip />
+ <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> – Մարտկոցը ժամանակավորապես սահմանափակված է"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Անհայտ"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Լիցքավորում"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Արագ լիցքավորում"</string>
diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml
index 9db21c796bbf..4123d9e3b755 100644
--- a/packages/SettingsLib/res/values-in/strings.xml
+++ b/packages/SettingsLib/res/values-in/strings.xml
@@ -449,8 +449,7 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"Sisa <xliff:g id="TIME">%1$s</xliff:g> hingga terisi penuh"</string>
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> lagi terisi penuh"</string>
- <!-- no translation found for power_charging_limited (5902301801611726210) -->
- <skip />
+ <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> - Daya baterai terbatas untuk sementara"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Tidak diketahui"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Mengisi daya"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Mengisi daya cepat"</string>
diff --git a/packages/SettingsLib/res/values-is/strings.xml b/packages/SettingsLib/res/values-is/strings.xml
index d9ee03adefa4..3b9bef872177 100644
--- a/packages/SettingsLib/res/values-is/strings.xml
+++ b/packages/SettingsLib/res/values-is/strings.xml
@@ -449,8 +449,7 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"<xliff:g id="TIME">%1$s</xliff:g> að fullri hleðslu"</string>
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> að fullri hleðslu"</string>
- <!-- no translation found for power_charging_limited (5902301801611726210) -->
- <skip />
+ <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> - Rafhlaða takmörkuð tímabundið"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Óþekkt"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Í hleðslu"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Hröð hleðsla"</string>
diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml
index 57378e78af65..1ab6b24456f3 100644
--- a/packages/SettingsLib/res/values-it/strings.xml
+++ b/packages/SettingsLib/res/values-it/strings.xml
@@ -66,7 +66,7 @@
<string name="bluetooth_disconnected" msgid="7739366554710388701">"Disconnesso"</string>
<string name="bluetooth_disconnecting" msgid="7638892134401574338">"Disconnessione…"</string>
<string name="bluetooth_connecting" msgid="5871702668260192755">"Connessione…"</string>
- <string name="bluetooth_connected" msgid="8065345572198502293">"<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g> connesso"</string>
+ <string name="bluetooth_connected" msgid="8065345572198502293">"<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g> Connesso"</string>
<string name="bluetooth_pairing" msgid="4269046942588193600">"Accoppiamento…"</string>
<string name="bluetooth_connected_no_headset" msgid="2224101138659967604">"<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g> connesso (telefono escluso)"</string>
<string name="bluetooth_connected_no_a2dp" msgid="8566874395813947092">"<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g> connesso (contenuti multimediali esclusi)"</string>
diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml
index fd53f14bd48f..15868d5fc997 100644
--- a/packages/SettingsLib/res/values-iw/strings.xml
+++ b/packages/SettingsLib/res/values-iw/strings.xml
@@ -399,12 +399,9 @@
<string name="inactive_app_inactive_summary" msgid="3161222402614236260">"אפליקציה לא פעילה. הקש כדי להחליף מצב."</string>
<string name="inactive_app_active_summary" msgid="8047630990208722344">"אפליקציה פעילה. הקש כדי להחליף מצב."</string>
<string name="standby_bucket_summary" msgid="5128193447550429600">"אפליקציה במצב המתנה:<xliff:g id="BUCKET"> %s</xliff:g>"</string>
- <!-- no translation found for transcode_settings_title (2581975870429850549) -->
- <skip />
- <!-- no translation found for transcode_enable_all (9102460144086871903) -->
- <skip />
- <!-- no translation found for transcode_skip_apps (8249721984597390142) -->
- <skip />
+ <string name="transcode_settings_title" msgid="2581975870429850549">"הגדרות של המרת קידוד למדיה"</string>
+ <string name="transcode_enable_all" msgid="9102460144086871903">"השבתה של המרת קידוד"</string>
+ <string name="transcode_skip_apps" msgid="8249721984597390142">"הפעלה של המרת קידוד לאפליקציות"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"שירותים פועלים"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"הצגת השירותים הפועלים כעת ושליטה בהם"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"‏יישום WebView"</string>
@@ -452,8 +449,7 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g>‏ - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"נשארו <xliff:g id="TIME">%1$s</xliff:g> עד הטעינה"</string>
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> עד הטעינה"</string>
- <!-- no translation found for power_charging_limited (5902301801611726210) -->
- <skip />
+ <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> - הסוללה מוגבלת באופן זמני"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"לא ידוע"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"בטעינה"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"הסוללה נטענת מהר"</string>
diff --git a/packages/SettingsLib/res/values-ja/strings.xml b/packages/SettingsLib/res/values-ja/strings.xml
index c0aa74bafc56..89ee98eeeb42 100644
--- a/packages/SettingsLib/res/values-ja/strings.xml
+++ b/packages/SettingsLib/res/values-ja/strings.xml
@@ -449,8 +449,7 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"充電完了まであと <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - 充電完了まで <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <!-- no translation found for power_charging_limited (5902301801611726210) -->
- <skip />
+ <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> - 電池の使用が一時的に制限されています"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"不明"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"充電中"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"急速充電中"</string>
diff --git a/packages/SettingsLib/res/values-kk/strings.xml b/packages/SettingsLib/res/values-kk/strings.xml
index 09f3ff5c957a..2bc1c4d20728 100644
--- a/packages/SettingsLib/res/values-kk/strings.xml
+++ b/packages/SettingsLib/res/values-kk/strings.xml
@@ -449,8 +449,7 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"Зарядталғанға дейін <xliff:g id="TIME">%1$s</xliff:g> қалды"</string>
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> – зарядталғанға дейін <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <!-- no translation found for power_charging_limited (5902301801611726210) -->
- <skip />
+ <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> - Батарея жұмысы уақытша шектелген"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Белгісіз"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Зарядталуда"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Жылдам зарядталуда"</string>
diff --git a/packages/SettingsLib/res/values-km/strings.xml b/packages/SettingsLib/res/values-km/strings.xml
index 42e6a53a0078..7306cf8c5d3f 100644
--- a/packages/SettingsLib/res/values-km/strings.xml
+++ b/packages/SettingsLib/res/values-km/strings.xml
@@ -449,8 +449,7 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"<xliff:g id="TIME">%1$s</xliff:g> ទៀតទើបសាកថ្មពេញ"</string>
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> ទៀតទើប​សាកថ្មពេញ"</string>
- <!-- no translation found for power_charging_limited (5902301801611726210) -->
- <skip />
+ <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> - បានដាក់កម្រិតថ្ម​ជាបណ្ដោះអាសន្ន"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"មិន​ស្គាល់"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"កំពុងបញ្ចូល​ថ្ម"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"កំពុងសាកថ្មយ៉ាងឆាប់រហ័ស"</string>
diff --git a/packages/SettingsLib/res/values-kn/strings.xml b/packages/SettingsLib/res/values-kn/strings.xml
index 658b987dd833..0c1502ca620d 100644
--- a/packages/SettingsLib/res/values-kn/strings.xml
+++ b/packages/SettingsLib/res/values-kn/strings.xml
@@ -449,8 +449,7 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"ಚಾರ್ಜ್ ಆಗಲು <xliff:g id="TIME">%1$s</xliff:g> ಸಮಯ ಬಾಕಿ ಇದೆ"</string>
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - ಚಾರ್ಜ್ ಆಗಲು <xliff:g id="TIME">%2$s</xliff:g> ಸಮಯ ಬೇಕು"</string>
- <!-- no translation found for power_charging_limited (5902301801611726210) -->
- <skip />
+ <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> - ಬ್ಯಾಟರಿ ತಾತ್ಕಾಲಿಕವಾಗಿ ಸೀಮಿತವಾಗಿದೆ"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"ಅಪರಿಚಿತ"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"ಚಾರ್ಜ್ ಆಗುತ್ತಿದೆ"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"ವೇಗದ ಚಾರ್ಜಿಂಗ್"</string>
diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml
index 2b0843dcef39..13223440d098 100644
--- a/packages/SettingsLib/res/values-ko/strings.xml
+++ b/packages/SettingsLib/res/values-ko/strings.xml
@@ -449,8 +449,7 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"충전 완료까지 <xliff:g id="TIME">%1$s</xliff:g> 남음"</string>
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - 충전 완료까지 <xliff:g id="TIME">%2$s</xliff:g> 남음"</string>
- <!-- no translation found for power_charging_limited (5902301801611726210) -->
- <skip />
+ <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> - 일시적으로 배터리 사용 제한"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"알 수 없음"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"충전 중"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"고속 충전 중"</string>
diff --git a/packages/SettingsLib/res/values-ky/strings.xml b/packages/SettingsLib/res/values-ky/strings.xml
index 499fd88f5a4f..9697aa70e44f 100644
--- a/packages/SettingsLib/res/values-ky/strings.xml
+++ b/packages/SettingsLib/res/values-ky/strings.xml
@@ -449,8 +449,7 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"<xliff:g id="TIME">%1$s</xliff:g> кийин толук кубатталып бүтөт"</string>
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> кийин толук кубатталып бүтөт"</string>
- <!-- no translation found for power_charging_limited (5902301801611726210) -->
- <skip />
+ <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> - Батареяны колдонуу убактлуу чектелген"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Белгисиз"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Кубатталууда"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Ыкчам кубатталууда"</string>
diff --git a/packages/SettingsLib/res/values-lo/strings.xml b/packages/SettingsLib/res/values-lo/strings.xml
index a5be6017ca62..720122262dcf 100644
--- a/packages/SettingsLib/res/values-lo/strings.xml
+++ b/packages/SettingsLib/res/values-lo/strings.xml
@@ -399,9 +399,9 @@
<string name="inactive_app_inactive_summary" msgid="3161222402614236260">"ບໍ່ໄດ້ນຳໃຊ້. ແຕະບໍ່ສັບປ່ຽນ."</string>
<string name="inactive_app_active_summary" msgid="8047630990208722344">"ນຳໃຊ້ຢູ່. ແຕະເພື່ອສັບປ່ຽນ."</string>
<string name="standby_bucket_summary" msgid="5128193447550429600">"ສະຖານະສະແຕນບາຍແອັບ:<xliff:g id="BUCKET"> %s</xliff:g>"</string>
- <string name="transcode_settings_title" msgid="2581975870429850549">"ການຕັ້ງຄ່າການ​ປ່ຽນ​ຮູບ​ແບບ​ລະ​ຫັດມີເດຍ"</string>
- <string name="transcode_enable_all" msgid="9102460144086871903">"ປິດການນຳໃຊ້ການ​ປ່ຽນ​ຮູບ​ແບບ​ລະ​ຫັດ"</string>
- <string name="transcode_skip_apps" msgid="8249721984597390142">"ເປີດການນຳໃຊ້ການ​ປ່ຽນ​ຮູບ​ແບບ​ລະ​ຫັດສຳລັບແອັບ"</string>
+ <string name="transcode_settings_title" msgid="2581975870429850549">"ການຕັ້ງຄ່າການປ່ຽນຮູບແບບລະຫັດມີເດຍ"</string>
+ <string name="transcode_enable_all" msgid="9102460144086871903">"ປິດການນຳໃຊ້ການປ່ຽນຮູບແບບລະຫັດ"</string>
+ <string name="transcode_skip_apps" msgid="8249721984597390142">"ເປີດການນຳໃຊ້ການປ່ຽນຮູບແບບລະຫັດສຳລັບແອັບ"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"ບໍລິການທີ່ເຮັດວຽກຢູ່"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"ເບິ່ງ ແລະຈັດການບໍລິການທີ່ກຳລັງເຮັດວຽກຢູ່ໃນປັດຈຸບັນ"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"ການຈັດຕັ້ງປະຕິບັດ WebView"</string>
@@ -449,8 +449,7 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"<xliff:g id="TIME">%1$s</xliff:g> ຈົນກວ່າຈະສາກເຕັມ"</string>
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> ຈົນກວ່າຈະສາກເຕັມ"</string>
- <!-- no translation found for power_charging_limited (5902301801611726210) -->
- <skip />
+ <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> - ຈຳກັດແບັດເຕີຣີຊົ່ວຄາວ"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"ບໍ່ຮູ້ຈັກ"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"ກຳລັງສາກໄຟ"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"ກຳລັງສາກໄຟດ່ວນ"</string>
diff --git a/packages/SettingsLib/res/values-lt/strings.xml b/packages/SettingsLib/res/values-lt/strings.xml
index 181fb10dd845..e62eeb2dbd97 100644
--- a/packages/SettingsLib/res/values-lt/strings.xml
+++ b/packages/SettingsLib/res/values-lt/strings.xml
@@ -449,8 +449,7 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"Iki visiškos įkrovos liko <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> – iki visiškos įkrovos liko <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <!-- no translation found for power_charging_limited (5902301801611726210) -->
- <skip />
+ <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> – akumuliatorius laikinai apribotas"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Nežinomas"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Kraunasi..."</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Greitai įkraunama"</string>
diff --git a/packages/SettingsLib/res/values-lv/strings.xml b/packages/SettingsLib/res/values-lv/strings.xml
index 717e2b0c89d8..2f305612a5fc 100644
--- a/packages/SettingsLib/res/values-lv/strings.xml
+++ b/packages/SettingsLib/res/values-lv/strings.xml
@@ -449,8 +449,7 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> — <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"Vēl <xliff:g id="TIME">%1$s</xliff:g> līdz pilnai uzlādei"</string>
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> — <xliff:g id="TIME">%2$s</xliff:g> līdz pilnai uzlādei"</string>
- <!-- no translation found for power_charging_limited (5902301801611726210) -->
- <skip />
+ <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g>, akumulatora uzlāde pagaidām ierobežota"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Nezināms"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Uzlāde"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Notiek ātrā uzlāde"</string>
diff --git a/packages/SettingsLib/res/values-mk/strings.xml b/packages/SettingsLib/res/values-mk/strings.xml
index 2ccb150b8ca3..1936fe2d32a4 100644
--- a/packages/SettingsLib/res/values-mk/strings.xml
+++ b/packages/SettingsLib/res/values-mk/strings.xml
@@ -449,8 +449,7 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"Уште <xliff:g id="TIME">%1$s</xliff:g> до целосно полнење"</string>
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> до целосно полнење"</string>
- <!-- no translation found for power_charging_limited (5902301801611726210) -->
- <skip />
+ <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> - Батеријата е привремено ограничена"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Непознато"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Се полни"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Брзо полнење"</string>
diff --git a/packages/SettingsLib/res/values-ml/strings.xml b/packages/SettingsLib/res/values-ml/strings.xml
index 768ad5e70698..de4a49a2ed06 100644
--- a/packages/SettingsLib/res/values-ml/strings.xml
+++ b/packages/SettingsLib/res/values-ml/strings.xml
@@ -399,12 +399,9 @@
<string name="inactive_app_inactive_summary" msgid="3161222402614236260">"നിഷ്‌ക്രിയം. മാറ്റുന്നതിനു ടാപ്പുചെയ്യുക."</string>
<string name="inactive_app_active_summary" msgid="8047630990208722344">"സജീവം. മാറ്റുന്നതിന് ടാപ്പുചെയ്യുക."</string>
<string name="standby_bucket_summary" msgid="5128193447550429600">"ആപ്പ് സ്‌റ്റാൻഡ്‌ബൈ നില:<xliff:g id="BUCKET"> %s</xliff:g>"</string>
- <!-- no translation found for transcode_settings_title (2581975870429850549) -->
- <skip />
- <!-- no translation found for transcode_enable_all (9102460144086871903) -->
- <skip />
- <!-- no translation found for transcode_skip_apps (8249721984597390142) -->
- <skip />
+ <string name="transcode_settings_title" msgid="2581975870429850549">"മീഡിയ ട്രാൻസ്കോഡ് ചെയ്യൽ ക്രമീകരണം"</string>
+ <string name="transcode_enable_all" msgid="9102460144086871903">"ട്രാൻസ്കോഡ് ചെയ്യൽ പ്രവർത്തനരഹിതമാക്കുക"</string>
+ <string name="transcode_skip_apps" msgid="8249721984597390142">"ആപ്പുകൾക്കായി ട്രാൻസ്കോഡ് ചെയ്യുന്നത് പ്രവർത്തനക്ഷമമാക്കുക"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"പ്രവർത്തിക്കുന്ന സേവനങ്ങൾ"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"നിലവിൽ പ്രവർത്തിക്കുന്ന സേവനങ്ങൾ കാണുക, നിയന്ത്രിക്കുക"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView നടപ്പാക്കൽ"</string>
@@ -452,8 +449,7 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"പൂർണ്ണമായി ചാർജാവാൻ <xliff:g id="TIME">%1$s</xliff:g> ശേഷിക്കുന്നു"</string>
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - പൂർണ്ണമായി ചാർജാവാൻ <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <!-- no translation found for power_charging_limited (5902301801611726210) -->
- <skip />
+ <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> - ബാറ്ററി താൽക്കാലം പരിമിതപ്പെടുത്തി"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"അജ്ഞാതം"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"ചാർജ് ചെയ്യുന്നു"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"അതിവേഗ ചാർജിംഗ്"</string>
diff --git a/packages/SettingsLib/res/values-mn/strings.xml b/packages/SettingsLib/res/values-mn/strings.xml
index 61ebca5992b8..dee8add685f9 100644
--- a/packages/SettingsLib/res/values-mn/strings.xml
+++ b/packages/SettingsLib/res/values-mn/strings.xml
@@ -449,8 +449,7 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"Цэнэглэх хүртэл үлдсэн <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - цэнэглэх хүртэл <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <!-- no translation found for power_charging_limited (5902301801611726210) -->
- <skip />
+ <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> - Батарейг түр хугацаанд хязгаарласан"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Тодорхойгүй"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Цэнэглэж байна"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Хурдан цэнэглэж байна"</string>
diff --git a/packages/SettingsLib/res/values-mr/strings.xml b/packages/SettingsLib/res/values-mr/strings.xml
index ef319c3a4fc1..60ad68e42c09 100644
--- a/packages/SettingsLib/res/values-mr/strings.xml
+++ b/packages/SettingsLib/res/values-mr/strings.xml
@@ -399,12 +399,9 @@
<string name="inactive_app_inactive_summary" msgid="3161222402614236260">"निष्क्रिय. टॉगल करण्यासाठी टॅप करा."</string>
<string name="inactive_app_active_summary" msgid="8047630990208722344">"सक्रिय. टॉगल करण्यासाठी टॅप करा."</string>
<string name="standby_bucket_summary" msgid="5128193447550429600">"अ‍ॅप स्टँडबाय स्थिती: <xliff:g id="BUCKET"> %s</xliff:g>"</string>
- <!-- no translation found for transcode_settings_title (2581975870429850549) -->
- <skip />
- <!-- no translation found for transcode_enable_all (9102460144086871903) -->
- <skip />
- <!-- no translation found for transcode_skip_apps (8249721984597390142) -->
- <skip />
+ <string name="transcode_settings_title" msgid="2581975870429850549">"मीडिया ट्रान्सकोडिंगची सेटिंग्ज"</string>
+ <string name="transcode_enable_all" msgid="9102460144086871903">"ट्रान्सकोडिंग बंद करा"</string>
+ <string name="transcode_skip_apps" msgid="8249721984597390142">"ॲप्ससाठी ट्रान्सकोडिंग सुरू करा"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"सुरू सेवा"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"सध्या सुरू असलेल्या सेवा पहा आणि नियंत्रित करा"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"वेबदृश्य अंमलबजावणी"</string>
@@ -452,8 +449,7 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"<xliff:g id="TIME">%1$s</xliff:g> पर्यंत पूर्ण चार्ज होईल"</string>
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> पर्यंत पूर्ण चार्ज होईल"</string>
- <!-- no translation found for power_charging_limited (5902301801611726210) -->
- <skip />
+ <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> - बॅटरी तात्पुरती मर्यादित आहे"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"अज्ञात"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"चार्ज होत आहे"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"वेगाने चार्ज होत आहे"</string>
diff --git a/packages/SettingsLib/res/values-ms/strings.xml b/packages/SettingsLib/res/values-ms/strings.xml
index 83c038453265..e4d591207937 100644
--- a/packages/SettingsLib/res/values-ms/strings.xml
+++ b/packages/SettingsLib/res/values-ms/strings.xml
@@ -449,8 +449,7 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"<xliff:g id="TIME">%1$s</xliff:g> lagi sehingga dicas penuh"</string>
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> sehingga dicas"</string>
- <!-- no translation found for power_charging_limited (5902301801611726210) -->
- <skip />
+ <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> - Bateri terhad untuk sementara"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Tidak diketahui"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Mengecas"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Mengecas dgn cepat"</string>
diff --git a/packages/SettingsLib/res/values-my/strings.xml b/packages/SettingsLib/res/values-my/strings.xml
index f398487856bf..09a8bf87700b 100644
--- a/packages/SettingsLib/res/values-my/strings.xml
+++ b/packages/SettingsLib/res/values-my/strings.xml
@@ -449,8 +449,7 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"အားပြည့်ရန် <xliff:g id="TIME">%1$s</xliff:g> ကျန်သည်"</string>
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - အားပြည့်ရန် <xliff:g id="TIME">%2$s</xliff:g> ကျန်သည်"</string>
- <!-- no translation found for power_charging_limited (5902301801611726210) -->
- <skip />
+ <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> - ဘက်ထရီ ယာယီကန့်သတ်ထားသည်"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"မသိ"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"အားသွင်းနေပါသည်"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"အမြန် အားသွင်းနေသည်"</string>
diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml
index 0ef5809e2a6d..d1af28940f1b 100644
--- a/packages/SettingsLib/res/values-nb/strings.xml
+++ b/packages/SettingsLib/res/values-nb/strings.xml
@@ -449,8 +449,7 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"<xliff:g id="TIME">%1$s</xliff:g> til batteriet er fulladet"</string>
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> til batteriet er fulladet"</string>
- <!-- no translation found for power_charging_limited (5902301801611726210) -->
- <skip />
+ <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> – Batteriet er midlertidig begrenset"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Ukjent"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Lader"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Lader raskt"</string>
diff --git a/packages/SettingsLib/res/values-ne/strings.xml b/packages/SettingsLib/res/values-ne/strings.xml
index b956e2104c82..0c6114b9e220 100644
--- a/packages/SettingsLib/res/values-ne/strings.xml
+++ b/packages/SettingsLib/res/values-ne/strings.xml
@@ -399,12 +399,9 @@
<string name="inactive_app_inactive_summary" msgid="3161222402614236260">"निष्क्रिय। टगल गर्न ट्याप गर्नुहोस्।"</string>
<string name="inactive_app_active_summary" msgid="8047630990208722344">"सक्रिय। टगल गर्न ट्याप गर्नुहोस्।"</string>
<string name="standby_bucket_summary" msgid="5128193447550429600">"एपको स्ट्यान्डबाई अवस्था:<xliff:g id="BUCKET"> %s</xliff:g>"</string>
- <!-- no translation found for transcode_settings_title (2581975870429850549) -->
- <skip />
- <!-- no translation found for transcode_enable_all (9102460144086871903) -->
- <skip />
- <!-- no translation found for transcode_skip_apps (8249721984597390142) -->
- <skip />
+ <string name="transcode_settings_title" msgid="2581975870429850549">"मिडिया ट्रान्सकोडिङ सेटिङ"</string>
+ <string name="transcode_enable_all" msgid="9102460144086871903">"ट्रान्सकोडिङ अफ गर्नुहोस्"</string>
+ <string name="transcode_skip_apps" msgid="8249721984597390142">"एपहरूमा ट्रान्सकोडिङ अन गर्नुहोस्"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"चलिरहेका सेवाहरू"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"हाल चालु भइरहेका सेवाहरू हेर्नुहोस् र नियन्त्रण गर्नुहोस्"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView कार्यान्वयन"</string>
@@ -452,8 +449,7 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"पूर्ण चार्ज हुन <xliff:g id="TIME">%1$s</xliff:g> बाँकी"</string>
<string name="power_charging_duration" msgid="5005740040558984057">"पूर्ण चार्ज हुन <xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> लाग्छ"</string>
- <!-- no translation found for power_charging_limited (5902301801611726210) -->
- <skip />
+ <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> - केही समयका लागि ब्याट्री प्रयोग सीमित गरिएको छ"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"अज्ञात"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"चार्ज हुँदै"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"द्रुत गतिमा चार्ज गरिँदै"</string>
diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml
index 3223857a0949..a409756e5b5f 100644
--- a/packages/SettingsLib/res/values-nl/strings.xml
+++ b/packages/SettingsLib/res/values-nl/strings.xml
@@ -449,8 +449,7 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"Nog <xliff:g id="TIME">%1$s</xliff:g> tot opgeladen"</string>
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> tot opgeladen"</string>
- <!-- no translation found for power_charging_limited (5902301801611726210) -->
- <skip />
+ <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> - Batterij tijdelijk beperkt"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Onbekend"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Opladen"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Snel opladen"</string>
diff --git a/packages/SettingsLib/res/values-or/strings.xml b/packages/SettingsLib/res/values-or/strings.xml
index 11bb550caa49..0a0eeff6de60 100644
--- a/packages/SettingsLib/res/values-or/strings.xml
+++ b/packages/SettingsLib/res/values-or/strings.xml
@@ -399,12 +399,9 @@
<string name="inactive_app_inactive_summary" msgid="3161222402614236260">"ନିଷ୍କ୍ରିୟ। ଟୋଗଲ୍‌ କରିବାକୁ ଟାପ୍‌ କରନ୍ତୁ।"</string>
<string name="inactive_app_active_summary" msgid="8047630990208722344">"ସକ୍ରିୟ। ବଦଳାଇବା ପାଇଁ ଟାପ୍‌ କରନ୍ତୁ"</string>
<string name="standby_bucket_summary" msgid="5128193447550429600">"ଆପ୍ ଷ୍ଟାଣ୍ଡବାଏ ଅବସ୍ଥା:<xliff:g id="BUCKET"> %s</xliff:g>"</string>
- <!-- no translation found for transcode_settings_title (2581975870429850549) -->
- <skip />
- <!-- no translation found for transcode_enable_all (9102460144086871903) -->
- <skip />
- <!-- no translation found for transcode_skip_apps (8249721984597390142) -->
- <skip />
+ <string name="transcode_settings_title" msgid="2581975870429850549">"ମିଡିଆ ଟ୍ରାନ୍ସକୋଡିଂ ସେଟିଂସ୍"</string>
+ <string name="transcode_enable_all" msgid="9102460144086871903">"ଟ୍ରାନ୍ସକୋଡିଂ ଅକ୍ଷମ କରନ୍ତୁ"</string>
+ <string name="transcode_skip_apps" msgid="8249721984597390142">"ଆପଗୁଡ଼ିକ ପାଇଁ ଟ୍ରାନ୍ସକୋଡିଂ ସକ୍ଷମ କରନ୍ତୁ"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"ଚାଲୁଥିବା ସେବାଗୁଡ଼ିକ"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"ଏବେ ଚାଲୁଥିବା ସେବାଗୁଡ଼ିକୁ ଦେଖନ୍ତୁ ଓ ନିୟନ୍ତ୍ରଣ କରନ୍ତୁ"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"ୱେବ୍‌ଭ୍ୟୁ ପ୍ରୟୋଗ"</string>
@@ -452,8 +449,7 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"ଚାର୍ଜ ହେବା ପାଇଁ <xliff:g id="TIME">%1$s</xliff:g> ବାକି ଅଛି"</string>
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> ଚାର୍ଜ ହେବା ପର୍ଯ୍ୟନ୍ତ"</string>
- <!-- no translation found for power_charging_limited (5902301801611726210) -->
- <skip />
+ <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> - ବ୍ୟାଟେରୀ ଅସ୍ଥାୟୀ ଭାବେ ସୀମିତ ଅଛି"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"ଅଜ୍ଞାତ"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"ଚାର୍ଜ ହେଉଛି"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"ଶୀଘ୍ର ଚାର୍ଜ ହେଉଛି"</string>
diff --git a/packages/SettingsLib/res/values-pa/strings.xml b/packages/SettingsLib/res/values-pa/strings.xml
index 8d66f3ca4adc..c9c37d922537 100644
--- a/packages/SettingsLib/res/values-pa/strings.xml
+++ b/packages/SettingsLib/res/values-pa/strings.xml
@@ -399,12 +399,9 @@
<string name="inactive_app_inactive_summary" msgid="3161222402614236260">"ਅਕਿਰਿਆਸ਼ੀਲ। ਟੌਗਲ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ।"</string>
<string name="inactive_app_active_summary" msgid="8047630990208722344">"ਕਿਰਿਆਸ਼ੀਲ। ਟੌਗਲ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ।"</string>
<string name="standby_bucket_summary" msgid="5128193447550429600">"ਐਪ ਸਟੈਂਡਬਾਈ ਸਥਿਤੀ:<xliff:g id="BUCKET"> %s</xliff:g>"</string>
- <!-- no translation found for transcode_settings_title (2581975870429850549) -->
- <skip />
- <!-- no translation found for transcode_enable_all (9102460144086871903) -->
- <skip />
- <!-- no translation found for transcode_skip_apps (8249721984597390142) -->
- <skip />
+ <string name="transcode_settings_title" msgid="2581975870429850549">"ਮੀਡੀਆ ਟ੍ਰਾਂਸਕੋਡਿੰਗ ਸੈਟਿੰਗਾਂ"</string>
+ <string name="transcode_enable_all" msgid="9102460144086871903">"ਟ੍ਰਾਂਸਕੋਡਿੰਗ ਬੰਦ ਕਰੋ"</string>
+ <string name="transcode_skip_apps" msgid="8249721984597390142">"ਐਪਾਂ ਲਈ ਟ੍ਰਾਂਸਕੋਡਿੰਗ ਚਾਲੂ ਕਰੋ"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"ਚੱਲ ਰਹੀਆਂ ਸੇਵਾਵਾਂ"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"ਇਸ ਵੇਲੇ ਚੱਲ ਰਹੀਆਂ ਸੇਵਾਵਾਂ ਦੇਖੋ ਅਤੇ ਇਹਨਾਂ ਨੂੰ ਕੰਟਰੋਲ ਕਰੋ"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView ਅਮਲ"</string>
@@ -452,8 +449,7 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"ਚਾਰਜ ਹੋਣ ਵਿੱਚ <xliff:g id="TIME">%1$s</xliff:g> ਬਾਕੀ"</string>
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> ਤੱਕ ਚਾਰਜ ਹੋ ਜਾਵੇਗੀ"</string>
- <!-- no translation found for power_charging_limited (5902301801611726210) -->
- <skip />
+ <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> - ਬੈਟਰੀ ਕੁਝ ਸਮੇਂ ਲਈ ਸੀਮਤ"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"ਅਗਿਆਤ"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"ਚਾਰਜ ਹੋ ਰਿਹਾ ਹੈ"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"ਤੇਜ਼ ਚਾਰਜ ਹੋ ਰਹੀ ਹੈ"</string>
diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml
index ed96c46848d9..e894c2cbc34c 100644
--- a/packages/SettingsLib/res/values-pl/strings.xml
+++ b/packages/SettingsLib/res/values-pl/strings.xml
@@ -449,8 +449,7 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"Do naładowania <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> – do naładowania <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <!-- no translation found for power_charging_limited (5902301801611726210) -->
- <skip />
+ <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> – bateria tymczasowo ograniczona"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Nieznane"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Ładowanie"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Szybkie ładowanie"</string>
diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml
index 46d6d0a89f5e..57a0454f3465 100644
--- a/packages/SettingsLib/res/values-ro/strings.xml
+++ b/packages/SettingsLib/res/values-ro/strings.xml
@@ -449,8 +449,7 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"Au mai rămas <xliff:g id="TIME">%1$s</xliff:g> până la încărcare"</string>
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> până la încărcare"</string>
- <!-- no translation found for power_charging_limited (5902301801611726210) -->
- <skip />
+ <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> – baterie limitată temporar"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Necunoscut"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Se încarcă"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Se încarcă rapid"</string>
diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml
index 2a79ad3005ff..09b8de04388b 100644
--- a/packages/SettingsLib/res/values-ru/strings.xml
+++ b/packages/SettingsLib/res/values-ru/strings.xml
@@ -449,8 +449,7 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"<xliff:g id="TIME">%1$s</xliff:g> до полной зарядки"</string>
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> до полной зарядки"</string>
- <!-- no translation found for power_charging_limited (5902301801611726210) -->
- <skip />
+ <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> • Уровень заряда временно ограничен"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Неизвестно"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Идет зарядка"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Быстрая зарядка"</string>
diff --git a/packages/SettingsLib/res/values-si/strings.xml b/packages/SettingsLib/res/values-si/strings.xml
index 78f355865ced..d36140f66b54 100644
--- a/packages/SettingsLib/res/values-si/strings.xml
+++ b/packages/SettingsLib/res/values-si/strings.xml
@@ -449,8 +449,7 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"ආරෝපණය වන තෙක් <xliff:g id="TIME">%1$s</xliff:g> ඇත"</string>
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - ආරෝපණය වන තෙක් <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <!-- no translation found for power_charging_limited (5902301801611726210) -->
- <skip />
+ <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> - බැටරිය තාවකාලිකව සීමිතයි"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"නොදනී"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"ආරෝපණය වෙමින්"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"ශීඝ්‍ර ආරෝපණය"</string>
diff --git a/packages/SettingsLib/res/values-sk/strings.xml b/packages/SettingsLib/res/values-sk/strings.xml
index 152c7a885457..096e95e7050b 100644
--- a/packages/SettingsLib/res/values-sk/strings.xml
+++ b/packages/SettingsLib/res/values-sk/strings.xml
@@ -449,8 +449,7 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"Zostávajúci čas do úplného nabitia: <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> do úplného nabitia"</string>
- <!-- no translation found for power_charging_limited (5902301801611726210) -->
- <skip />
+ <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> – Batéria je dočasne obmedzená"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Neznáme"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Nabíja sa"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Rýchle nabíjanie"</string>
diff --git a/packages/SettingsLib/res/values-sl/strings.xml b/packages/SettingsLib/res/values-sl/strings.xml
index a2f093e89ad8..345fa36d3bd6 100644
--- a/packages/SettingsLib/res/values-sl/strings.xml
+++ b/packages/SettingsLib/res/values-sl/strings.xml
@@ -449,8 +449,7 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"Še <xliff:g id="TIME">%1$s</xliff:g> do polne napolnjenosti"</string>
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> do polne napolnjenosti"</string>
- <!-- no translation found for power_charging_limited (5902301801611726210) -->
- <skip />
+ <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> – baterija je začasno omejena"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Neznano"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Polnjenje"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Hitro polnjenje"</string>
diff --git a/packages/SettingsLib/res/values-sq/strings.xml b/packages/SettingsLib/res/values-sq/strings.xml
index b4589173f234..3953a6a4f6e0 100644
--- a/packages/SettingsLib/res/values-sq/strings.xml
+++ b/packages/SettingsLib/res/values-sq/strings.xml
@@ -449,8 +449,7 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"<xliff:g id="TIME">%1$s</xliff:g> të mbetura deri në karikim"</string>
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> derisa të karikohet"</string>
- <!-- no translation found for power_charging_limited (5902301801611726210) -->
- <skip />
+ <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> - Bateria e kufizuar përkohësisht"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"I panjohur"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Po karikohet"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Po ngarkon me shpejtësi"</string>
diff --git a/packages/SettingsLib/res/values-sr/strings.xml b/packages/SettingsLib/res/values-sr/strings.xml
index 970c70f48c68..70b287933c93 100644
--- a/packages/SettingsLib/res/values-sr/strings.xml
+++ b/packages/SettingsLib/res/values-sr/strings.xml
@@ -449,8 +449,7 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"Напуниће се за <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> – напуниће се за <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <!-- no translation found for power_charging_limited (5902301801611726210) -->
- <skip />
+ <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> – батерија је тренутно ограничена"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Непознато"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Пуни се"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Брзо се пуни"</string>
diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml
index 42d907734e30..f466e882c2fc 100644
--- a/packages/SettingsLib/res/values-sv/strings.xml
+++ b/packages/SettingsLib/res/values-sv/strings.xml
@@ -449,8 +449,7 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"<xliff:g id="TIME">%1$s</xliff:g> kvar till full laddning"</string>
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> till full laddning"</string>
- <!-- no translation found for power_charging_limited (5902301801611726210) -->
- <skip />
+ <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> – batteriet är tillfälligt begränsat"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Okänd"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Laddar"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Laddas snabbt"</string>
diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml
index f1a41994d2c8..e1060fec2a66 100644
--- a/packages/SettingsLib/res/values-sw/strings.xml
+++ b/packages/SettingsLib/res/values-sw/strings.xml
@@ -449,8 +449,7 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"Imebakisha <xliff:g id="TIME">%1$s</xliff:g> ijae chaji"</string>
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> ijae chaji"</string>
- <!-- no translation found for power_charging_limited (5902301801611726210) -->
- <skip />
+ <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> - Betri imedhibitiwa kwa muda"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Haijulikani"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Inachaji"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Inachaji kwa kasi"</string>
diff --git a/packages/SettingsLib/res/values-ta/strings.xml b/packages/SettingsLib/res/values-ta/strings.xml
index 2d696c5f79eb..ba98d79ff7e4 100644
--- a/packages/SettingsLib/res/values-ta/strings.xml
+++ b/packages/SettingsLib/res/values-ta/strings.xml
@@ -449,8 +449,7 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"முழு சார்ஜாக <xliff:g id="TIME">%1$s</xliff:g> ஆகும்"</string>
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - முழு சார்ஜாக <xliff:g id="TIME">%2$s</xliff:g> ஆகும்"</string>
- <!-- no translation found for power_charging_limited (5902301801611726210) -->
- <skip />
+ <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g>-பேட்டரி தற்காலிகக் கட்டுப்பாட்டிலுள்ளது"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"அறியப்படாத"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"சார்ஜ் ஆகிறது"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"வேகமாக சார்ஜாகிறது"</string>
diff --git a/packages/SettingsLib/res/values-te/strings.xml b/packages/SettingsLib/res/values-te/strings.xml
index 8e0f0b603523..0b93979dbd07 100644
--- a/packages/SettingsLib/res/values-te/strings.xml
+++ b/packages/SettingsLib/res/values-te/strings.xml
@@ -449,8 +449,7 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"ఛార్జ్ అవ్వడానికి <xliff:g id="TIME">%1$s</xliff:g> సమయం మిగిలి ఉంది"</string>
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - ఛార్జ్ అవ్వడానికి <xliff:g id="TIME">%2$s</xliff:g> పడుతుంది"</string>
- <!-- no translation found for power_charging_limited (5902301801611726210) -->
- <skip />
+ <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> -బ్యాటరీ తాత్కాలికంగా పరిమితం చేయబడింది"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"తెలియదు"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"ఛార్జ్ అవుతోంది"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"వేగవంతమైన ఛార్జింగ్"</string>
diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml
index 81895b923a44..a31e14611bf6 100644
--- a/packages/SettingsLib/res/values-th/strings.xml
+++ b/packages/SettingsLib/res/values-th/strings.xml
@@ -449,8 +449,7 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"เหลือ <xliff:g id="TIME">%1$s</xliff:g> จนกว่าจะชาร์จเต็ม"</string>
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> จนกว่าจะชาร์จ"</string>
- <!-- no translation found for power_charging_limited (5902301801611726210) -->
- <skip />
+ <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> - การชาร์จแบตเตอรี่จำกัดชั่วคราว"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"ไม่ทราบ"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"กำลังชาร์จ"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"กำลังชาร์จอย่างเร็ว"</string>
diff --git a/packages/SettingsLib/res/values-tl/strings.xml b/packages/SettingsLib/res/values-tl/strings.xml
index 5d1630f28675..bbb77790e68a 100644
--- a/packages/SettingsLib/res/values-tl/strings.xml
+++ b/packages/SettingsLib/res/values-tl/strings.xml
@@ -449,8 +449,7 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"<xliff:g id="TIME">%1$s</xliff:g> ang natitira bago matapos mag-charge"</string>
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> hanggang matapos mag-charge"</string>
- <!-- no translation found for power_charging_limited (5902301801611726210) -->
- <skip />
+ <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> - Pansamantalang limitado ang baterya"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Hindi Kilala"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Nagcha-charge"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Mabilis na charge"</string>
diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml
index 34c96a815616..fba7f41bbbf5 100644
--- a/packages/SettingsLib/res/values-tr/strings.xml
+++ b/packages/SettingsLib/res/values-tr/strings.xml
@@ -449,8 +449,7 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"Şarj olmaya <xliff:g id="TIME">%1$s</xliff:g> kaldı"</string>
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - şarj olmaya <xliff:g id="TIME">%2$s</xliff:g> kaldı"</string>
- <!-- no translation found for power_charging_limited (5902301801611726210) -->
- <skip />
+ <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> - Pil geçici olarak sınırlı"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Bilinmiyor"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Şarj oluyor"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Hızlı şarj oluyor"</string>
diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml
index de2456cce092..b633752d28a9 100644
--- a/packages/SettingsLib/res/values-uk/strings.xml
+++ b/packages/SettingsLib/res/values-uk/strings.xml
@@ -449,8 +449,7 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"<xliff:g id="TIME">%1$s</xliff:g> до повного заряду"</string>
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> до повного заряду"</string>
- <!-- no translation found for power_charging_limited (5902301801611726210) -->
- <skip />
+ <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> – дані акумулятора тимчасово недоступні"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Невідомо"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Заряджається"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Швидке заряджання"</string>
diff --git a/packages/SettingsLib/res/values-ur/strings.xml b/packages/SettingsLib/res/values-ur/strings.xml
index 7842ba9bcdbf..b4d8ad2576bd 100644
--- a/packages/SettingsLib/res/values-ur/strings.xml
+++ b/packages/SettingsLib/res/values-ur/strings.xml
@@ -399,12 +399,9 @@
<string name="inactive_app_inactive_summary" msgid="3161222402614236260">"غیر فعال۔ ٹوگل کرنے کیلئے تھپتھپائیں۔"</string>
<string name="inactive_app_active_summary" msgid="8047630990208722344">"فعال۔ ٹوگل کرنے کیلئے تھپتھپائیں۔"</string>
<string name="standby_bucket_summary" msgid="5128193447550429600">"ایپ اسٹینڈ بائی کی حالت:<xliff:g id="BUCKET"> %s</xliff:g>"</string>
- <!-- no translation found for transcode_settings_title (2581975870429850549) -->
- <skip />
- <!-- no translation found for transcode_enable_all (9102460144086871903) -->
- <skip />
- <!-- no translation found for transcode_skip_apps (8249721984597390142) -->
- <skip />
+ <string name="transcode_settings_title" msgid="2581975870429850549">"میڈیا ٹرانسکوڈنگ کی ترتیبات"</string>
+ <string name="transcode_enable_all" msgid="9102460144086871903">"ٹرانسکوڈنگ غیر فعال کریں"</string>
+ <string name="transcode_skip_apps" msgid="8249721984597390142">"ایپس کے لئے ٹرانسکوڈنگ فعال کریں"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"چل رہی سروسز"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"فی الحال چل رہی سروسز دیکھیں اور انہیں کنٹرول کریں"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"‏WebView کا نفاذ"</string>
@@ -452,8 +449,7 @@
<string name="power_charging" msgid="6727132649743436802">"‎<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>‎"</string>
<string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"چارج ہونے میں <xliff:g id="TIME">%1$s</xliff:g> باقی"</string>
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> چارج ہونے تک"</string>
- <!-- no translation found for power_charging_limited (5902301801611726210) -->
- <skip />
+ <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> - بیٹری عارضی طور پر محدود ہے"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"نامعلوم"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"چارج ہو رہا ہے"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"تیزی سے چارج ہو رہا ہے"</string>
diff --git a/packages/SettingsLib/res/values-uz/strings.xml b/packages/SettingsLib/res/values-uz/strings.xml
index 9457d9001a88..5bb422ecf96a 100644
--- a/packages/SettingsLib/res/values-uz/strings.xml
+++ b/packages/SettingsLib/res/values-uz/strings.xml
@@ -449,8 +449,7 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"<xliff:g id="TIME">%1$s</xliff:g> ichida toʻladi"</string>
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> ichida toʻladi"</string>
- <!-- no translation found for power_charging_limited (5902301801611726210) -->
- <skip />
+ <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> – Quvvat darajasi vaqtincha cheklangan"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Noma’lum"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Quvvat olmoqda"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Tezkor quvvat olmoqda"</string>
diff --git a/packages/SettingsLib/res/values-vi/strings.xml b/packages/SettingsLib/res/values-vi/strings.xml
index 235987c423d5..0acf9418b718 100644
--- a/packages/SettingsLib/res/values-vi/strings.xml
+++ b/packages/SettingsLib/res/values-vi/strings.xml
@@ -449,8 +449,7 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"Còn <xliff:g id="TIME">%1$s</xliff:g> nữa là sạc đầy"</string>
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> nữa là sạc đầy"</string>
- <!-- no translation found for power_charging_limited (5902301801611726210) -->
- <skip />
+ <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> – Thời lượng pin bị hạn chế tạm thời"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Không xác định"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Đang sạc"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Đang sạc nhanh"</string>
diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml
index 46188e9859e6..ca2ad87fb864 100644
--- a/packages/SettingsLib/res/values-zh-rCN/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml
@@ -449,8 +449,7 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"还剩 <xliff:g id="TIME">%1$s</xliff:g>充满电"</string>
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g>后充满电"</string>
- <!-- no translation found for power_charging_limited (5902301801611726210) -->
- <skip />
+ <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> - 暂时限用电池"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"未知"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"正在充电"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"正在快速充电"</string>
diff --git a/packages/SettingsLib/res/values-zh-rHK/strings.xml b/packages/SettingsLib/res/values-zh-rHK/strings.xml
index 6f5c0253e94f..16ca19d313c1 100644
--- a/packages/SettingsLib/res/values-zh-rHK/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rHK/strings.xml
@@ -399,9 +399,9 @@
<string name="inactive_app_inactive_summary" msgid="3161222402614236260">"未啟用。輕按即可切換。"</string>
<string name="inactive_app_active_summary" msgid="8047630990208722344">"已啟用。輕按即可切換。"</string>
<string name="standby_bucket_summary" msgid="5128193447550429600">"備用應用程式狀態:<xliff:g id="BUCKET"> %s</xliff:g>"</string>
- <string name="transcode_settings_title" msgid="2581975870429850549">"媒體轉碼功能設定"</string>
+ <string name="transcode_settings_title" msgid="2581975870429850549">"媒體轉碼設定"</string>
<string name="transcode_enable_all" msgid="9102460144086871903">"停用轉碼功能"</string>
- <string name="transcode_skip_apps" msgid="8249721984597390142">"替應用程式啟用轉碼功能"</string>
+ <string name="transcode_skip_apps" msgid="8249721984597390142">"為應用程式啟用轉碼功能"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"執行中的服務"</string>
<string name="runningservices_settings_summary" msgid="1046080643262665743">"查看並控制目前正在執行中的服務"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"WebView 設置"</string>
@@ -449,8 +449,7 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"還需 <xliff:g id="TIME">%1$s</xliff:g>才能充滿電"</string>
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - 還需 <xliff:g id="TIME">%2$s</xliff:g>才能充滿電"</string>
- <!-- no translation found for power_charging_limited (5902301801611726210) -->
- <skip />
+ <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> - 暫時限制電池充電"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"未知"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"充電中"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"正在快速充電"</string>
diff --git a/packages/SettingsLib/res/values-zh-rTW/strings.xml b/packages/SettingsLib/res/values-zh-rTW/strings.xml
index f966df68e0c3..810119b97777 100644
--- a/packages/SettingsLib/res/values-zh-rTW/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rTW/strings.xml
@@ -449,8 +449,7 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"<xliff:g id="TIME">%1$s</xliff:g>後充飽電"</string>
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g>後充飽電"</string>
- <!-- no translation found for power_charging_limited (5902301801611726210) -->
- <skip />
+ <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> - 暫時限制電池用量"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"不明"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"充電中"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"快速充電中"</string>
diff --git a/packages/SettingsLib/res/values-zu/strings.xml b/packages/SettingsLib/res/values-zu/strings.xml
index 8ad37d330bc4..23beeb1aee82 100644
--- a/packages/SettingsLib/res/values-zu/strings.xml
+++ b/packages/SettingsLib/res/values-zu/strings.xml
@@ -449,8 +449,7 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"<xliff:g id="TIME">%1$s</xliff:g> esele ize ishaje"</string>
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> ize igcwale"</string>
- <!-- no translation found for power_charging_limited (5902301801611726210) -->
- <skip />
+ <string name="power_charging_limited" msgid="5902301801611726210">"<xliff:g id="LEVEL">%1$s</xliff:g> - Ibhethri ikhawulelwe okwesikhashana"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Akwaziwa"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Iyashaja"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Ishaja ngokushesha"</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtilsInternal.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtilsInternal.java
index 9f16d033aea5..ac20ee14ced2 100644
--- a/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtilsInternal.java
+++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtilsInternal.java
@@ -408,7 +408,8 @@ public class RestrictedLockUtilsInternal extends RestrictedLockUtils {
}
/**
- * Checks if an admin has enforced minimum password quality requirements on the given user.
+ * Checks if an admin has enforced minimum password quality or complexity requirements on the
+ * given user.
*
* @return EnforcedAdmin Object containing the enforced admin component and admin user details,
* or {@code null} if no quality requirements are set. If the requirements are set by
@@ -428,6 +429,30 @@ public class RestrictedLockUtilsInternal extends RestrictedLockUtils {
}
LockPatternUtils lockPatternUtils = new LockPatternUtils(context);
+ final int aggregatedComplexity = dpm.getAggregatedPasswordComplexityForUser(userId);
+ if (aggregatedComplexity > DevicePolicyManager.PASSWORD_COMPLEXITY_NONE) {
+ // First, check if there's a Device Owner. If so, then only it can apply password
+ // complexity requiremnts (there can be no secondary profiles).
+ final UserHandle deviceOwnerUser = dpm.getDeviceOwnerUser();
+ if (deviceOwnerUser != null) {
+ return new EnforcedAdmin(dpm.getDeviceOwnerComponentOnAnyUser(), deviceOwnerUser);
+ }
+
+ // The complexity could be enforced by a Profile Owner - either in the current user
+ // or the current user is the parent user that is affected by the profile owner.
+ for (UserInfo userInfo : UserManager.get(context).getProfiles(userId)) {
+ final ComponentName profileOwnerComponent = dpm.getProfileOwnerAsUser(userInfo.id);
+ if (profileOwnerComponent != null) {
+ return new EnforcedAdmin(profileOwnerComponent, getUserHandleOf(userInfo.id));
+ }
+ }
+
+ // Should not get here: A Device Owner or Profile Owner should be found.
+ throw new IllegalStateException(
+ String.format("Could not find admin enforcing complexity %d for user %d",
+ aggregatedComplexity, userId));
+ }
+
if (sProxy.isSeparateProfileChallengeEnabled(lockPatternUtils, userId)) {
// userId is managed profile and has a separate challenge, only consider
// the admins in that user.
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
index 59d8acb82196..8fd1910041c8 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
@@ -49,6 +49,7 @@ import java.util.concurrent.CopyOnWriteArrayList;
*/
public class BluetoothEventManager {
private static final String TAG = "BluetoothEventManager";
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
private final LocalBluetoothAdapter mLocalAdapter;
private final CachedBluetoothDeviceManager mDeviceManager;
@@ -366,6 +367,9 @@ public class BluetoothEventManager {
* BluetoothDevice.UNBOND_REASON_*
*/
private void showUnbondMessage(Context context, String name, int reason) {
+ if (DEBUG) {
+ Log.d(TAG, "showUnbondMessage() name : " + name + ", reason : " + reason);
+ }
int errorMsg;
switch (reason) {
@@ -382,6 +386,7 @@ public class BluetoothEventManager {
case BluetoothDevice.UNBOND_REASON_AUTH_TIMEOUT:
case BluetoothDevice.UNBOND_REASON_REPEATED_ATTEMPTS:
case BluetoothDevice.UNBOND_REASON_REMOTE_AUTH_CANCELED:
+ case BluetoothDevice.UNBOND_REASON_REMOVED:
errorMsg = R.string.bluetooth_pairing_error_message;
break;
default:
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaDevice.java
index 00f94f5c2e64..9d4669a5a37d 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaDevice.java
@@ -18,6 +18,7 @@ package com.android.settingslib.media;
import android.bluetooth.BluetoothClass;
import android.bluetooth.BluetoothDevice;
import android.content.Context;
+import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.media.MediaRoute2Info;
import android.media.MediaRouter2Manager;
@@ -56,8 +57,9 @@ public class BluetoothMediaDevice extends MediaDevice {
@Override
public Drawable getIcon() {
- final Drawable drawable = getIconWithoutBackground();
- if (!isFastPairDevice()) {
+ final Drawable drawable =
+ BluetoothUtils.getBtDrawableWithDescription(mContext, mCachedDevice).first;
+ if (!(drawable instanceof BitmapDrawable)) {
setColorFilter(drawable);
}
return BluetoothUtils.buildAdvancedDrawable(mContext, drawable);
@@ -65,9 +67,7 @@ public class BluetoothMediaDevice extends MediaDevice {
@Override
public Drawable getIconWithoutBackground() {
- return isFastPairDevice()
- ? BluetoothUtils.getBtDrawableWithDescription(mContext, mCachedDevice).first
- : mContext.getDrawable(R.drawable.ic_headphone);
+ return BluetoothUtils.getBtClassDrawableWithDescription(mContext, mCachedDevice).first;
}
@Override
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothEventManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothEventManagerTest.java
index ba1dc64ce1e6..6a4d650ebf31 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothEventManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothEventManagerTest.java
@@ -35,6 +35,8 @@ import android.content.IntentFilter;
import android.os.UserHandle;
import android.telephony.TelephonyManager;
+import com.android.settingslib.R;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -49,6 +51,8 @@ import java.util.List;
@RunWith(RobolectricTestRunner.class)
public class BluetoothEventManagerTest {
+ private static final String DEVICE_NAME = "test_device_name";
+
@Mock
private LocalBluetoothAdapter mLocalAdapter;
@Mock
@@ -71,6 +75,8 @@ public class BluetoothEventManagerTest {
private BluetoothDevice mDevice2;
@Mock
private LocalBluetoothProfileManager mLocalProfileManager;
+ @Mock
+ private BluetoothUtils.ErrorListener mErrorListener;
private Context mContext;
private Intent mIntent;
@@ -92,6 +98,7 @@ public class BluetoothEventManagerTest {
mCachedDevice1 = new CachedBluetoothDevice(mContext, mLocalProfileManager, mDevice1);
mCachedDevice2 = new CachedBluetoothDevice(mContext, mLocalProfileManager, mDevice2);
+ BluetoothUtils.setErrorListener(mErrorListener);
}
@Test
@@ -344,4 +351,80 @@ public class BluetoothEventManagerTest {
assertThat(mCachedDevice2.isActiveDevice(BluetoothProfile.HEADSET)).isFalse();
assertThat(mCachedDevice2.isActiveDevice(BluetoothProfile.HEARING_AID)).isFalse();
}
+
+ @Test
+ public void showUnbondMessage_reasonRemoved_showCorrectedErrorCode() {
+ mIntent = new Intent(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
+ mIntent.putExtra(BluetoothDevice.EXTRA_DEVICE, mBluetoothDevice);
+ mIntent.putExtra(BluetoothDevice.EXTRA_BOND_STATE, BluetoothDevice.BOND_NONE);
+ mIntent.putExtra(BluetoothDevice.EXTRA_REASON, BluetoothDevice.UNBOND_REASON_REMOVED);
+ when(mCachedDeviceManager.findDevice(mBluetoothDevice)).thenReturn(mCachedDevice1);
+ when(mCachedDevice1.getName()).thenReturn(DEVICE_NAME);
+
+ mContext.sendBroadcast(mIntent);
+
+ verify(mErrorListener).onShowError(any(Context.class), eq(DEVICE_NAME),
+ eq(R.string.bluetooth_pairing_error_message));
+ }
+
+ @Test
+ public void showUnbondMessage_reasonAuthTimeout_showCorrectedErrorCode() {
+ mIntent = new Intent(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
+ mIntent.putExtra(BluetoothDevice.EXTRA_DEVICE, mBluetoothDevice);
+ mIntent.putExtra(BluetoothDevice.EXTRA_BOND_STATE, BluetoothDevice.BOND_NONE);
+ mIntent.putExtra(BluetoothDevice.EXTRA_REASON, BluetoothDevice.UNBOND_REASON_AUTH_TIMEOUT);
+ when(mCachedDeviceManager.findDevice(mBluetoothDevice)).thenReturn(mCachedDevice1);
+ when(mCachedDevice1.getName()).thenReturn(DEVICE_NAME);
+
+ mContext.sendBroadcast(mIntent);
+
+ verify(mErrorListener).onShowError(any(Context.class), eq(DEVICE_NAME),
+ eq(R.string.bluetooth_pairing_error_message));
+ }
+
+ @Test
+ public void showUnbondMessage_reasonRemoteDeviceDown_showCorrectedErrorCode() {
+ mIntent = new Intent(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
+ mIntent.putExtra(BluetoothDevice.EXTRA_DEVICE, mBluetoothDevice);
+ mIntent.putExtra(BluetoothDevice.EXTRA_BOND_STATE, BluetoothDevice.BOND_NONE);
+ mIntent.putExtra(BluetoothDevice.EXTRA_REASON,
+ BluetoothDevice.UNBOND_REASON_REMOTE_DEVICE_DOWN);
+ when(mCachedDeviceManager.findDevice(mBluetoothDevice)).thenReturn(mCachedDevice1);
+ when(mCachedDevice1.getName()).thenReturn(DEVICE_NAME);
+
+ mContext.sendBroadcast(mIntent);
+
+ verify(mErrorListener).onShowError(any(Context.class), eq(DEVICE_NAME),
+ eq(R.string.bluetooth_pairing_device_down_error_message));
+ }
+
+ @Test
+ public void showUnbondMessage_reasonAuthRejected_showCorrectedErrorCode() {
+ mIntent = new Intent(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
+ mIntent.putExtra(BluetoothDevice.EXTRA_DEVICE, mBluetoothDevice);
+ mIntent.putExtra(BluetoothDevice.EXTRA_BOND_STATE, BluetoothDevice.BOND_NONE);
+ mIntent.putExtra(BluetoothDevice.EXTRA_REASON, BluetoothDevice.UNBOND_REASON_AUTH_REJECTED);
+ when(mCachedDeviceManager.findDevice(mBluetoothDevice)).thenReturn(mCachedDevice1);
+ when(mCachedDevice1.getName()).thenReturn(DEVICE_NAME);
+
+ mContext.sendBroadcast(mIntent);
+
+ verify(mErrorListener).onShowError(any(Context.class), eq(DEVICE_NAME),
+ eq(R.string.bluetooth_pairing_rejected_error_message));
+ }
+
+ @Test
+ public void showUnbondMessage_reasonAuthFailed_showCorrectedErrorCode() {
+ mIntent = new Intent(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
+ mIntent.putExtra(BluetoothDevice.EXTRA_DEVICE, mBluetoothDevice);
+ mIntent.putExtra(BluetoothDevice.EXTRA_BOND_STATE, BluetoothDevice.BOND_NONE);
+ mIntent.putExtra(BluetoothDevice.EXTRA_REASON, BluetoothDevice.UNBOND_REASON_AUTH_FAILED);
+ when(mCachedDeviceManager.findDevice(mBluetoothDevice)).thenReturn(mCachedDevice1);
+ when(mCachedDevice1.getName()).thenReturn(DEVICE_NAME);
+
+ mContext.sendBroadcast(mIntent);
+
+ verify(mErrorListener).onShowError(any(Context.class), eq(DEVICE_NAME),
+ eq(R.string.bluetooth_pairing_pin_error_message));
+ }
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/BluetoothMediaDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/BluetoothMediaDeviceTest.java
index 8973d116e438..e887c45083c0 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/BluetoothMediaDeviceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/BluetoothMediaDeviceTest.java
@@ -24,6 +24,7 @@ import static org.mockito.Mockito.when;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothProfile;
import android.content.Context;
+import android.graphics.drawable.BitmapDrawable;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
@@ -96,4 +97,17 @@ public class BluetoothMediaDeviceTest {
assertThat(mBluetoothMediaDevice.isFastPairDevice()).isFalse();
}
+
+ @Test
+ public void getIcon_isNotFastPairDevice_drawableTypeIsNotBitmapDrawable() {
+ final BluetoothDevice bluetoothDevice = mock(BluetoothDevice.class);
+ when(mDevice.getDevice()).thenReturn(bluetoothDevice);
+
+ final String value = "False";
+ final byte[] bytes = value.getBytes();
+ when(bluetoothDevice.getMetadata(BluetoothDevice.METADATA_IS_UNTETHERED_HEADSET))
+ .thenReturn(bytes);
+
+ assertThat(mBluetoothMediaDevice.getIcon() instanceof BitmapDrawable).isFalse();
+ }
}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
index b061df1423ba..40b0fcff3aac 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
@@ -496,11 +496,14 @@ final class SettingsState {
public List<String> setSettingsLocked(String prefix, Map<String, String> keyValues,
String packageName) {
List<String> changedKeys = new ArrayList<>();
+ final Iterator<Map.Entry<String, Setting>> iterator = mSettings.entrySet().iterator();
// Delete old keys with the prefix that are not part of the new set.
- for (int i = 0; i < mSettings.keySet().size(); ++i) {
- String key = mSettings.keyAt(i);
- if (key.startsWith(prefix) && !keyValues.containsKey(key)) {
- Setting oldState = mSettings.remove(key);
+ while (iterator.hasNext()) {
+ Map.Entry<String, Setting> entry = iterator.next();
+ final String key = entry.getKey();
+ final Setting oldState = entry.getValue();
+ if (key != null && key.startsWith(prefix) && !keyValues.containsKey(key)) {
+ iterator.remove();
FrameworkStatsLog.write(FrameworkStatsLog.SETTING_CHANGED, key,
/* value= */ "", /* newValue= */ "", oldState.value, /* tag */ "", false,
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/WifiSoftApConfigChangedNotifier.java b/packages/SettingsProvider/src/com/android/providers/settings/WifiSoftApConfigChangedNotifier.java
index 5e5a9d9b2ec8..c33f02dff561 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/WifiSoftApConfigChangedNotifier.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/WifiSoftApConfigChangedNotifier.java
@@ -82,6 +82,7 @@ public class WifiSoftApConfigChangedNotifier {
private static PendingIntent getPendingActivity(Context context) {
Intent intent = new Intent("com.android.settings.WIFI_TETHER_SETTINGS")
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- return PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
+ return PendingIntent.getActivity(context, 0, intent,
+ PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
}
}
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index af12ddd8895b..75eea8db8085 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -230,7 +230,7 @@ public class SettingsBackupTest {
Settings.Global.DEVELOPMENT_RENDER_SHADOWS_IN_COMPOSITOR,
Settings.Global.DEVELOPMENT_USE_BLAST_ADAPTER_SV,
Settings.Global.DEVELOPMENT_USE_BLAST_ADAPTER_VR,
- Settings.Global.DEVELOPMENT_IGNORE_VENDOR_DISPLAY_SETTINGS,
+ Settings.Global.DEVELOPMENT_WM_DISPLAY_SETTINGS_PATH,
Settings.Global.DEVICE_DEMO_MODE,
Settings.Global.BATTERY_SAVER_ADAPTIVE_CONSTANTS,
Settings.Global.BATTERY_SAVER_CONSTANTS,
@@ -319,7 +319,6 @@ public class SettingsBackupTest {
Settings.Global.LOCATION_BACKGROUND_THROTTLE_PROXIMITY_ALERT_INTERVAL_MS,
Settings.Global.LOCATION_BACKGROUND_THROTTLE_PACKAGE_WHITELIST,
Settings.Global.LOCATION_IGNORE_SETTINGS_PACKAGE_WHITELIST,
- Settings.Global.LOCATION_GLOBAL_KILL_SWITCH,
Settings.Global.LOCATION_SETTINGS_LINK_TO_PERMISSIONS_ENABLED,
Settings.Global.LOCK_SOUND,
Settings.Global.LOOPER_STATS,
@@ -576,8 +575,6 @@ public class SettingsBackupTest {
Settings.Global.CHAINED_BATTERY_ATTRIBUTION_ENABLED,
Settings.Global.HIDDEN_API_BLACKLIST_EXEMPTIONS,
Settings.Global.BACKUP_AGENT_TIMEOUT_PARAMETERS,
- Settings.Global.ISOLATED_STORAGE_LOCAL,
- Settings.Global.ISOLATED_STORAGE_REMOTE,
Settings.Global.APPOP_HISTORY_PARAMETERS,
Settings.Global.APPOP_HISTORY_MODE,
Settings.Global.APPOP_HISTORY_INTERVAL_MULTIPLIER,
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 2a699ea45abe..2e3ea24f62e2 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -70,6 +70,7 @@
<uses-permission android:name="android.permission.SET_PROCESS_LIMIT" />
<uses-permission android:name="android.permission.SET_ALWAYS_FINISH" />
<uses-permission android:name="android.permission.DUMP" />
+ <uses-permission android:name="android.permission.CONTROL_UI_TRACING" />
<uses-permission android:name="android.permission.SIGNAL_PERSISTENT_PROCESSES" />
<uses-permission android:name="android.permission.KILL_BACKGROUND_PROCESSES" />
<!-- Internal permissions granted to the shell. -->
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 7120cc21c821..52b41a43c63e 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -530,6 +530,14 @@
androidprv:alwaysFocusable="true"
android:excludeFromRecents="true" />
+ <!-- started from TvNotificationPanel -->
+ <activity
+ android:name=".statusbar.tv.notifications.TvNotificationPanelActivity"
+ android:excludeFromRecents="true"
+ android:launchMode="singleTask"
+ android:noHistory="true"
+ android:theme="@style/TvSidePanelTheme" />
+
<!-- started from SliceProvider -->
<activity android:name=".SlicePermissionActivity"
android:theme="@style/Theme.SystemUI.Dialog.Alert"
diff --git a/packages/SystemUI/OWNERS b/packages/SystemUI/OWNERS
index 17d2f9c89c30..f884270eaba8 100644
--- a/packages/SystemUI/OWNERS
+++ b/packages/SystemUI/OWNERS
@@ -2,8 +2,11 @@ set noparent
dsandler@android.com
+aaliomer@google.com
adamcohen@google.com
+alexflo@google.com
asc@google.com
+awickham@google.com
beverlyt@google.com
brockman@google.com
cinek@google.com
@@ -11,11 +14,16 @@ cwren@google.com
dupin@google.com
ethibodeau@google.com
evanlaird@google.com
+gwasserman@google.com
hwwang@google.com
hyunyoungs@google.com
jaggies@google.com
+jamesoleary@google.com
+jeffdq@google.com
jjaggi@google.com
+jonmiranda@google.com
joshmcgrath@google.com
+joshtrask@google.com
juliacr@google.com
juliatuttle@google.com
kchyn@google.com
@@ -24,28 +32,38 @@ kprevas@google.com
lynhan@google.com
madym@google.com
mankoff@google.com
+mett@google.com
+mkephart@google.com
+mpietal@google.com
mrcasey@google.com
mrenouf@google.com
nbenbernou@google.com
nesciosquid@google.com
ogunwale@google.com
peanutbutter@google.com
+pinyaoting@google.com
pixel@google.com
roosa@google.com
+santie@google.com
snoeberger@google.com
+sreyasr@google.com
steell@google.com
+sfufa@google.com
stwu@google.com
sunnygoyal@google.com
susikp@google.com
+thiruram@google.com
tracyzhou@google.com
tsuji@google.com
twickham@google.com
+vadimt@google.com
+victortulias@google.com
winsonc@google.com
+xuqiu@google.com
zakcohen@google.com
#Android Auto
hseog@google.com
#Android TV
-rgl@google.com
-
+rgl@google.com \ No newline at end of file
diff --git a/packages/SystemUI/res/color/background_protect_secondary.xml b/packages/SystemUI/res-keyguard/color/notification_background_dimmed_color.xml
index 97744dbe9190..3345e6e42500 100644
--- a/packages/SystemUI/res/color/background_protect_secondary.xml
+++ b/packages/SystemUI/res-keyguard/color/notification_background_dimmed_color.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- ~ Copyright (C) 2017 The Android Open Source Project
+ ~ Copyright (C) 2020 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
@@ -14,7 +14,6 @@
~ See the License for the specific language governing permissions and
~ limitations under the License
-->
-
<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:color="?attr/wallpaperTextColorSecondary" />
+ <item android:alpha="0.7" android:color="?android:attr/colorBackground" />
</selector> \ No newline at end of file
diff --git a/packages/SystemUI/res-keyguard/drawable/circle_white.xml b/packages/SystemUI/res-keyguard/drawable/circle_white.xml
new file mode 100644
index 000000000000..d1b20979c29e
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/drawable/circle_white.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="oval">
+ <solid android:color="#33FFFFFF" />
+</shape> \ No newline at end of file
diff --git a/packages/SystemUI/res-keyguard/drawable/kg_emergency_button_background.xml b/packages/SystemUI/res-keyguard/drawable/kg_emergency_button_background.xml
index cc2089f69287..99c70a54a3cd 100644
--- a/packages/SystemUI/res-keyguard/drawable/kg_emergency_button_background.xml
+++ b/packages/SystemUI/res-keyguard/drawable/kg_emergency_button_background.xml
@@ -19,13 +19,13 @@
<item android:id="@android:id/background">
<shape
android:color="@android:color/transparent">
- <stroke android:width="1dp" android:color="?attr/wallpaperTextColorSecondary"/>
+ <stroke android:width="1dp" android:color="?android:attr/textColorSecondary"/>
<corners android:radius="24dp"/>
</shape>
</item>
<item android:id="@android:id/mask">
<shape android:shape="rectangle">
- <solid android:color="?attr/wallpaperTextColorSecondary"/>
+ <solid android:color="?android:attr/textColorSecondary"/>
<corners android:radius="24dp"/>
</shape>
</item>
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml b/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml
index b75c2c4cea6c..c82bda6620bd 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml
@@ -95,7 +95,7 @@
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:gravity="center_horizontal"
- android:textSize="170dp"
+ android:textSize="180dp"
android:letterSpacing="0.02"
android:lineSpacingMultiplier=".8"
android:includeFontPadding="false"
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_password_view.xml b/packages/SystemUI/res-keyguard/layout/keyguard_password_view.xml
index b06d6a989cb8..e1550aa0c87c 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_password_view.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_password_view.xml
@@ -34,7 +34,7 @@
android:layout_weight="7"
/>
- <!-- Password entry field -->
+ <!-- Password entry field -->
<FrameLayout
android:layout_height="wrap_content"
android:layout_width="280dp"
@@ -51,9 +51,9 @@
android:textStyle="normal"
android:inputType="textPassword"
android:textSize="16sp"
- android:textColor="?attr/wallpaperTextColor"
android:textAppearance="?android:attr/textAppearanceMedium"
android:imeOptions="flagForceAscii|actionDone"
+ android:textCursorDrawable="@null"
android:maxLength="500"
/>
@@ -65,7 +65,7 @@
android:contentDescription="@string/accessibility_ime_switch_button"
android:clickable="true"
android:padding="8dip"
- android:tint="@color/background_protected"
+ android:tint="?android:attr/textColorPrimary"
android:layout_gravity="end|center_vertical"
android:background="?android:attr/selectableItemBackground"
android:visibility="gone"
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_pin_view.xml b/packages/SystemUI/res-keyguard/layout/keyguard_pin_view.xml
index a75b35d117b6..87c98d2e9597 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_pin_view.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_pin_view.xml
@@ -46,11 +46,10 @@
android:id="@+id/pinEntry"
android:layout_width="@dimen/keyguard_security_width"
android:layout_height="match_parent"
- android:gravity="center"
+ style="@style/Widget.TextView.Password"
android:layout_centerHorizontal="true"
android:layout_marginRight="72dp"
androidprv:scaledTextSize="@integer/scaled_password_text_size"
- android:textColor="?attr/wallpaperTextColor"
android:contentDescription="@string/keyguard_accessibility_pin_area"
/>
<View
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_sim_pin_view.xml b/packages/SystemUI/res-keyguard/layout/keyguard_sim_pin_view.xml
index cd61a3775bf7..912d7bbf7ef5 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_sim_pin_view.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_sim_pin_view.xml
@@ -64,7 +64,6 @@
android:layout_centerHorizontal="true"
android:layout_marginRight="72dp"
androidprv:scaledTextSize="@integer/scaled_password_text_size"
- android:textColor="?attr/wallpaperTextColor"
android:contentDescription="@string/keyguard_accessibility_sim_pin_area"
/>
<View
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_sim_puk_view.xml b/packages/SystemUI/res-keyguard/layout/keyguard_sim_puk_view.xml
index bb757356f2b9..81b49648ab62 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_sim_puk_view.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_sim_puk_view.xml
@@ -65,7 +65,6 @@
android:layout_centerHorizontal="true"
android:layout_marginRight="72dp"
androidprv:scaledTextSize="@integer/scaled_password_text_size"
- android:textColor="?attr/wallpaperTextColor"
android:contentDescription="@string/keyguard_accessibility_sim_puk_area"
/>
<View
diff --git a/packages/SystemUI/res-keyguard/values/styles.xml b/packages/SystemUI/res-keyguard/values/styles.xml
index 401f3e3e0685..bc48e8fe3eea 100644
--- a/packages/SystemUI/res-keyguard/values/styles.xml
+++ b/packages/SystemUI/res-keyguard/values/styles.xml
@@ -20,41 +20,46 @@
<resources>
<!-- Keyguard PIN pad styles -->
<style name="Keyguard.TextView" parent="@android:style/Widget.DeviceDefault.TextView">
- <item name="android:textColor">?attr/wallpaperTextColorSecondary</item>
<item name="android:textSize">@dimen/kg_status_line_font_size</item>
</style>
<style name="Keyguard.TextView.EmergencyButton" parent="Theme.SystemUI">
- <item name="android:textColor">?attr/wallpaperTextColorSecondary</item>
+ <item name="android:textColor">?android:attr/textColorSecondary</item>
<item name="android:textSize">14dp</item>
<item name="android:background">@drawable/kg_emergency_button_background</item>
<item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
<item name="android:paddingLeft">12dp</item>
<item name="android:paddingRight">12dp</item>
</style>
- <style name="Widget.TextView.NumPadKey" parent="@android:style/Widget.TextView">
+ <style name="Widget.TextView.NumPadKey" parent="@android:style/Widget.DeviceDefault.TextView">
<item name="android:singleLine">true</item>
<item name="android:gravity">center_horizontal|center_vertical</item>
<item name="android:background">@null</item>
<item name="android:textSize">32sp</item>
+ <item name="android:textColor">?android:attr/textColorPrimary</item>
<item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
- <item name="android:textColor">?attr/wallpaperTextColor</item>
<item name="android:paddingBottom">-16dp</item>
+ <item name="android:colorControlHighlight">?android:attr/textColorPrimary</item>
+ </style>
+ <style name="Widget.TextView.Password" parent="@android:style/Widget.TextView">
+ <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
+ <item name="android:gravity">center</item>
+ <item name="android:textColor">?android:attr/textColorPrimary</item>
</style>
- <style name="Keyguard.ImageButton.NumPadDelete" parent="@android:style/Widget.ImageButton">
+ <style name="Keyguard.ImageButton.NumPadDelete" parent="@android:style/Widget.DeviceDefault.ImageButton">
<item name="android:src">@drawable/ic_backspace_black_24dp</item>
<item name="android:paddingBottom">11sp</item>
- <item name="android:tint">@color/pin_delete_color</item>
+ <item name="android:tint">?android:attr/textColorSecondary</item>
<item name="android:tintMode">src_in</item>
<item name="android:src">@drawable/ic_backspace_black_24dp</item>
</style>
- <style name="Keyguard.ImageButton.NumPadEnter" parent="@android:style/Widget.ImageButton">
+ <style name="Keyguard.ImageButton.NumPadEnter" parent="@android:style/Widget.DeviceDefault.ImageButton">
<item name="android:src">@drawable/ic_keyboard_tab_36dp</item>
<item name="android:paddingBottom">11sp</item>
</style>
- <style name="Widget.TextView.NumPadKey.Klondike" parent="Widget.TextView.NumPadKey">
+ <style name="Widget.TextView.NumPadKey.Klondike">
<item name="android:textSize">12sp</item>
<item name="android:fontFamily">@*android:string/config_bodyFontFamily</item>
- <item name="android:textColor">?attr/wallpaperTextColorSecondary</item>
+ <item name="android:textColor">?android:attr/textColorSecondary</item>
<item name="android:paddingBottom">0dp</item>
</style>
@@ -95,15 +100,9 @@
</style>
<style name="PasswordTheme" parent="Theme.SystemUI">
- <item name="android:textColor">?attr/wallpaperTextColor</item>
- <item name="android:colorControlNormal">?attr/wallpaperTextColor</item>
- <item name="android:colorControlActivated">?attr/wallpaperTextColor</item>
- </style>
-
- <style name="PasswordTheme.Light" parent="Theme.SystemUI.Light">
- <item name="android:textColor">?attr/wallpaperTextColor</item>
- <item name="android:colorControlNormal">?attr/wallpaperTextColor</item>
- <item name="android:colorControlActivated">?attr/wallpaperTextColor</item>
+ <item name="android:textColor">?android:attr/textColorPrimary</item>
+ <item name="android:colorControlNormal">?android:attr/textColorPrimary</item>
+ <item name="android:colorControlActivated">?android:attr/textColorPrimary</item>
</style>
<style name="Theme.SystemUI.KeyguardPresentation">
diff --git a/packages/SystemUI/res/color/pin_delete_color.xml b/packages/SystemUI/res/color/pin_delete_color.xml
index 7d4f1321d52f..c1b4cf87e923 100644
--- a/packages/SystemUI/res/color/pin_delete_color.xml
+++ b/packages/SystemUI/res/color/pin_delete_color.xml
@@ -15,5 +15,5 @@
~ limitations under the License
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:alpha="0.61" android:color="?attr/wallpaperTextColor" />
+ <item android:alpha="0.61" android:color="?android:attr/textColor" />
</selector> \ No newline at end of file
diff --git a/packages/SystemUI/res/color/pin_divider_color.xml b/packages/SystemUI/res/color/pin_divider_color.xml
index aff23171eee3..e05772fab8b2 100644
--- a/packages/SystemUI/res/color/pin_divider_color.xml
+++ b/packages/SystemUI/res/color/pin_divider_color.xml
@@ -15,5 +15,5 @@
~ limitations under the License
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:alpha="0.45" android:color="?attr/wallpaperTextColorSecondary" />
+ <item android:alpha="0.45" android:color="?android:attr/textColorSecondary" />
</selector> \ No newline at end of file
diff --git a/packages/SystemUI/res/color/qs_background_dark.xml b/packages/SystemUI/res/color/qs_background_dark.xml
index 24afebde046b..c47959a04fff 100644
--- a/packages/SystemUI/res/color/qs_background_dark.xml
+++ b/packages/SystemUI/res/color/qs_background_dark.xml
@@ -16,5 +16,5 @@
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:alpha="1"
- android:color="?android:attr/colorBackgroundFloating"/>
+ android:color="?android:attr/colorBackground"/>
</selector>
diff --git a/packages/SystemUI/res/drawable/notification_guts_bg.xml b/packages/SystemUI/res/drawable/notification_guts_bg.xml
index 2fe6c7b2d1a2..d62687883c35 100644
--- a/packages/SystemUI/res/drawable/notification_guts_bg.xml
+++ b/packages/SystemUI/res/drawable/notification_guts_bg.xml
@@ -16,7 +16,7 @@
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android">
- <solid android:color="@color/notification_material_background_color" />
+ <solid android:color="?android:attr/colorBackground" />
<!--The radius is 1dp smaller than the notification one, to avoid aliasing bugs on the corners -->
<corners android:radius="1dp" />
</shape>
diff --git a/packages/SystemUI/res/drawable/notification_material_bg.xml b/packages/SystemUI/res/drawable/notification_material_bg.xml
index ae456631c4f1..1e9be2fb9b05 100644
--- a/packages/SystemUI/res/drawable/notification_material_bg.xml
+++ b/packages/SystemUI/res/drawable/notification_material_bg.xml
@@ -19,7 +19,7 @@
android:color="@color/notification_ripple_untinted_color">
<item>
<shape>
- <solid android:color="@color/notification_material_background_color" />
+ <solid android:color="?android:attr/colorBackground" />
</shape>
</item>
</ripple> \ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/notification_material_bg_dim.xml b/packages/SystemUI/res/drawable/notification_material_bg_dim.xml
index b6a8b70bb3e0..1127d3c247fd 100644
--- a/packages/SystemUI/res/drawable/notification_material_bg_dim.xml
+++ b/packages/SystemUI/res/drawable/notification_material_bg_dim.xml
@@ -17,7 +17,7 @@
<ripple xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape>
- <solid android:color="@color/notification_material_background_dimmed_color" />
+ <solid android:color="@color/notification_background_dimmed_color" />
</shape>
</item>
</ripple>
diff --git a/packages/SystemUI/res/layout/app_ops_info.xml b/packages/SystemUI/res/layout/app_ops_info.xml
index 667c857b6967..ecf572ba4a5c 100644
--- a/packages/SystemUI/res/layout/app_ops_info.xml
+++ b/packages/SystemUI/res/layout/app_ops_info.xml
@@ -26,7 +26,7 @@
android:orientation="vertical"
android:paddingStart="@*android:dimen/notification_content_margin_start"
android:paddingEnd="@*android:dimen/notification_content_margin_end"
- android:background="@color/notification_material_background_color"
+ android:background="?android:attr/colorBackground"
android:theme="@*android:style/Theme.DeviceDefault.Light">
<!-- Package Info -->
diff --git a/packages/SystemUI/res/layout/disabled_udfps_view.xml b/packages/SystemUI/res/layout/disabled_udfps_view.xml
new file mode 100644
index 000000000000..aab86613ef45
--- /dev/null
+++ b/packages/SystemUI/res/layout/disabled_udfps_view.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2020 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<com.android.keyguard.DisabledUdfpsView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:systemui="http://schemas.android.com/apk/res-auto"
+ android:id="@+id/disabled_udfps_view"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:background="@drawable/circle_white"
+/>
diff --git a/packages/SystemUI/res/layout/feedback_info.xml b/packages/SystemUI/res/layout/feedback_info.xml
index 5e847a28558e..7047c1b21961 100644
--- a/packages/SystemUI/res/layout/feedback_info.xml
+++ b/packages/SystemUI/res/layout/feedback_info.xml
@@ -26,7 +26,7 @@
android:orientation="vertical"
android:paddingStart="@*android:dimen/notification_content_margin_start"
android:paddingEnd="@*android:dimen/notification_content_margin_end"
- android:background="@color/notification_material_background_color"
+ android:background="?android:attr/colorBackground"
android:theme="@*android:style/Theme.DeviceDefault.Light">
<!-- Package Info -->
diff --git a/packages/SystemUI/res/layout/global_actions_grid_v2.xml b/packages/SystemUI/res/layout/global_actions_grid_v2.xml
index 7d45de3fa50d..30ffc32ce1f8 100644
--- a/packages/SystemUI/res/layout/global_actions_grid_v2.xml
+++ b/packages/SystemUI/res/layout/global_actions_grid_v2.xml
@@ -1,67 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/global_actions_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
>
- <com.android.systemui.globalactions.GlobalActionsFlatLayout
- android:id="@id/global_actions_view"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal"
- android:theme="@style/qs_theme"
- android:clipChildren="false"
- android:clipToPadding="false"
- android:layout_marginStart="@dimen/global_actions_side_margin"
- >
- <LinearLayout
- android:id="@android:id/list"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:paddingTop="@dimen/global_actions_grid_vertical_padding"
- android:paddingBottom="@dimen/global_actions_grid_vertical_padding"
- android:orientation="horizontal"
- android:gravity="left | center_vertical"
- android:translationZ="@dimen/global_actions_translate"
- >
- <RelativeLayout
- android:id="@+id/global_actions_overflow_button"
- android:contentDescription="@string/accessibility_menu"
- android:layout_width="48dp"
- android:layout_height="48dp"
- >
- <ImageView
- android:src="@drawable/ic_more_vert"
- android:layout_centerInParent="true"
- android:layout_width="24dp"
- android:layout_height="24dp"
- android:tint="@color/control_more_vert"
- />
- </RelativeLayout>
- </LinearLayout>
- </com.android.systemui.globalactions.GlobalActionsFlatLayout>
- <androidx.constraintlayout.widget.ConstraintLayout
- android:id="@+id/global_actions_lock_message_container"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:visibility="gone">
- <TextView
- android:id="@+id/global_actions_lock_message"
- style="@style/TextAppearance.Control.Title"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginHorizontal="@dimen/global_actions_side_margin"
- android:drawablePadding="12dp"
- android:gravity="center"
- android:text="@string/global_action_lock_message"
- app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintTop_toTopOf="parent"
- app:layout_constraintVertical_bias="0.35"/>
- </androidx.constraintlayout.widget.ConstraintLayout>
+ <include layout="@layout/global_actions_view" />
+
+ <include layout="@layout/global_actions_lock_view" />
<com.android.systemui.globalactions.MinHeightScrollView
android:layout_width="match_parent"
diff --git a/packages/SystemUI/res/layout/global_actions_lock_view.xml b/packages/SystemUI/res/layout/global_actions_lock_view.xml
new file mode 100644
index 000000000000..eccc63688065
--- /dev/null
+++ b/packages/SystemUI/res/layout/global_actions_lock_view.xml
@@ -0,0 +1,35 @@
+<!--
+ ~ Copyright (C) 2020 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<androidx.constraintlayout.widget.ConstraintLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:id="@+id/global_actions_lock_message_container"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:visibility="gone">
+ <TextView
+ android:id="@+id/global_actions_lock_message"
+ style="@style/TextAppearance.Control.Title"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginHorizontal="@dimen/global_actions_side_margin"
+ android:drawablePadding="12dp"
+ android:gravity="center"
+ android:text="@string/global_action_lock_message"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintVertical_bias="0.35"/>
+</androidx.constraintlayout.widget.ConstraintLayout> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/global_actions_view.xml b/packages/SystemUI/res/layout/global_actions_view.xml
new file mode 100644
index 000000000000..454707bc44e2
--- /dev/null
+++ b/packages/SystemUI/res/layout/global_actions_view.xml
@@ -0,0 +1,52 @@
+<!--
+ ~ Copyright (C) 2020 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<com.android.systemui.globalactions.GlobalActionsFlatLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@id/global_actions_view"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:theme="@style/qs_theme"
+ android:clipChildren="false"
+ android:clipToPadding="false"
+ android:layout_marginStart="@dimen/global_actions_side_margin"
+ >
+ <LinearLayout
+ android:id="@android:id/list"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingTop="@dimen/global_actions_grid_vertical_padding"
+ android:paddingBottom="@dimen/global_actions_grid_vertical_padding"
+ android:orientation="horizontal"
+ android:gravity="left | center_vertical"
+ android:translationZ="@dimen/global_actions_translate"
+ >
+ <RelativeLayout
+ android:id="@+id/global_actions_overflow_button"
+ android:contentDescription="@string/accessibility_menu"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ >
+ <ImageView
+ android:src="@drawable/ic_more_vert"
+ android:layout_centerInParent="true"
+ android:layout_width="24dp"
+ android:layout_height="24dp"
+ android:tint="@color/control_more_vert"
+ />
+ </RelativeLayout>
+ </LinearLayout>
+</com.android.systemui.globalactions.GlobalActionsFlatLayout> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/global_screenshot.xml b/packages/SystemUI/res/layout/global_screenshot.xml
index 6c20c1e95c6d..2bf41d2472be 100644
--- a/packages/SystemUI/res/layout/global_screenshot.xml
+++ b/packages/SystemUI/res/layout/global_screenshot.xml
@@ -40,18 +40,4 @@
android:visibility="gone"
android:pointerIcon="crosshair"/>
<include layout="@layout/global_screenshot_static"/>
- <FrameLayout
- android:id="@+id/global_screenshot_dismiss_button"
- android:layout_width="@dimen/screenshot_dismiss_button_tappable_size"
- android:layout_height="@dimen/screenshot_dismiss_button_tappable_size"
- android:elevation="7dp"
- android:visibility="gone"
- android:contentDescription="@string/screenshot_dismiss_description">
- <ImageView
- android:id="@+id/global_screenshot_dismiss_image"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_margin="@dimen/screenshot_dismiss_button_margin"
- android:src="@drawable/screenshot_cancel"/>
- </FrameLayout>
</com.android.systemui.screenshot.ScreenshotView>
diff --git a/packages/SystemUI/res/layout/global_screenshot_static.xml b/packages/SystemUI/res/layout/global_screenshot_static.xml
index 096ec7ddd004..9f63c4334a8c 100644
--- a/packages/SystemUI/res/layout/global_screenshot_static.xml
+++ b/packages/SystemUI/res/layout/global_screenshot_static.xml
@@ -17,7 +17,6 @@
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
- android:fitsSystemWindows="true"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
@@ -62,4 +61,22 @@
</LinearLayout>
</HorizontalScrollView>
<include layout="@layout/global_screenshot_preview"/>
+ <FrameLayout
+ android:id="@+id/global_screenshot_dismiss_button"
+ android:layout_width="@dimen/screenshot_dismiss_button_tappable_size"
+ android:layout_height="@dimen/screenshot_dismiss_button_tappable_size"
+ android:elevation="7dp"
+ android:visibility="gone"
+ app:layout_constraintStart_toEndOf="@id/global_screenshot_preview"
+ app:layout_constraintEnd_toEndOf="@id/global_screenshot_preview"
+ app:layout_constraintTop_toTopOf="@id/global_screenshot_preview"
+ app:layout_constraintBottom_toTopOf="@id/global_screenshot_preview"
+ android:contentDescription="@string/screenshot_dismiss_description">
+ <ImageView
+ android:id="@+id/global_screenshot_dismiss_image"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_margin="@dimen/screenshot_dismiss_button_margin"
+ android:src="@drawable/screenshot_cancel"/>
+ </FrameLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/packages/SystemUI/res/layout/notification_conversation_info.xml b/packages/SystemUI/res/layout/notification_conversation_info.xml
index 10ad8291636e..fcc1aed65470 100644
--- a/packages/SystemUI/res/layout/notification_conversation_info.xml
+++ b/packages/SystemUI/res/layout/notification_conversation_info.xml
@@ -24,7 +24,7 @@
android:clipChildren="true"
android:clipToPadding="true"
android:orientation="vertical"
- android:background="@color/notification_material_background_color"
+ android:background="?android:attr/colorBackground"
android:paddingStart="12dp">
<!-- Package Info -->
diff --git a/packages/SystemUI/res/layout/notification_guts.xml b/packages/SystemUI/res/layout/notification_guts.xml
index 5399f57c322f..fb75dd348a41 100644
--- a/packages/SystemUI/res/layout/notification_guts.xml
+++ b/packages/SystemUI/res/layout/notification_guts.xml
@@ -22,5 +22,4 @@
android:focusable="true"
android:id="@+id/notification_guts"
android:visibility="gone"
- android:gravity="top|start"
- android:theme="@*android:style/Theme.DeviceDefault.Light"/>
+ android:gravity="top|start"/>
diff --git a/packages/SystemUI/res/layout/notification_snooze.xml b/packages/SystemUI/res/layout/notification_snooze.xml
index 253bc328c5b8..dc9d92001351 100644
--- a/packages/SystemUI/res/layout/notification_snooze.xml
+++ b/packages/SystemUI/res/layout/notification_snooze.xml
@@ -20,7 +20,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
- android:background="@color/notification_material_background_color"
+ android:background="?android:attr/colorBackground"
android:theme="@style/Theme.SystemUI">
<RelativeLayout
diff --git a/packages/SystemUI/res/layout/quick_settings_footer.xml b/packages/SystemUI/res/layout/quick_settings_footer.xml
index e7c7b5fbf890..13572fa9f4f3 100644
--- a/packages/SystemUI/res/layout/quick_settings_footer.xml
+++ b/packages/SystemUI/res/layout/quick_settings_footer.xml
@@ -26,11 +26,19 @@
android:layout_gravity="center_vertical|center_horizontal"
android:background="@android:color/transparent">
+ <ImageView
+ android:id="@+id/primary_footer_icon"
+ android:layout_width="@dimen/qs_footer_icon_size"
+ android:layout_height="@dimen/qs_footer_icon_size"
+ android:gravity="start"
+ android:layout_marginEnd="8dp"
+ android:contentDescription="@null"
+ android:tint="?android:attr/textColorPrimary" />
+
<com.android.systemui.util.AutoMarqueeTextView
android:id="@+id/footer_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:gravity="start"
android:layout_weight="1"
android:singleLine="true"
android:ellipsize="marquee"
diff --git a/packages/SystemUI/res/layout/quick_settings_footer_dialog_parental_controls.xml b/packages/SystemUI/res/layout/quick_settings_footer_dialog_parental_controls.xml
index 1a356769d334..3e40321aba42 100644
--- a/packages/SystemUI/res/layout/quick_settings_footer_dialog_parental_controls.xml
+++ b/packages/SystemUI/res/layout/quick_settings_footer_dialog_parental_controls.xml
@@ -29,8 +29,8 @@
android:orientation="vertical">
<ImageView
android:id="@+id/parental_controls_icon"
- android:layout_width="36dip"
- android:layout_height="36dip"
+ android:layout_width="24dip"
+ android:layout_height="24dip"
android:layout_gravity="center_horizontal"
/>
diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml
index 1d4b98242519..75f76b431da8 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded.xml
@@ -92,13 +92,5 @@
layout="@layout/keyguard_bottom_area"
android:visibility="gone" />
- <com.android.systemui.statusbar.AlphaOptimizedView
- android:id="@+id/qs_navbar_scrim"
- android:layout_height="96dp"
- android:layout_width="match_parent"
- android:layout_gravity="bottom"
- android:visibility="invisible"
- android:background="@drawable/qs_navbar_scrim" />
-
<include layout="@layout/status_bar_expanded_plugin_frame"/>
</com.android.systemui.statusbar.phone.NotificationPanelView>
diff --git a/packages/SystemUI/res/layout/status_bar_notification_section_header.xml b/packages/SystemUI/res/layout/status_bar_notification_section_header.xml
index b5822c889f1c..e33f186dcbb7 100644
--- a/packages/SystemUI/res/layout/status_bar_notification_section_header.xml
+++ b/packages/SystemUI/res/layout/status_bar_notification_section_header.xml
@@ -58,7 +58,6 @@
android:src="@drawable/status_bar_notification_section_header_clear_btn"
android:contentDescription="@string/accessibility_notification_section_header_gentle_clear_all"
android:scaleType="center"
- android:tint="?attr/wallpaperTextColor"
android:tintMode="src_in"
android:visibility="gone"
android:forceHasOverlappingRendering="false"
diff --git a/packages/SystemUI/res/layout/tv_notification_item.xml b/packages/SystemUI/res/layout/tv_notification_item.xml
new file mode 100644
index 000000000000..711cd4e4258a
--- /dev/null
+++ b/packages/SystemUI/res/layout/tv_notification_item.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2020 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="@dimen/tv_notification_panel_width"
+ android:layout_height="wrap_content"
+ android:background="?android:attr/selectableItemBackground"
+ android:orientation="vertical"
+ android:padding="12dp">
+
+ <TextView
+ android:id="@+id/tv_notification_title"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingBottom="12dp"
+ android:textColor="@color/tv_notification_text_color"
+ android:textSize="18sp" />
+
+ <TextView
+ android:id="@+id/tv_notification_details"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:textColor="@color/tv_notification_text_color" />
+
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/tv_notification_panel.xml b/packages/SystemUI/res/layout/tv_notification_panel.xml
new file mode 100644
index 000000000000..8f00a727b912
--- /dev/null
+++ b/packages/SystemUI/res/layout/tv_notification_panel.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2020 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/tv_notification_panel"
+ android:layout_width="@dimen/tv_notification_panel_width"
+ android:layout_height="match_parent"
+ android:layout_gravity="end"
+ android:background="@color/tv_notification_background_color"
+ android:orientation="vertical">
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:padding="12dp"
+ android:paddingTop="24dp"
+ android:text="@string/tv_notification_panel_title"
+ android:textColor="@color/tv_notification_text_color"
+ android:textSize="24sp"
+ android:textStyle="bold" />
+
+ <TextView
+ android:id="@+id/no_tv_notifications"
+ style="?android:attr/titleTextStyle"
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1"
+ android:gravity="top|center"
+ android:paddingTop="24dp"
+ android:text="@string/tv_notification_panel_no_notifications"
+ android:textColor="@color/tv_notification_text_color"
+ android:visibility="gone" />
+
+ <androidx.leanback.widget.VerticalGridView
+ android:id="@+id/notifications_list"
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1" />
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/udfps_view.xml b/packages/SystemUI/res/layout/udfps_view.xml
index ccd235d54c0b..c0788051efed 100644
--- a/packages/SystemUI/res/layout/udfps_view.xml
+++ b/packages/SystemUI/res/layout/udfps_view.xml
@@ -1,4 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2020 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
<com.android.systemui.biometrics.UdfpsView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:systemui="http://schemas.android.com/apk/res-auto"
diff --git a/packages/SystemUI/res/values-night/colors.xml b/packages/SystemUI/res/values-night/colors.xml
index cb9e178de243..8cc747bf04d6 100644
--- a/packages/SystemUI/res/values-night/colors.xml
+++ b/packages/SystemUI/res/values-night/colors.xml
@@ -17,22 +17,13 @@
NOTE: You might also want to edit: core/res/res/values-night/*.xml
-->
<resources>
- <!-- The color of the material notification background -->
- <color name="notification_material_background_color">@*android:color/notification_material_background_color</color>
-
<!-- The color of the legacy notifications with customs backgrounds (gingerbread and lollipop.)
It's fine to override this color since at that point the shade was dark. -->
- <color name="notification_legacy_background_color">@*android:color/notification_material_background_color</color>
-
- <!-- The color of the material notification background when dimmed -->
- <color name="notification_material_background_dimmed_color">#aa000000</color>
+ <color name="notification_legacy_background_color">@color/GM2_grey_900</color>
<!-- The color of the dividing line between grouped notifications while . -->
<color name="notification_divider_color">#212121</color>
- <!-- The background color of the notification shade -->
- <color name="notification_shade_background_color">@color/GM2_grey_900</color>
-
<!-- The color of the gear shown behind a notification -->
<color name="notification_gear_color">@color/GM2_grey_500</color>
diff --git a/packages/SystemUI/res/values-television/config.xml b/packages/SystemUI/res/values-television/config.xml
index 09ec439b183e..0c8c5c443c4a 100644
--- a/packages/SystemUI/res/values-television/config.xml
+++ b/packages/SystemUI/res/values-television/config.xml
@@ -29,7 +29,8 @@
<item>com.android.systemui.util.NotificationChannels</item>
<item>com.android.systemui.volume.VolumeUI</item>
<item>com.android.systemui.statusbar.tv.TvStatusBar</item>
- <item>com.android.systemui.statusbar.tv.TvNotificationPanel</item>
+ <item>com.android.systemui.statusbar.tv.notifications.TvNotificationPanel</item>
+ <item>com.android.systemui.statusbar.tv.notifications.TvNotificationHandler</item>
<item>com.android.systemui.statusbar.tv.VpnStatusObserver</item>
<item>com.android.systemui.usb.StorageNotification</item>
<item>com.android.systemui.power.PowerUI</item>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index be36316d013c..c51e0bf2c31b 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -80,21 +80,12 @@
<!-- The color of the legacy notification background -->
<color name="notification_legacy_background_color">#ff1a1a1a</color>
- <!-- The color of the material notification background -->
- <color name="notification_material_background_color">@*android:color/notification_material_background_color</color>
-
- <!-- The color of the material notification background when dimmed -->
- <color name="notification_material_background_dimmed_color">#ccffffff</color>
-
<!-- The color of the material notification background when dark -->
<color name="notification_material_background_dark_color">#ff333333</color>
<!-- The color of the dividing line between grouped notifications. -->
<color name="notification_divider_color">#FF616161</color>
- <!-- The background color of the notification shade -->
- <color name="notification_shade_background_color">@color/GM2_grey_200</color>
-
<!-- The color of the ripples on the untinted notifications -->
<color name="notification_ripple_untinted_color">#28000000</color>
diff --git a/packages/SystemUI/res/values/colors_tv.xml b/packages/SystemUI/res/values/colors_tv.xml
index 9b0ae1d61de6..0961f503e7d4 100644
--- a/packages/SystemUI/res/values/colors_tv.xml
+++ b/packages/SystemUI/res/values/colors_tv.xml
@@ -33,4 +33,7 @@
<color name="tv_volume_dialog_seek_bar_background">#A03C4043</color>
<color name="tv_volume_dialog_seek_bar_fill">#FFF8F9FA</color>
<color name="tv_volume_dialog_accent">#FFDADCE0</color>
+
+ <color name="tv_notification_background_color">#383838</color>
+ <color name="tv_notification_text_color">#FFFFFF</color>
</resources>
diff --git a/packages/SystemUI/res/drawable/qs_navbar_scrim.xml b/packages/SystemUI/res/values/dimens_tv.xml
index bbb2617db4a0..9545bfd088a0 100644
--- a/packages/SystemUI/res/drawable/qs_navbar_scrim.xml
+++ b/packages/SystemUI/res/values/dimens_tv.xml
@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
-
<!--
- ~ Copyright (C) 2014 The Android Open Source Project
+ ~ Copyright (C) 2020 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
@@ -13,13 +12,8 @@
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT 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.
-->
-
-<shape xmlns:android="http://schemas.android.com/apk/res/android">
- <gradient
- android:type="linear"
- android:angle="90"
- android:startColor="#55000000"
- android:endColor="#00000000" />
-</shape> \ No newline at end of file
+<resources>
+ <dimen name="tv_notification_panel_width">360dp</dimen>
+</resources> \ No newline at end of file
diff --git a/packages/SystemUI/res/values/strings_tv.xml b/packages/SystemUI/res/values/strings_tv.xml
index 13271d6f7f2e..b51cb5619f0c 100644
--- a/packages/SystemUI/res/values/strings_tv.xml
+++ b/packages/SystemUI/res/values/strings_tv.xml
@@ -26,4 +26,6 @@
<!-- Disclosure text in the connected notification that indicates that the device is connected to a VPN. The placeholder is the VPN name. [CHAR LIMIT=40] -->
<string name="notification_disclosure_vpn_text">Via <xliff:g id="vpn_app" example="Foo VPN App">%1$s</xliff:g></string>
+ <string name="tv_notification_panel_title">Notifications</string>
+ <string name="tv_notification_panel_no_notifications">No Notifications</string>
</resources>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index f38e653190b0..0697c5c0084c 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -334,7 +334,6 @@
<item name="wallpaperTextColorSecondary">@*android:color/secondary_text_material_light</item>
<item name="android:colorError">@*android:color/error_color_material_light</item>
<item name="android:colorControlHighlight">#40000000</item>
- <item name="passwordStyle">@style/PasswordTheme.Light</item>
<item name="shadowRadius">0</item>
<!-- Needed for MediaRoute chooser dialog -->
@@ -356,8 +355,8 @@
</style>
<style name="LockPatternStyle">
- <item name="*android:regularColor">?attr/wallpaperTextColor</item>
- <item name="*android:successColor">?attr/wallpaperTextColor</item>
+ <item name="*android:regularColor">?android:attr/textColorPrimary</item>
+ <item name="*android:successColor">?android:attr/textColorPrimary</item>
<item name="*android:errorColor">?android:attr/colorError</item>
</style>
@@ -555,8 +554,8 @@
<style
name="TextAppearance.NotificationSectionHeaderButton"
- parent="@android:style/Widget.Material.Button.Borderless">
- <item name="android:textColor">?attr/wallpaperTextColor</item>
+ parent="@android:style/Widget.DeviceDefault.Button.Borderless">
+ <item name="android:textColor">?android:attr/textColorPrimary</item>
<item name="android:textAllCaps">false</item>
<item name="android:textSize">14sp</item>
<item name="android:minWidth">0dp</item>
diff --git a/packages/SystemUI/res/values/styles_tv.xml b/packages/SystemUI/res/values/styles_tv.xml
index 0c4fd23ca107..cb433f3a6009 100644
--- a/packages/SystemUI/res/values/styles_tv.xml
+++ b/packages/SystemUI/res/values/styles_tv.xml
@@ -23,4 +23,12 @@
<item name="android:backgroundDimEnabled">false</item>
<item name="android:windowDisablePreview">true</item>
</style>
+
+ <style name="TvSidePanelTheme">
+ <item name="android:windowIsTranslucent">true</item>
+ <item name="android:windowBackground">@android:color/transparent</item>
+ <item name="android:backgroundDimEnabled">false</item>
+ <item name="android:windowNoTitle">true</item>
+ <item name="android:windowContentOverlay">@null</item>
+ </style>
</resources>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
index dd57af33b4dc..229d20b6543e 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
@@ -20,6 +20,7 @@ import static android.app.ActivityManager.LOCK_TASK_MODE_LOCKED;
import static android.app.ActivityManager.LOCK_TASK_MODE_NONE;
import static android.app.ActivityManager.LOCK_TASK_MODE_PINNED;
import static android.app.ActivityManager.RECENT_IGNORE_UNAVAILABLE;
+import static android.app.ActivityTaskManager.getService;
import android.annotation.NonNull;
import android.app.Activity;
@@ -53,7 +54,6 @@ import com.android.internal.app.IVoiceInteractionManagerService;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.recents.model.ThumbnailData;
-import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
@@ -70,6 +70,7 @@ public class ActivityManagerWrapper {
// Should match the value in AssistManager
private static final String INVOCATION_TIME_MS_KEY = "invocation_time_ms";
+ private final ActivityTaskManager mAtm = ActivityTaskManager.getInstance();
private ActivityManagerWrapper() { }
public static ActivityManagerWrapper getInstance() {
@@ -102,29 +103,19 @@ public class ActivityManagerWrapper {
*/
public ActivityManager.RunningTaskInfo getRunningTask(boolean filterOnlyVisibleRecents) {
// Note: The set of running tasks from the system is ordered by recency
- try {
- List<ActivityManager.RunningTaskInfo> tasks =
- ActivityTaskManager.getService().getFilteredTasks(1, filterOnlyVisibleRecents);
- if (tasks.isEmpty()) {
- return null;
- }
- return tasks.get(0);
- } catch (RemoteException e) {
+ List<ActivityManager.RunningTaskInfo> tasks =
+ mAtm.getTasks(1, filterOnlyVisibleRecents);
+ if (tasks.isEmpty()) {
return null;
}
+ return tasks.get(0);
}
/**
* @return a list of the recents tasks.
*/
public List<RecentTaskInfo> getRecentTasks(int numTasks, int userId) {
- try {
- return ActivityTaskManager.getService().getRecentTasks(numTasks,
- RECENT_IGNORE_UNAVAILABLE, userId).getList();
- } catch (RemoteException e) {
- Log.e(TAG, "Failed to get recent tasks", e);
- return new ArrayList<>();
- }
+ return mAtm.getRecentTasks(numTasks, RECENT_IGNORE_UNAVAILABLE, userId);
}
/**
@@ -133,7 +124,7 @@ public class ActivityManagerWrapper {
public @NonNull ThumbnailData getTaskThumbnail(int taskId, boolean isLowResolution) {
ActivityManager.TaskSnapshot snapshot = null;
try {
- snapshot = ActivityTaskManager.getService().getTaskSnapshot(taskId, isLowResolution);
+ snapshot = getService().getTaskSnapshot(taskId, isLowResolution);
} catch (RemoteException e) {
Log.w(TAG, "Failed to retrieve task snapshot", e);
}
@@ -149,8 +140,7 @@ public class ActivityManagerWrapper {
*/
public void invalidateHomeTaskSnapshot(final Activity homeActivity) {
try {
- ActivityTaskManager.getService().invalidateHomeTaskSnapshot(
- homeActivity.getActivityToken());
+ getService().invalidateHomeTaskSnapshot(homeActivity.getActivityToken());
} catch (RemoteException e) {
Log.w(TAG, "Failed to invalidate home snapshot", e);
}
@@ -208,7 +198,7 @@ public class ActivityManagerWrapper {
}
};
}
- ActivityTaskManager.getService().startRecentsActivity(intent, eventTime, runner);
+ getService().startRecentsActivity(intent, eventTime, runner);
return true;
} catch (Exception e) {
return false;
@@ -220,7 +210,7 @@ public class ActivityManagerWrapper {
*/
public void cancelRecentsAnimation(boolean restoreHomeRootTaskPosition) {
try {
- ActivityTaskManager.getService().cancelRecentsAnimation(restoreHomeRootTaskPosition);
+ getService().cancelRecentsAnimation(restoreHomeRootTaskPosition);
} catch (RemoteException e) {
Log.e(TAG, "Failed to cancel recents animation", e);
}
@@ -259,7 +249,7 @@ public class ActivityManagerWrapper {
public boolean startActivityFromRecents(int taskId, ActivityOptions options) {
try {
Bundle optsBundle = options == null ? null : options.toBundle();
- ActivityTaskManager.getService().startActivityFromRecents(taskId, optsBundle);
+ getService().startActivityFromRecents(taskId, optsBundle);
return true;
} catch (Exception e) {
return false;
@@ -296,7 +286,7 @@ public class ActivityManagerWrapper {
*/
public void removeTask(final int taskId) {
try {
- ActivityTaskManager.getService().removeTask(taskId);
+ getService().removeTask(taskId);
} catch (RemoteException e) {
Log.w(TAG, "Failed to remove task=" + taskId, e);
}
@@ -307,7 +297,7 @@ public class ActivityManagerWrapper {
*/
public void removeAllRecentTasks() {
try {
- ActivityTaskManager.getService().removeAllVisibleRecentTasks();
+ getService().removeAllVisibleRecentTasks();
} catch (RemoteException e) {
Log.w(TAG, "Failed to remove all tasks", e);
}
@@ -318,7 +308,7 @@ public class ActivityManagerWrapper {
*/
public boolean isScreenPinningActive() {
try {
- return ActivityTaskManager.getService().getLockTaskModeState() == LOCK_TASK_MODE_PINNED;
+ return getService().getLockTaskModeState() == LOCK_TASK_MODE_PINNED;
} catch (RemoteException e) {
return false;
}
@@ -337,7 +327,7 @@ public class ActivityManagerWrapper {
*/
public boolean isLockToAppActive() {
try {
- return ActivityTaskManager.getService().getLockTaskModeState() != LOCK_TASK_MODE_NONE;
+ return getService().getLockTaskModeState() != LOCK_TASK_MODE_NONE;
} catch (RemoteException e) {
return false;
}
@@ -348,7 +338,7 @@ public class ActivityManagerWrapper {
*/
public boolean isLockTaskKioskModeActive() {
try {
- return ActivityTaskManager.getService().getLockTaskModeState() == LOCK_TASK_MODE_LOCKED;
+ return getService().getLockTaskModeState() == LOCK_TASK_MODE_LOCKED;
} catch (RemoteException e) {
return false;
}
diff --git a/packages/SystemUI/src/com/android/keyguard/DisabledUdfpsController.java b/packages/SystemUI/src/com/android/keyguard/DisabledUdfpsController.java
new file mode 100644
index 000000000000..f01b67b7b5c2
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/DisabledUdfpsController.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.keyguard;
+
+import static android.hardware.biometrics.BiometricSourceType.FINGERPRINT;
+
+import android.hardware.biometrics.BiometricSourceType;
+import android.view.View;
+
+import androidx.annotation.NonNull;
+
+import com.android.systemui.Dumpable;
+import com.android.systemui.biometrics.AuthController;
+import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.util.ViewController;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
+/**
+ * Controls when to show the DisabledUdfpsView to unlock the device on the lockscreen.
+ * If the device is not authenticated, the bouncer will show.
+ *
+ * This tap target will only show when:
+ * - User has UDFPS enrolled
+ * - UDFPS is currently unavailable see {@link KeyguardUpdateMonitor#shouldListenForUdfps}
+ */
+@SysUISingleton
+public class DisabledUdfpsController extends ViewController<DisabledUdfpsView> implements Dumpable {
+ @NonNull private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+ @NonNull private final KeyguardViewController mKeyguardViewController;
+ @NonNull private final StatusBarStateController mStatusBarStateController;
+
+ private boolean mIsDozing;
+ private boolean mIsBouncerShowing;
+ private boolean mIsKeyguardShowing;
+ private boolean mRunningFPS;
+ private boolean mAuthenticated;
+
+ private boolean mShowButton;
+
+ public DisabledUdfpsController(
+ @NonNull DisabledUdfpsView view,
+ @NonNull StatusBarStateController statusBarStateController,
+ @NonNull KeyguardUpdateMonitor keyguardUpdateMonitor,
+ @NonNull AuthController authController,
+ @NonNull KeyguardViewController keyguardViewController
+ ) {
+ super(view);
+ mView.setOnClickListener(mOnClickListener);
+ mView.setSensorProperties(authController.getUdfpsProps().get(0));
+
+ mStatusBarStateController = statusBarStateController;
+ mKeyguardUpdateMonitor = keyguardUpdateMonitor;
+ mKeyguardViewController = keyguardViewController;
+ }
+
+ @Override
+ protected void onViewAttached() {
+ mKeyguardUpdateMonitor.registerCallback(mKeyguardUpdateMonitorCallback);
+ mIsBouncerShowing = mKeyguardViewController.isBouncerShowing();
+
+ mStatusBarStateController.addCallback(mStatusBarStateListener);
+ mIsKeyguardShowing = mStatusBarStateController.getState() == StatusBarState.KEYGUARD;
+ mIsDozing = mStatusBarStateController.isDozing();
+ mAuthenticated = false;
+ }
+
+ @Override
+ protected void onViewDetached() {
+ mKeyguardUpdateMonitor.removeCallback(mKeyguardUpdateMonitorCallback);
+ mStatusBarStateController.removeCallback(mStatusBarStateListener);
+ }
+
+ private void updateButtonVisibility() {
+ mShowButton = !mAuthenticated && !mIsDozing && mIsKeyguardShowing
+ && !mIsBouncerShowing && !mRunningFPS;
+ if (mShowButton) {
+ mView.setVisibility(View.VISIBLE);
+ } else {
+ mView.setVisibility(View.INVISIBLE);
+ }
+ }
+
+ @Override
+ public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) {
+ pw.println("DisabledUdfpsController state:");
+ pw.println(" mShowBouncerButton: " + mShowButton);
+ pw.println(" mIsDozing: " + mIsDozing);
+ pw.println(" mIsKeyguardShowing: " + mIsKeyguardShowing);
+ pw.println(" mIsBouncerShowing: " + mIsBouncerShowing);
+ pw.println(" mRunningFPS: " + mRunningFPS);
+ pw.println(" mAuthenticated: " + mAuthenticated);
+ }
+
+ private final View.OnClickListener mOnClickListener = new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ mKeyguardViewController.showBouncer(/* scrim */ true);
+ }
+ };
+
+ private StatusBarStateController.StateListener mStatusBarStateListener =
+ new StatusBarStateController.StateListener() {
+ @Override
+ public void onStateChanged(int newState) {
+ mIsKeyguardShowing = newState == StatusBarState.KEYGUARD;
+ updateButtonVisibility();
+ }
+
+ @Override
+ public void onDozingChanged(boolean isDozing) {
+ mIsDozing = isDozing;
+ updateButtonVisibility();
+ }
+ };
+
+ private final KeyguardUpdateMonitorCallback mKeyguardUpdateMonitorCallback =
+ new KeyguardUpdateMonitorCallback() {
+ @Override
+ public void onKeyguardBouncerChanged(boolean bouncer) {
+ mIsBouncerShowing = bouncer;
+ updateButtonVisibility();
+ }
+
+ @Override
+ public void onBiometricRunningStateChanged(boolean running,
+ BiometricSourceType biometricSourceType) {
+ mRunningFPS = running && biometricSourceType == FINGERPRINT;
+ updateButtonVisibility();
+ }
+
+ @Override
+ public void onUserUnlocked() {
+ mAuthenticated = true;
+ updateButtonVisibility();
+ }
+ };
+}
diff --git a/packages/SystemUI/src/com/android/keyguard/DisabledUdfpsView.java b/packages/SystemUI/src/com/android/keyguard/DisabledUdfpsView.java
new file mode 100644
index 000000000000..d8ab780eb6bd
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/DisabledUdfpsView.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.keyguard;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.graphics.RectF;
+import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
+import android.util.AttributeSet;
+import android.view.Surface;
+import android.widget.Button;
+import android.widget.FrameLayout;
+
+/**
+ * A full screen view with an oval target where the UDFPS sensor is.
+ * Controlled by {@link DisabledUdfpsController}.
+ */
+public class DisabledUdfpsView extends Button {
+ @NonNull private final RectF mSensorRect;
+ @NonNull private final Context mContext;
+
+ // Used to obtain the sensor location.
+ @NonNull private FingerprintSensorPropertiesInternal mSensorProps;
+
+ public DisabledUdfpsView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ mContext = context;
+ mSensorRect = new RectF();
+ }
+
+ public void setSensorProperties(@NonNull FingerprintSensorPropertiesInternal properties) {
+ mSensorProps = properties;
+ }
+
+ // The "h" and "w" are the display's height and width relative to its current rotation.
+ private void updateSensorRect(int h, int w) {
+ // mSensorProps coordinates assume portrait mode.
+ mSensorRect.set(mSensorProps.sensorLocationX - mSensorProps.sensorRadius,
+ mSensorProps.sensorLocationY - mSensorProps.sensorRadius,
+ mSensorProps.sensorLocationX + mSensorProps.sensorRadius,
+ mSensorProps.sensorLocationY + mSensorProps.sensorRadius);
+
+ // Transform mSensorRect if the device is in landscape mode.
+ switch (mContext.getDisplay().getRotation()) {
+ case Surface.ROTATION_90:
+ mSensorRect.set(mSensorRect.top, h - mSensorRect.right, mSensorRect.bottom,
+ h - mSensorRect.left);
+ break;
+ case Surface.ROTATION_270:
+ mSensorRect.set(w - mSensorRect.bottom, mSensorRect.left, w - mSensorRect.top,
+ mSensorRect.right);
+ break;
+ default:
+ // Do nothing to stay in portrait mode.
+ }
+
+ setX(mSensorRect.left);
+ setY(mSensorRect.top);
+ setLayoutParams(new FrameLayout.LayoutParams(
+ (int) (mSensorRect.right - mSensorRect.left),
+ (int) (mSensorRect.bottom - mSensorRect.top)));
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ super.onLayout(changed, left, top, right, bottom);
+ // Always re-compute the layout regardless of whether "changed" is true. It is usually false
+ // when the device goes from landscape to seascape and vice versa, but mSensorRect and
+ // its dependencies need to be recalculated to stay at the same physical location on the
+ // screen.
+ final int w = getLayoutParams().width;
+ final int h = getLayoutParams().height;
+ updateSensorRect(h, w);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/keyguard/EmergencyButton.java b/packages/SystemUI/src/com/android/keyguard/EmergencyButton.java
index 487e0d8ea38e..b7d7498e8960 100644
--- a/packages/SystemUI/src/com/android/keyguard/EmergencyButton.java
+++ b/packages/SystemUI/src/com/android/keyguard/EmergencyButton.java
@@ -41,6 +41,7 @@ import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.util.EmergencyAffordanceManager;
import com.android.internal.widget.LockPatternUtils;
+import com.android.settingslib.Utils;
import com.android.systemui.Dependency;
import com.android.systemui.util.EmergencyDialerConstants;
@@ -148,6 +149,17 @@ public class EmergencyButton extends Button {
return super.onTouchEvent(event);
}
+ /**
+ * Reload colors from resources.
+ **/
+ public void reloadColors() {
+ int color = Utils.getColorAttrDefaultColor(getContext(),
+ android.R.attr.textColorSecondary);
+ setTextColor(color);
+ setBackground(getContext()
+ .getDrawable(com.android.systemui.R.drawable.kg_emergency_button_background));
+ }
+
@Override
public boolean performLongClick() {
return super.performLongClick();
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java
index 217cf701b265..5760565aaab1 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java
@@ -20,6 +20,7 @@ import static com.android.internal.util.LatencyTracker.ACTION_CHECK_CREDENTIAL;
import static com.android.internal.util.LatencyTracker.ACTION_CHECK_CREDENTIAL_UNLOCKED;
import static com.android.keyguard.KeyguardAbsKeyInputView.MINIMUM_PASSWORD_LENGTH_BEFORE_REPORT;
+import android.annotation.CallSuper;
import android.content.res.ColorStateList;
import android.os.AsyncTask;
import android.os.CountDownTimer;
@@ -87,6 +88,7 @@ public abstract class KeyguardAbsKeyInputViewController<T extends KeyguardAbsKey
@Override
protected void onViewAttached() {
+ super.onViewAttached();
mView.setKeyDownListener(mKeyDownListener);
mView.setEnableHaptics(mLockPatternUtils.isTactileFeedbackEnabled());
EmergencyButton button = mView.findViewById(R.id.emergency_call_button);
@@ -110,6 +112,13 @@ public abstract class KeyguardAbsKeyInputViewController<T extends KeyguardAbsKey
}
}
+ @CallSuper
+ @Override
+ public void reloadColors() {
+ super.reloadColors();
+ mMessageAreaController.reloadColors();
+ }
+
@Override
public boolean needsInput() {
return false;
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
index c5c36e920d45..829ff9771fb4 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
@@ -62,6 +62,7 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
private AnimatableClockController mNewLockScreenClockViewController;
private FrameLayout mNewLockScreenClockFrame;
private AnimatableClockController mNewLockScreenLargeClockViewController;
+ private FrameLayout mNewLockScreenLargeClockFrame;
private int mLockScreenMode = KeyguardUpdateMonitor.LOCK_SCREEN_MODE_NORMAL;
@@ -126,6 +127,7 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
mView.updateColors(getGradientColors());
updateAodIcons();
mNewLockScreenClockFrame = mView.findViewById(R.id.new_lockscreen_clock_view);
+ mNewLockScreenLargeClockFrame = mView.findViewById(R.id.new_lockscreen_clock_view_large);
}
@Override
@@ -199,13 +201,18 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
/**
* Update position of the view, with optional animation. Move the slice view and the clock
* slightly towards the center in order to prevent burn-in. Y positioning occurs at the
- * view parent level.
+ * view parent level. The large clock view will scale instead of using x position offsets, to
+ * keep the clock centered.
*/
- void updatePosition(int x, AnimationProperties props, boolean animate) {
+ void updatePosition(int x, float scale, AnimationProperties props, boolean animate) {
x = Math.abs(x);
if (mNewLockScreenClockFrame != null) {
PropertyAnimator.setProperty(mNewLockScreenClockFrame, AnimatableProperty.TRANSLATION_X,
-x, props, animate);
+ PropertyAnimator.setProperty(mNewLockScreenLargeClockFrame, AnimatableProperty.SCALE_X,
+ scale, props, animate);
+ PropertyAnimator.setProperty(mNewLockScreenLargeClockFrame, AnimatableProperty.SCALE_Y,
+ scale, props, animate);
}
mKeyguardSliceViewController.updatePosition(x, props, animate);
mNotificationIconAreaController.updatePosition(x, props, animate);
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java
index fbda818740e8..6aa5e0df3653 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java
@@ -16,6 +16,7 @@
package com.android.keyguard;
+import android.annotation.CallSuper;
import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.telephony.TelephonyManager;
@@ -24,6 +25,7 @@ import android.view.inputmethod.InputMethodManager;
import com.android.internal.util.LatencyTracker;
import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
+import com.android.systemui.R;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.util.ViewController;
import com.android.systemui.util.concurrency.DelayableExecutor;
@@ -37,6 +39,7 @@ public abstract class KeyguardInputViewController<T extends KeyguardInputView>
private final SecurityMode mSecurityMode;
private final KeyguardSecurityCallback mKeyguardSecurityCallback;
+ private final EmergencyButton mEmergencyButton;
private boolean mPaused;
@@ -68,6 +71,7 @@ public abstract class KeyguardInputViewController<T extends KeyguardInputView>
super(view);
mSecurityMode = securityMode;
mKeyguardSecurityCallback = keyguardSecurityCallback;
+ mEmergencyButton = view == null ? null : view.findViewById(R.id.emergency_call_button);
}
@Override
@@ -112,6 +116,16 @@ public abstract class KeyguardInputViewController<T extends KeyguardInputView>
public void showMessage(CharSequence message, ColorStateList colorState) {
}
+ /**
+ * Reload colors from resources.
+ **/
+ @CallSuper
+ public void reloadColors() {
+ if (mEmergencyButton != null) {
+ mEmergencyButton.reloadColors();
+ }
+ }
+
public void startAppearAnimation() {
mView.startAppearAnimation();
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardMessageArea.java b/packages/SystemUI/src/com/android/keyguard/KeyguardMessageArea.java
index 1a0a4370fca4..561ea4075291 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardMessageArea.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardMessageArea.java
@@ -29,6 +29,7 @@ import android.util.TypedValue;
import android.view.View;
import android.widget.TextView;
+import com.android.settingslib.Utils;
import com.android.systemui.R;
import java.lang.ref.WeakReference;
@@ -69,7 +70,7 @@ public class KeyguardMessageArea extends TextView implements SecurityMessageDisp
void onThemeChanged() {
TypedArray array = mContext.obtainStyledAttributes(new int[] {
- R.attr.wallpaperTextColor
+ android.R.attr.textColor
});
ColorStateList newTextColors = ColorStateList.valueOf(array.getColor(0, Color.RED));
array.recycle();
@@ -77,6 +78,11 @@ public class KeyguardMessageArea extends TextView implements SecurityMessageDisp
update();
}
+ void reloadColor() {
+ mDefaultColorState = Utils.getColorAttr(getContext(), android.R.attr.textColorPrimary);
+ update();
+ }
+
void onDensityOrFontScaleChanged() {
TypedArray array = mContext.obtainStyledAttributes(R.style.Keyguard_TextView, new int[] {
android.R.attr.textSize
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardMessageAreaController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardMessageAreaController.java
index 1618e8e58055..6e40f025da50 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardMessageAreaController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardMessageAreaController.java
@@ -93,6 +93,13 @@ public class KeyguardMessageAreaController extends ViewController<KeyguardMessag
mView.setNextMessageColor(colorState);
}
+ /**
+ * Reload colors from resources.
+ **/
+ public void reloadColors() {
+ mView.reloadColor();
+ }
+
/** Factory for creating {@link com.android.keyguard.KeyguardMessageAreaController}. */
public static class Factory {
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java
index d34ea8c5e018..5e339172ca28 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java
@@ -16,6 +16,7 @@
package com.android.keyguard;
+import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.os.UserHandle;
import android.text.Editable;
@@ -30,12 +31,14 @@ import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodInfo;
import android.view.inputmethod.InputMethodManager;
import android.view.inputmethod.InputMethodSubtype;
-import android.widget.TextView;
+import android.widget.EditText;
+import android.widget.ImageView;
import android.widget.TextView.OnEditorActionListener;
import com.android.internal.util.LatencyTracker;
import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
+import com.android.settingslib.Utils;
import com.android.systemui.R;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.util.concurrency.DelayableExecutor;
@@ -51,8 +54,8 @@ public class KeyguardPasswordViewController
private final InputMethodManager mInputMethodManager;
private final DelayableExecutor mMainExecutor;
private final boolean mShowImeAtScreenOn;
- private TextView mPasswordEntry;
- private View mSwitchImeButton;
+ private EditText mPasswordEntry;
+ private ImageView mSwitchImeButton;
private final OnEditorActionListener mOnEditorActionListener = (v, actionId, event) -> {
// Check if this was the result of hitting the enter key
@@ -88,6 +91,18 @@ public class KeyguardPasswordViewController
}
};
+ @Override
+ public void reloadColors() {
+ super.reloadColors();
+ int textColor = Utils.getColorAttr(mView.getContext(),
+ android.R.attr.textColorPrimary).getDefaultColor();
+ mPasswordEntry.setTextColor(textColor);
+ mPasswordEntry.setHighlightColor(textColor);
+ mPasswordEntry.setBackgroundTintList(ColorStateList.valueOf(textColor));
+ mPasswordEntry.setForegroundTintList(ColorStateList.valueOf(textColor));
+ mSwitchImeButton.setImageTintList(ColorStateList.valueOf(textColor));
+ }
+
protected KeyguardPasswordViewController(KeyguardPasswordView view,
KeyguardUpdateMonitor keyguardUpdateMonitor,
SecurityMode securityMode,
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java
index 730c17787908..2aaf748e2415 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java
@@ -33,6 +33,7 @@ import com.android.internal.widget.LockPatternView.Cell;
import com.android.internal.widget.LockscreenCredential;
import com.android.keyguard.EmergencyButton.EmergencyButtonCallback;
import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
+import com.android.settingslib.Utils;
import com.android.systemui.R;
import java.util.List;
@@ -197,6 +198,7 @@ public class KeyguardPatternViewController
@Override
protected void onViewAttached() {
+ super.onViewAttached();
mLockPatternView.setOnPatternListener(new UnlockPatternListener());
mLockPatternView.setSaveEnabled(false);
mLockPatternView.setInStealthMode(!mLockPatternUtils.isVisiblePatternEnabled(
@@ -252,6 +254,16 @@ public class KeyguardPatternViewController
}
@Override
+ public void reloadColors() {
+ super.reloadColors();
+ mMessageAreaController.reloadColors();
+ int textColor = Utils.getColorAttr(mLockPatternView.getContext(),
+ android.R.attr.textColorPrimary).getDefaultColor();
+ int errorColor = Utils.getColorError(mLockPatternView.getContext()).getDefaultColor();
+ mLockPatternView.setColors(textColor, textColor, errorColor);
+ }
+
+ @Override
public void onPause() {
super.onPause();
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java
index 7fa43116a7b1..4ddfccb21c73 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java
@@ -24,12 +24,16 @@ import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_TIMEOUT;
import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_USER_REQUEST;
import android.content.Context;
+import android.content.res.ColorStateList;
import android.graphics.Rect;
import android.util.AttributeSet;
+import android.view.ContextThemeWrapper;
import android.view.KeyEvent;
import android.view.View;
+import android.widget.ImageButton;
import com.android.internal.widget.LockscreenCredential;
+import com.android.settingslib.Utils;
import com.android.systemui.R;
/**
@@ -39,8 +43,9 @@ public abstract class KeyguardPinBasedInputView extends KeyguardAbsKeyInputView
protected PasswordTextView mPasswordEntry;
private View mOkButton;
- private View mDeleteButton;
- private View[] mButtons = new View[10];
+ private ImageButton mDeleteButton;
+ private NumPadKey[] mButtons = new NumPadKey[10];
+ private View mDivider;
public KeyguardPinBasedInputView(Context context) {
this(context, null);
@@ -147,6 +152,7 @@ public abstract class KeyguardPinBasedInputView extends KeyguardAbsKeyInputView
mDeleteButton = findViewById(R.id.delete_button);
mDeleteButton.setVisibility(View.VISIBLE);
+ mDivider = findViewById(R.id.divider);
mButtons[0] = findViewById(R.id.key0);
mButtons[1] = findViewById(R.id.key1);
@@ -161,6 +167,26 @@ public abstract class KeyguardPinBasedInputView extends KeyguardAbsKeyInputView
mPasswordEntry.requestFocus();
super.onFinishInflate();
+ reloadColors();
+ }
+
+ /**
+ * Reload colors from resources.
+ **/
+ public void reloadColors() {
+ for (NumPadKey key : mButtons) {
+ key.reloadColors();
+ }
+ mPasswordEntry.reloadColors();
+ int deleteColor = Utils.getColorAttr(getContext(), android.R.attr.textColorSecondary)
+ .getDefaultColor();
+ mDeleteButton.setImageTintList(ColorStateList.valueOf(deleteColor));
+ mDivider.setBackground(getContext().getDrawable(R.drawable.pin_divider));
+
+ ContextThemeWrapper themedContext = new ContextThemeWrapper(mContext,
+ R.style.Widget_TextView_NumPadKey);
+ mDeleteButton.setBackground(themedContext.getDrawable(R.drawable.ripple_drawable_pin));
+ mOkButton.setBackground(themedContext.getDrawable(R.drawable.ripple_drawable_pin));
}
@Override
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java
index 6769436be8ef..fb0d6beca513 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java
@@ -53,6 +53,12 @@ public class KeyguardPinViewController
}
@Override
+ public void reloadColors() {
+ super.reloadColors();
+ mView.reloadColors();
+ }
+
+ @Override
void resetState() {
super.resetState();
mMessageAreaController.setMessage("");
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
index 9a511502b475..1a8d420fb394 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
@@ -47,6 +47,7 @@ import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
import com.android.keyguard.dagger.KeyguardBouncerScope;
import com.android.settingslib.utils.ThreadUtils;
import com.android.systemui.shared.system.SysUiStatsLog;
+import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.ViewController;
@@ -69,6 +70,7 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
private final KeyguardStateController mKeyguardStateController;
private final KeyguardSecurityViewFlipperController mSecurityViewFlipperController;
private final SecurityCallback mSecurityCallback;
+ private final ConfigurationController mConfigurationController;
private SecurityMode mCurrentSecurityMode = SecurityMode.Invalid;
@@ -144,6 +146,18 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
}
}
};
+ private ConfigurationController.ConfigurationListener mConfigurationListener =
+ new ConfigurationController.ConfigurationListener() {
+ @Override
+ public void onOverlayChanged() {
+ mSecurityViewFlipperController.reloadColors();
+ }
+
+ @Override
+ public void onUiModeChanged() {
+ mSecurityViewFlipperController.reloadColors();
+ }
+ };
private KeyguardSecurityContainerController(KeyguardSecurityContainer view,
AdminSecondaryLockScreenController.Factory adminSecondaryLockScreenControllerFactory,
@@ -154,7 +168,8 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
UiEventLogger uiEventLogger,
KeyguardStateController keyguardStateController,
SecurityCallback securityCallback,
- KeyguardSecurityViewFlipperController securityViewFlipperController) {
+ KeyguardSecurityViewFlipperController securityViewFlipperController,
+ ConfigurationController configurationController) {
super(view);
mLockPatternUtils = lockPatternUtils;
mUpdateMonitor = keyguardUpdateMonitor;
@@ -166,6 +181,7 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
mSecurityViewFlipperController = securityViewFlipperController;
mAdminSecondaryLockScreenController = adminSecondaryLockScreenControllerFactory.create(
mKeyguardSecurityCallback);
+ mConfigurationController = configurationController;
}
@Override
@@ -176,10 +192,12 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
@Override
protected void onViewAttached() {
mView.setSwipeListener(mSwipeListener);
+ mConfigurationController.addCallback(mConfigurationListener);
}
@Override
protected void onViewDetached() {
+ mConfigurationController.removeCallback(mConfigurationListener);
}
/** */
@@ -459,6 +477,7 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
private final UiEventLogger mUiEventLogger;
private final KeyguardStateController mKeyguardStateController;
private final KeyguardSecurityViewFlipperController mSecurityViewFlipperController;
+ private final ConfigurationController mConfigurationController;
@Inject
Factory(KeyguardSecurityContainer view,
@@ -470,7 +489,8 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
MetricsLogger metricsLogger,
UiEventLogger uiEventLogger,
KeyguardStateController keyguardStateController,
- KeyguardSecurityViewFlipperController securityViewFlipperController) {
+ KeyguardSecurityViewFlipperController securityViewFlipperController,
+ ConfigurationController configurationController) {
mView = view;
mAdminSecondaryLockScreenControllerFactory = adminSecondaryLockScreenControllerFactory;
mLockPatternUtils = lockPatternUtils;
@@ -480,6 +500,7 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
mUiEventLogger = uiEventLogger;
mKeyguardStateController = keyguardStateController;
mSecurityViewFlipperController = securityViewFlipperController;
+ mConfigurationController = configurationController;
}
public KeyguardSecurityContainerController create(
@@ -487,7 +508,8 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
return new KeyguardSecurityContainerController(mView,
mAdminSecondaryLockScreenControllerFactory, mLockPatternUtils,
mKeyguardUpdateMonitor, mKeyguardSecurityModel, mMetricsLogger, mUiEventLogger,
- mKeyguardStateController, securityCallback, mSecurityViewFlipperController);
+ mKeyguardStateController, securityCallback, mSecurityViewFlipperController,
+ mConfigurationController);
}
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipperController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipperController.java
index 49530355a6fb..f1b504e9f941 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipperController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipperController.java
@@ -71,6 +71,15 @@ public class KeyguardSecurityViewFlipperController
}
}
+ /**
+ * Reload colors of ui elements upon theme change.
+ */
+ public void reloadColors() {
+ for (KeyguardInputViewController<KeyguardInputView> child : mChildren) {
+ child.reloadColors();
+ }
+ }
+
@VisibleForTesting
KeyguardInputViewController<KeyguardInputView> getSecurityView(SecurityMode securityMode,
KeyguardSecurityCallback keyguardSecurityCallback) {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java
index 2cdd7f117594..5b4a7ff3e16e 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java
@@ -309,7 +309,7 @@ public class KeyguardSimPinViewController
Resources rez = mView.getResources();
String msg;
TypedArray array = mView.getContext().obtainStyledAttributes(
- new int[] { R.attr.wallpaperTextColor });
+ new int[] { android.R.attr.textColor });
int color = array.getColor(0, Color.WHITE);
array.recycle();
if (count < 2) {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukViewController.java
index adb4c13b74d5..eafb33f8195d 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukViewController.java
@@ -189,7 +189,7 @@ public class KeyguardSimPukViewController
Resources rez = mView.getResources();
String msg;
TypedArray array = mView.getContext().obtainStyledAttributes(
- new int[] { R.attr.wallpaperTextColor });
+ new int[] { android.R.attr.textColor });
int color = array.getColor(0, Color.WHITE);
array.recycle();
if (count < 2) {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
index a32cd1420fdc..3cbab8e66fdb 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
@@ -244,7 +244,7 @@ public class KeyguardSliceView extends LinearLayout {
iconDrawable.setBounds(0, 0, Math.max(width, 1), iconSize);
}
}
- button.setCompoundDrawables(iconDrawable, null, null, null);
+ button.setCompoundDrawablesRelative(iconDrawable, null, null, null);
button.setOnClickListener(mOnClickListener);
button.setClickable(pendingIntent != null);
}
@@ -536,9 +536,9 @@ public class KeyguardSliceView extends LinearLayout {
}
@Override
- public void setCompoundDrawables(Drawable left, Drawable top, Drawable right,
+ public void setCompoundDrawablesRelative(Drawable start, Drawable top, Drawable end,
Drawable bottom) {
- super.setCompoundDrawables(left, top, right, bottom);
+ super.setCompoundDrawablesRelative(start, top, end, bottom);
updateDrawableColors();
updatePadding();
}
@@ -558,9 +558,9 @@ public class KeyguardSliceView extends LinearLayout {
public void setLockScreenMode(int mode) {
mLockScreenMode = mode;
if (mLockScreenMode == KeyguardUpdateMonitor.LOCK_SCREEN_MODE_LAYOUT_1) {
- setGravity(Gravity.START);
+ setTextAlignment(View.TEXT_ALIGNMENT_VIEW_START);
} else {
- setGravity(Gravity.CENTER);
+ setTextAlignment(View.TEXT_ALIGNMENT_CENTER);
}
updatePadding();
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
index c0e06e87b753..bc81a198c7e6 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
@@ -193,7 +193,7 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV
/**
* Update position of the view with an optional animation
*/
- public void updatePosition(int x, int y, boolean animate) {
+ public void updatePosition(int x, int y, float scale, boolean animate) {
PropertyAnimator.setProperty(mView, AnimatableProperty.Y, y, CLOCK_ANIMATION_PROPERTIES,
animate);
@@ -202,10 +202,12 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV
PropertyAnimator.setProperty(mView, AnimatableProperty.X, 0,
CLOCK_ANIMATION_PROPERTIES, animate);
- mKeyguardClockSwitchController.updatePosition(x, CLOCK_ANIMATION_PROPERTIES, animate);
+ mKeyguardClockSwitchController.updatePosition(x, scale, CLOCK_ANIMATION_PROPERTIES,
+ animate);
} else {
// reset any prior movement
- mKeyguardClockSwitchController.updatePosition(0, CLOCK_ANIMATION_PROPERTIES, animate);
+ mKeyguardClockSwitchController.updatePosition(0, 0f, CLOCK_ANIMATION_PROPERTIES,
+ animate);
PropertyAnimator.setProperty(mView, AnimatableProperty.X, x,
CLOCK_ANIMATION_PROPERTIES, animate);
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 611131f6e216..a7e51951e9cd 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -1925,6 +1925,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
}
// TODO: Add support for multiple fingerprint sensors, b/173730729
+ updateUdfpsEnrolled(getCurrentUser());
boolean shouldListenForFingerprint =
isUdfpsEnrolled() ? shouldListenForUdfps() : shouldListenForFingerprint();
boolean runningOrRestarting = mFingerprintRunningState == BIOMETRIC_STATE_RUNNING
@@ -2137,7 +2138,6 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
}
if (DEBUG) Log.v(TAG, "startListeningForFingerprint()");
int userId = getCurrentUser();
- updateUdfpsEnrolled(userId);
if (isUnlockWithFingerprintPossible(userId)) {
if (mFingerprintCancelSignal != null) {
mFingerprintCancelSignal.cancel();
@@ -2627,7 +2627,6 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
Assert.isMainThread();
if (DEBUG) Log.d(TAG, "handleKeyguardBouncerChanged(" + bouncerVisible + ")");
mBouncer = bouncerVisible == 1;
-
if (mBouncer) {
// If the bouncer is shown, always clear this flag. This can happen in the following
// situations: 1) Default camera with SHOW_WHEN_LOCKED is not chosen yet. 2) Secure
diff --git a/packages/SystemUI/src/com/android/keyguard/NumPadKey.java b/packages/SystemUI/src/com/android/keyguard/NumPadKey.java
index 2205fdd4267d..a5182055e14d 100644
--- a/packages/SystemUI/src/com/android/keyguard/NumPadKey.java
+++ b/packages/SystemUI/src/com/android/keyguard/NumPadKey.java
@@ -18,9 +18,11 @@ package com.android.keyguard;
import android.content.Context;
import android.content.res.TypedArray;
+import android.graphics.drawable.Drawable;
import android.os.PowerManager;
import android.os.SystemClock;
import android.util.AttributeSet;
+import android.view.ContextThemeWrapper;
import android.view.HapticFeedbackConstants;
import android.view.LayoutInflater;
import android.view.MotionEvent;
@@ -30,6 +32,7 @@ import android.view.accessibility.AccessibilityManager;
import android.widget.TextView;
import com.android.internal.widget.LockPatternUtils;
+import com.android.settingslib.Utils;
import com.android.systemui.R;
public class NumPadKey extends ViewGroup {
@@ -121,12 +124,29 @@ public class NumPadKey extends ViewGroup {
a = context.obtainStyledAttributes(attrs, android.R.styleable.View);
if (!a.hasValueOrEmpty(android.R.styleable.View_background)) {
- setBackground(mContext.getDrawable(R.drawable.ripple_drawable_pin));
+ Drawable rippleDrawable = new ContextThemeWrapper(mContext,
+ R.style.Widget_TextView_NumPadKey).getDrawable(R.drawable.ripple_drawable_pin);
+ setBackground(rippleDrawable);
}
a.recycle();
setContentDescription(mDigitText.getText().toString());
}
+ /**
+ * Reload colors from resources.
+ **/
+ public void reloadColors() {
+ int textColor = Utils.getColorAttr(getContext(), android.R.attr.textColorPrimary)
+ .getDefaultColor();
+ int klondikeColor = Utils.getColorAttr(getContext(), android.R.attr.textColorSecondary)
+ .getDefaultColor();
+ mDigitText.setTextColor(textColor);
+ mKlondikeText.setTextColor(klondikeColor);
+ Drawable rippleDrawable = new ContextThemeWrapper(mContext,
+ R.style.Widget_TextView_NumPadKey).getDrawable(R.drawable.ripple_drawable_pin);
+ setBackground(rippleDrawable);
+ }
+
@Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
diff --git a/packages/SystemUI/src/com/android/keyguard/PasswordTextView.java b/packages/SystemUI/src/com/android/keyguard/PasswordTextView.java
index c92174a0d8af..5ffc2836b9e3 100644
--- a/packages/SystemUI/src/com/android/keyguard/PasswordTextView.java
+++ b/packages/SystemUI/src/com/android/keyguard/PasswordTextView.java
@@ -42,6 +42,7 @@ import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
import android.widget.EditText;
+import com.android.settingslib.Utils;
import com.android.systemui.R;
import java.util.ArrayList;
@@ -131,8 +132,8 @@ public class PasswordTextView extends View {
mCharPadding = a.getDimensionPixelSize(R.styleable.PasswordTextView_charPadding,
getContext().getResources().getDimensionPixelSize(
R.dimen.password_char_padding));
- int textColor = a.getColor(R.styleable.PasswordTextView_android_textColor, Color.WHITE);
- mDrawPaint.setColor(textColor);
+ mDrawPaint.setColor(a.getColor(R.styleable.PasswordTextView_android_textColor,
+ Color.WHITE));
} finally {
a.recycle();
}
@@ -184,6 +185,15 @@ public class PasswordTextView extends View {
}
}
+ /**
+ * Reload colors from resources.
+ **/
+ public void reloadColors() {
+ int textColor = Utils.getColorAttr(getContext(), android.R.attr.textColorPrimary)
+ .getDefaultColor();
+ mDrawPaint.setColor(textColor);
+ }
+
@Override
public boolean hasOverlappingRendering() {
return false;
diff --git a/packages/SystemUI/src/com/android/keyguard/TextInterpolator.kt b/packages/SystemUI/src/com/android/keyguard/TextInterpolator.kt
index f5e01dedfe3e..0d41a2f56618 100644
--- a/packages/SystemUI/src/com/android/keyguard/TextInterpolator.kt
+++ b/packages/SystemUI/src/com/android/keyguard/TextInterpolator.kt
@@ -19,8 +19,9 @@ import android.graphics.Canvas
import android.graphics.Paint
import android.graphics.fonts.Font
import android.graphics.text.PositionedGlyphs
-import android.graphics.text.TextRunShaper
import android.text.Layout
+import android.text.TextPaint
+import android.text.TextShaper
import android.util.MathUtils
import com.android.internal.graphics.ColorUtils
import java.lang.Math.max
@@ -57,10 +58,10 @@ class TextInterpolator(
*/
val targetPaint = createDefaultPaint(layout.paint, lines)
- private fun createDefaultPaint(paint: Paint, lines: Int): ArrayList<Paint> {
- val paintList = ArrayList<Paint>()
+ private fun createDefaultPaint(paint: TextPaint, lines: Int): ArrayList<TextPaint> {
+ val paintList = ArrayList<TextPaint>()
for (i in 0 until lines)
- paintList.add(Paint(paint))
+ paintList.add(TextPaint(paint))
return paintList
}
@@ -79,9 +80,9 @@ class TextInterpolator(
}
/**
- * A class represents text layout of a single line.
+ * A class represents text layout of a single run.
*/
- private class Line(
+ private class Run(
val glyphIds: IntArray,
val baseX: FloatArray, // same length as glyphIds
val baseY: FloatArray, // same length as glyphIds
@@ -90,11 +91,18 @@ class TextInterpolator(
val fontRuns: List<FontRun>
)
+ /**
+ * A class represents text layout of a single line.
+ */
+ private class Line(
+ val runs: List<Run>
+ )
+
private var lines = listOf<Line>()
private val fontInterpolator = FontInterpolator()
// Recycling object for glyph drawing. Will be extended for the longest font run if needed.
- private val tmpDrawPaints = ArrayList<Paint>()
+ private val tmpDrawPaints = ArrayList<TextPaint>()
private var tmpPositionArray = FloatArray(20)
/**
@@ -215,12 +223,14 @@ class TextInterpolator(
}
lines.forEach { line ->
- for (i in line.baseX.indices) {
- line.baseX[i] = MathUtils.lerp(line.baseX[i], line.targetX[i], progress)
- line.baseY[i] = MathUtils.lerp(line.baseY[i], line.targetY[i], progress)
- }
- line.fontRuns.forEach {
- it.baseFont = fontInterpolator.lerp(it.baseFont, it.targetFont, progress)
+ line.runs.forEach { run ->
+ for (i in run.baseX.indices) {
+ run.baseX[i] = MathUtils.lerp(run.baseX[i], run.targetX[i], progress)
+ run.baseY[i] = MathUtils.lerp(run.baseY[i], run.targetY[i], progress)
+ }
+ run.fontRuns.forEach {
+ it.baseFont = fontInterpolator.lerp(it.baseFont, it.targetFont, progress)
+ }
}
}
@@ -228,10 +238,10 @@ class TextInterpolator(
}
companion object {
- fun updatePaint(toUpdate: ArrayList<Paint>, newValues: ArrayList<Paint>) {
+ fun updatePaint(toUpdate: ArrayList<TextPaint>, newValues: ArrayList<TextPaint>) {
toUpdate.clear()
for (paint in newValues)
- toUpdate.add(Paint(paint))
+ toUpdate.add(TextPaint(paint))
}
}
@@ -243,20 +253,22 @@ class TextInterpolator(
fun draw(canvas: Canvas) {
lerp(basePaint, targetPaint, progress, tmpDrawPaints)
lines.forEachIndexed { lineNo, line ->
- canvas.save()
- try {
- // Move to drawing origin.
- val origin = layout.getDrawOrigin(lineNo)
- canvas.translate(origin, layout.getLineBaseline(lineNo).toFloat())
-
- line.fontRuns.forEach { run ->
- if (lineNo >= tmpDrawPaints.size)
- drawFontRun(canvas, line, run, tmpDrawPaints[0])
- else
- drawFontRun(canvas, line, run, tmpDrawPaints[lineNo])
+ line.runs.forEach { run ->
+ canvas.save()
+ try {
+ // Move to drawing origin.
+ val origin = layout.getDrawOrigin(lineNo)
+ canvas.translate(origin, layout.getLineBaseline(lineNo).toFloat())
+
+ run.fontRuns.forEach { fontRun ->
+ if (lineNo >= tmpDrawPaints.size)
+ drawFontRun(canvas, run, fontRun, tmpDrawPaints[0])
+ else
+ drawFontRun(canvas, run, fontRun, tmpDrawPaints[lineNo])
+ }
+ } finally {
+ canvas.restore()
}
- } finally {
- canvas.restore()
}
}
}
@@ -271,64 +283,68 @@ class TextInterpolator(
}
var maxRunLength = 0
- lines = baseLayout.zip(targetLayout) { base, target ->
- require(base.glyphCount() == target.glyphCount()) {
- "Inconsistent glyph count at line ${lines.size}"
- }
-
- val glyphCount = base.glyphCount()
+ lines = baseLayout.zip(targetLayout) { baseLine, targetLine ->
+ val runs = baseLine.zip(targetLine) { base, target ->
- // Good to recycle the array if the existing array can hold the new layout result.
- val glyphIds = IntArray(glyphCount) {
- base.getGlyphId(it).also { baseGlyphId ->
- require(baseGlyphId == target.getGlyphId(it)) {
- "Inconsistent glyph ID at $it in line ${lines.size}"
- }
+ require(base.glyphCount() == target.glyphCount()) {
+ "Inconsistent glyph count at line ${lines.size}"
}
- }
- val baseX = FloatArray(glyphCount) { base.getGlyphX(it) }
- val baseY = FloatArray(glyphCount) { base.getGlyphY(it) }
- val targetX = FloatArray(glyphCount) { target.getGlyphX(it) }
- val targetY = FloatArray(glyphCount) { target.getGlyphY(it) }
-
- // Calculate font runs
- val fontRun = mutableListOf<FontRun>()
- if (glyphCount != 0) {
- var start = 0
- var baseFont = base.getFont(start)
- var targetFont = target.getFont(start)
- require(FontInterpolator.canInterpolate(baseFont, targetFont)) {
- "Cannot interpolate font at $start ($baseFont vs $targetFont)"
+ val glyphCount = base.glyphCount()
+
+ // Good to recycle the array if the existing array can hold the new layout result.
+ val glyphIds = IntArray(glyphCount) {
+ base.getGlyphId(it).also { baseGlyphId ->
+ require(baseGlyphId == target.getGlyphId(it)) {
+ "Inconsistent glyph ID at $it in line ${lines.size}"
+ }
+ }
}
- for (i in 1 until glyphCount) {
- val nextBaseFont = base.getFont(i)
- val nextTargetFont = target.getFont(i)
+ val baseX = FloatArray(glyphCount) { base.getGlyphX(it) }
+ val baseY = FloatArray(glyphCount) { base.getGlyphY(it) }
+ val targetX = FloatArray(glyphCount) { target.getGlyphX(it) }
+ val targetY = FloatArray(glyphCount) { target.getGlyphY(it) }
+
+ // Calculate font runs
+ val fontRun = mutableListOf<FontRun>()
+ if (glyphCount != 0) {
+ var start = 0
+ var baseFont = base.getFont(start)
+ var targetFont = target.getFont(start)
+ require(FontInterpolator.canInterpolate(baseFont, targetFont)) {
+ "Cannot interpolate font at $start ($baseFont vs $targetFont)"
+ }
- if (baseFont !== nextBaseFont) {
- require(targetFont !== nextTargetFont) {
- "Base font has changed at $i but target font has not changed."
- }
- // Font transition point. push run and reset context.
- fontRun.add(FontRun(start, i, baseFont, targetFont))
- maxRunLength = max(maxRunLength, i - start)
- baseFont = nextBaseFont
- targetFont = nextTargetFont
- start = i
- require(FontInterpolator.canInterpolate(baseFont, targetFont)) {
- "Cannot interpolate font at $start ($baseFont vs $targetFont)"
- }
- } else { // baseFont === nextBaseFont
- require(targetFont === nextTargetFont) {
- "Base font has not changed at $i but target font has changed."
+ for (i in 1 until glyphCount) {
+ val nextBaseFont = base.getFont(i)
+ val nextTargetFont = target.getFont(i)
+
+ if (baseFont !== nextBaseFont) {
+ require(targetFont !== nextTargetFont) {
+ "Base font has changed at $i but target font has not changed."
+ }
+ // Font transition point. push run and reset context.
+ fontRun.add(FontRun(start, i, baseFont, targetFont))
+ maxRunLength = max(maxRunLength, i - start)
+ baseFont = nextBaseFont
+ targetFont = nextTargetFont
+ start = i
+ require(FontInterpolator.canInterpolate(baseFont, targetFont)) {
+ "Cannot interpolate font at $start ($baseFont vs $targetFont)"
+ }
+ } else { // baseFont === nextBaseFont
+ require(targetFont === nextTargetFont) {
+ "Base font has not changed at $i but target font has changed."
+ }
}
}
+ fontRun.add(FontRun(start, glyphCount, baseFont, targetFont))
+ maxRunLength = max(maxRunLength, glyphCount - start)
}
- fontRun.add(FontRun(start, glyphCount, baseFont, targetFont))
- maxRunLength = max(maxRunLength, glyphCount - start)
+ Run(glyphIds, baseX, baseY, targetX, targetY, fontRun)
}
- Line(glyphIds, baseX, baseY, targetX, targetY, fontRun)
+ Line(runs)
}
// Update float array used for drawing.
@@ -338,7 +354,7 @@ class TextInterpolator(
}
// Draws single font run.
- private fun drawFontRun(c: Canvas, line: Line, run: FontRun, paint: Paint) {
+ private fun drawFontRun(c: Canvas, line: Run, run: FontRun, paint: Paint) {
var arrayIndex = 0
for (i in run.start until run.end) {
tmpPositionArray[arrayIndex++] =
@@ -358,7 +374,7 @@ class TextInterpolator(
}
private fun updatePositionsAndFonts(
- layoutResult: List<PositionedGlyphs>,
+ layoutResult: List<List<PositionedGlyphs>>,
updateBase: Boolean
) {
// Update target positions with newly calculated text layout.
@@ -366,45 +382,48 @@ class TextInterpolator(
"The new layout result has different line count."
}
- lines.zip(layoutResult) { line, newGlyphs ->
- require(newGlyphs.glyphCount() == line.glyphIds.size) {
- "The new layout has different glyph count."
- }
+ lines.zip(layoutResult) { line, runs ->
+ line.runs.zip(runs) { lineRun, newGlyphs ->
+ require(newGlyphs.glyphCount() == lineRun.glyphIds.size) {
+ "The new layout has different glyph count."
+ }
- line.fontRuns.forEach { run ->
- val newFont = newGlyphs.getFont(run.start)
- for (i in run.start until run.end) {
- require(newGlyphs.getGlyphId(run.start) == line.glyphIds[run.start]) {
- "The new layout has different glyph ID at ${run.start}"
+ lineRun.fontRuns.forEach { run ->
+ val newFont = newGlyphs.getFont(run.start)
+ for (i in run.start until run.end) {
+ require(newGlyphs.getGlyphId(run.start) == lineRun.glyphIds[run.start]) {
+ "The new layout has different glyph ID at ${run.start}"
+ }
+ require(newFont === newGlyphs.getFont(i)) {
+ "The new layout has different font run." +
+ " $newFont vs ${newGlyphs.getFont(i)} at $i"
+ }
}
- require(newFont === newGlyphs.getFont(i)) {
- "The new layout has different font run." +
- " $newFont vs ${newGlyphs.getFont(i)} at $i"
+
+ // The passing base font and target font is already interpolatable, so just
+ // check new font can be interpolatable with base font.
+ require(FontInterpolator.canInterpolate(newFont, run.baseFont)) {
+ "New font cannot be interpolated with existing font. $newFont," +
+ " ${run.baseFont}"
}
- }
- // The passing base font and target font is already interpolatable, so just check
- // new font can be interpolatable with base font.
- require(FontInterpolator.canInterpolate(newFont, run.baseFont)) {
- "New font cannot be interpolated with existing font. $newFont, ${run.baseFont}"
+ if (updateBase) {
+ run.baseFont = newFont
+ } else {
+ run.targetFont = newFont
+ }
}
if (updateBase) {
- run.baseFont = newFont
+ for (i in lineRun.baseX.indices) {
+ lineRun.baseX[i] = newGlyphs.getGlyphX(i)
+ lineRun.baseY[i] = newGlyphs.getGlyphY(i)
+ }
} else {
- run.targetFont = newFont
- }
- }
-
- if (updateBase) {
- for (i in line.baseX.indices) {
- line.baseX[i] = newGlyphs.getGlyphX(i)
- line.baseY[i] = newGlyphs.getGlyphY(i)
- }
- } else {
- for (i in line.baseX.indices) {
- line.targetX[i] = newGlyphs.getGlyphX(i)
- line.targetY[i] = newGlyphs.getGlyphY(i)
+ for (i in lineRun.baseX.indices) {
+ lineRun.targetX[i] = newGlyphs.getGlyphX(i)
+ lineRun.targetY[i] = newGlyphs.getGlyphY(i)
+ }
}
}
}
@@ -412,16 +431,16 @@ class TextInterpolator(
// Linear interpolate the paint.
private fun lerp(
- from: ArrayList<Paint>,
- to: ArrayList<Paint>,
+ from: ArrayList<TextPaint>,
+ to: ArrayList<TextPaint>,
progress: Float,
- out: ArrayList<Paint>
+ out: ArrayList<TextPaint>
) {
out.clear()
// Currently only font size & colors are interpolated.
// TODO(172943390): Add other interpolation or support custom interpolator.
for (index in from.indices) {
- val paint = Paint(from[index])
+ val paint = TextPaint(from[index])
paint.textSize = MathUtils.lerp(from[index].textSize, to[index].textSize, progress)
paint.color = ColorUtils.blendARGB(from[index].color, to[index].color, progress)
out.add(paint)
@@ -429,18 +448,20 @@ class TextInterpolator(
}
// Shape the text and stores the result to out argument.
- private fun shapeText(layout: Layout, paints: ArrayList<Paint>): List<PositionedGlyphs> {
- val out = mutableListOf<PositionedGlyphs>()
+ private fun shapeText(
+ layout: Layout,
+ paints: ArrayList<TextPaint>
+ ): List<List<PositionedGlyphs>> {
+ val out = mutableListOf<List<PositionedGlyphs>>()
for (lineNo in 0 until layout.lineCount) { // Shape all lines.
val lineStart = layout.getLineStart(lineNo)
val count = layout.getLineEnd(lineNo) - lineStart
- out.add(TextRunShaper.shapeTextRun(
- layout.text, // Styles are ignored.
- lineStart, count, // shape range
- lineStart, count, // shape context = shape range.
- 0f, 0f, // the layout offset. Not changed.
- layout.getParagraphDirection(lineNo) == Layout.DIR_RIGHT_TO_LEFT,
- paints[lineNo])) // Use given paint instead of layout's for style interpolation.
+ val runs = mutableListOf<PositionedGlyphs>()
+ TextShaper.shapeText(layout.text, lineStart, count, layout.textDirectionHeuristic,
+ paints[lineNo]) { _, _, glyphs, _ ->
+ runs.add(glyphs)
+ }
+ out.add(runs)
}
return out
}
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
index 8e5e9ea257ba..6b4e8bdef72a 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
@@ -113,8 +113,10 @@ public class SystemUIFactory {
.setShellCommandHandler(mWMComponent.getShellCommandHandler())
.setAppPairs(mWMComponent.getAppPairs());
} else {
- // TODO: Call on prepareSysUIComponentBuilder but not with real components.
- builder = builder.setPip(Optional.ofNullable(null))
+ // TODO: Call on prepareSysUIComponentBuilder but not with real components. Other option
+ // is separating this logic into newly creating SystemUITestsFactory.
+ builder = prepareSysUIComponentBuilder(builder, mWMComponent)
+ .setPip(Optional.ofNullable(null))
.setSplitScreen(Optional.ofNullable(null))
.setOneHanded(Optional.ofNullable(null))
.setBubbles(Optional.ofNullable(null))
@@ -194,4 +196,4 @@ public class SystemUIFactory {
AssetManager am, String modelName) {
return new BackGestureTfClassifierProvider();
}
-} \ No newline at end of file
+}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
index dc841d91b1ab..9edfee73936e 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
@@ -22,6 +22,7 @@ import static android.hardware.biometrics.BiometricManager.Authenticators;
import android.annotation.Nullable;
import android.app.ActivityManager;
+import android.app.ActivityTaskManager;
import android.app.IActivityTaskManager;
import android.app.TaskStackListener;
import android.content.BroadcastReceiver;
@@ -74,7 +75,7 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks,
private final CommandQueue mCommandQueue;
private final StatusBarStateController mStatusBarStateController;
- private final IActivityTaskManager mActivityTaskManager;
+ private final ActivityTaskManager mActivityTaskManager;
@Nullable private final FingerprintManager mFingerprintManager;
@Nullable private final FaceManager mFaceManager;
private final Provider<UdfpsController> mUdfpsControllerFactory;
@@ -313,7 +314,7 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks,
@Inject
public AuthController(Context context, CommandQueue commandQueue,
StatusBarStateController statusBarStateController,
- IActivityTaskManager activityTaskManager,
+ ActivityTaskManager activityTaskManager,
@Nullable FingerprintManager fingerprintManager,
@Nullable FaceManager faceManager,
Provider<UdfpsController> udfpsControllerFactory) {
@@ -356,12 +357,8 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks,
mUdfpsController = mUdfpsControllerFactory.get();
}
- try {
- mTaskStackListener = new BiometricTaskStackListener();
- mActivityTaskManager.registerTaskStackListener(mTaskStackListener);
- } catch (RemoteException e) {
- Log.w(TAG, "Unable to register task stack listener", e);
- }
+ mTaskStackListener = new BiometricTaskStackListener();
+ mActivityTaskManager.registerTaskStackListener(mTaskStackListener);
}
@Override
@@ -413,6 +410,11 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks,
mCurrentDialog.onHelp(message);
}
+ @Nullable
+ public List<FingerprintSensorPropertiesInternal> getUdfpsProps() {
+ return mUdfpsProps;
+ }
+
private String getErrorString(int modality, int error, int vendorCode) {
switch (modality) {
case TYPE_FACE:
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/brightline/BrightLineFalsingManager.java b/packages/SystemUI/src/com/android/systemui/classifier/BrightLineFalsingManager.java
index f6b8b4c92049..e24a513437ea 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/brightline/BrightLineFalsingManager.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/BrightLineFalsingManager.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,44 +14,39 @@
* limitations under the License.
*/
-package com.android.systemui.classifier.brightline;
+package com.android.systemui.classifier;
import static com.android.systemui.classifier.FalsingManagerProxy.FALSING_SUCCESS;
+import static com.android.systemui.classifier.FalsingModule.BRIGHT_LINE_GESTURE_CLASSIFERS;
-import android.app.ActivityManager;
-import android.content.res.Resources;
import android.net.Uri;
import android.os.Build;
import android.util.IndentingPrintWriter;
import android.util.Log;
import android.view.MotionEvent;
-import android.view.ViewConfiguration;
import androidx.annotation.NonNull;
import com.android.internal.logging.MetricsLogger;
-import com.android.systemui.R;
-import com.android.systemui.classifier.Classifier;
-import com.android.systemui.classifier.FalsingDataProvider;
import com.android.systemui.classifier.FalsingDataProvider.SessionListener;
-import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.dagger.qualifiers.TestHarness;
import com.android.systemui.dock.DockManager;
import com.android.systemui.plugins.FalsingManager;
-import com.android.systemui.statusbar.phone.NotificationTapHelper;
-import com.android.systemui.util.DeviceConfigProxy;
import com.android.systemui.util.sensors.ThresholdSensor;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayDeque;
-import java.util.ArrayList;
+import java.util.Collection;
import java.util.List;
import java.util.Locale;
import java.util.Queue;
+import java.util.Set;
import java.util.StringJoiner;
import java.util.stream.Collectors;
import javax.inject.Inject;
+import javax.inject.Named;
/**
* FalsingManager designed to make clear why a touch was rejected.
@@ -68,6 +63,7 @@ public class BrightLineFalsingManager implements FalsingManager {
private final DockManager mDockManager;
private final SingleTapClassifier mSingleTapClassifier;
private final DoubleTapClassifier mDoubleTapClassifier;
+ private final boolean mTestHarness;
private final MetricsLogger mMetricsLogger;
private int mIsFalseTouchCalls;
private static final Queue<String> RECENT_INFO_LOG =
@@ -75,7 +71,7 @@ public class BrightLineFalsingManager implements FalsingManager {
private static final Queue<DebugSwipeRecord> RECENT_SWIPES =
new ArrayDeque<>(RECENT_SWIPE_LOG_SIZE + 1);
- private final List<FalsingClassifier> mClassifiers;
+ private final Collection<FalsingClassifier> mClassifiers;
private final SessionListener mSessionListener = new SessionListener() {
@Override
@@ -93,29 +89,17 @@ public class BrightLineFalsingManager implements FalsingManager {
@Inject
public BrightLineFalsingManager(FalsingDataProvider falsingDataProvider,
- DeviceConfigProxy deviceConfigProxy, @Main Resources resources,
- ViewConfiguration viewConfiguration, DockManager dockManager) {
+ DockManager dockManager, MetricsLogger metricsLogger,
+ @Named(BRIGHT_LINE_GESTURE_CLASSIFERS) Set<FalsingClassifier> classifiers,
+ SingleTapClassifier singleTapClassifier, DoubleTapClassifier doubleTapClassifier,
+ @TestHarness boolean testHarness) {
mDataProvider = falsingDataProvider;
mDockManager = dockManager;
-
- mMetricsLogger = new MetricsLogger();
- mClassifiers = new ArrayList<>();
- DistanceClassifier distanceClassifier =
- new DistanceClassifier(mDataProvider, deviceConfigProxy);
- ProximityClassifier proximityClassifier =
- new ProximityClassifier(distanceClassifier, mDataProvider, deviceConfigProxy);
- mClassifiers.add(new PointerCountClassifier(mDataProvider));
- mClassifiers.add(new TypeClassifier(mDataProvider));
- mClassifiers.add(new DiagonalClassifier(mDataProvider, deviceConfigProxy));
- mClassifiers.add(distanceClassifier);
- mClassifiers.add(proximityClassifier);
- mClassifiers.add(new ZigZagClassifier(mDataProvider, deviceConfigProxy));
-
- mSingleTapClassifier = new SingleTapClassifier(
- mDataProvider, viewConfiguration.getScaledTouchSlop());
- mDoubleTapClassifier = new DoubleTapClassifier(mDataProvider, mSingleTapClassifier,
- resources.getDimension(R.dimen.double_tap_slop),
- NotificationTapHelper.DOUBLE_TAP_TIMEOUT_MS);
+ mMetricsLogger = metricsLogger;
+ mClassifiers = classifiers;
+ mSingleTapClassifier = singleTapClassifier;
+ mDoubleTapClassifier = doubleTapClassifier;
+ mTestHarness = testHarness;
mDataProvider.addSessionListener(mSessionListener);
}
@@ -132,7 +116,7 @@ public class BrightLineFalsingManager implements FalsingManager {
return mPreviousResult;
}
- mPreviousResult = !ActivityManager.isRunningInUserTestHarness()
+ mPreviousResult = !mTestHarness
&& !mDataProvider.isJustUnlockedWithFace() && !mDockManager.isDocked()
&& mClassifiers.stream().anyMatch(falsingClassifier -> {
boolean result = falsingClassifier.isFalseTouch();
@@ -185,8 +169,12 @@ public class BrightLineFalsingManager implements FalsingManager {
return true;
}
- // TODO(b/172655679): we always reject single-taps when doing a robust check for now.
- return robustCheck;
+ // TODO(b/172655679): More heuristics to come. For now, allow touches through if face-authed
+ if (robustCheck) {
+ return !mDataProvider.isJustUnlockedWithFace();
+ }
+
+ return false;
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/brightline/DiagonalClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/DiagonalClassifier.java
index a73ccf575249..92dd8b74e959 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/brightline/DiagonalClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/DiagonalClassifier.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.classifier.brightline;
+package com.android.systemui.classifier;
import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.BRIGHTLINE_FALSING_DIAGONAL_HORIZONTAL_ANGLE_RANGE;
import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.BRIGHTLINE_FALSING_DIAGONAL_VERTICAL_ANGLE_RANGE;
@@ -23,11 +23,12 @@ import static com.android.systemui.classifier.Classifier.RIGHT_AFFORDANCE;
import android.provider.DeviceConfig;
-import com.android.systemui.classifier.FalsingDataProvider;
import com.android.systemui.util.DeviceConfigProxy;
import java.util.Locale;
+import javax.inject.Inject;
+
/**
* False on swipes that are too close to 45 degrees.
*
@@ -47,6 +48,7 @@ class DiagonalClassifier extends FalsingClassifier {
private final float mHorizontalAngleRange;
private final float mVerticalAngleRange;
+ @Inject
DiagonalClassifier(FalsingDataProvider dataProvider, DeviceConfigProxy deviceConfigProxy) {
super(dataProvider);
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/brightline/DistanceClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/DistanceClassifier.java
index 524d524f38b6..50d55f6f6028 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/brightline/DistanceClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/DistanceClassifier.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.classifier.brightline;
+package com.android.systemui.classifier;
import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.BRIGHTLINE_FALSING_DISTANCE_HORIZONTAL_FLING_THRESHOLD_IN;
import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.BRIGHTLINE_FALSING_DISTANCE_HORIZONTAL_SWIPE_THRESHOLD_IN;
@@ -27,12 +27,13 @@ import android.provider.DeviceConfig;
import android.view.MotionEvent;
import android.view.VelocityTracker;
-import com.android.systemui.classifier.FalsingDataProvider;
import com.android.systemui.util.DeviceConfigProxy;
import java.util.List;
import java.util.Locale;
+import javax.inject.Inject;
+
/**
* Ensure that the swipe + momentum covers a minimum distance.
*/
@@ -54,6 +55,7 @@ class DistanceClassifier extends FalsingClassifier {
private boolean mDistanceDirty;
private DistanceVectors mCachedDistance;
+ @Inject
DistanceClassifier(FalsingDataProvider dataProvider, DeviceConfigProxy deviceConfigProxy) {
super(dataProvider);
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/brightline/DoubleTapClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/DoubleTapClassifier.java
index a27ea6172414..1c8f4208edba 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/brightline/DoubleTapClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/DoubleTapClassifier.java
@@ -14,15 +14,19 @@
* limitations under the License.
*/
-package com.android.systemui.classifier.brightline;
+package com.android.systemui.classifier;
-import android.view.MotionEvent;
+import static com.android.systemui.classifier.FalsingModule.DOUBLE_TAP_TIMEOUT_MS;
+import static com.android.systemui.classifier.FalsingModule.DOUBLE_TAP_TOUCH_SLOP;
-import com.android.systemui.classifier.FalsingDataProvider;
+import android.view.MotionEvent;
import java.util.List;
import java.util.Queue;
+import javax.inject.Inject;
+import javax.inject.Named;
+
/**
* Returns a false touch if the most two recent gestures are not taps or are too far apart.
*/
@@ -34,8 +38,10 @@ public class DoubleTapClassifier extends FalsingClassifier {
private StringBuilder mReason = new StringBuilder();
+ @Inject
DoubleTapClassifier(FalsingDataProvider dataProvider, SingleTapClassifier singleTapClassifier,
- float doubleTapSlop, long doubleTapTimeMs) {
+ @Named(DOUBLE_TAP_TOUCH_SLOP) float doubleTapSlop,
+ @Named(DOUBLE_TAP_TIMEOUT_MS) long doubleTapTimeMs) {
super(dataProvider);
mSingleTapClassifier = singleTapClassifier;
mDoubleTapSlop = doubleTapSlop;
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/brightline/FalsingClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingClassifier.java
index 568dc432729f..82575c3e639e 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/brightline/FalsingClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingClassifier.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,12 +14,10 @@
* limitations under the License.
*/
-package com.android.systemui.classifier.brightline;
+package com.android.systemui.classifier;
import android.view.MotionEvent;
-import com.android.systemui.classifier.Classifier;
-import com.android.systemui.classifier.FalsingDataProvider;
import com.android.systemui.util.sensors.ProximitySensor;
import java.util.List;
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingDataProvider.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingDataProvider.java
index b29871c1c3d0..009b311f2363 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingDataProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingDataProvider.java
@@ -21,9 +21,6 @@ import android.view.MotionEvent;
import android.view.MotionEvent.PointerCoords;
import android.view.MotionEvent.PointerProperties;
-import com.android.systemui.classifier.brightline.BrightLineFalsingManager;
-import com.android.systemui.classifier.brightline.FalsingClassifier;
-import com.android.systemui.classifier.brightline.TimeLimitedMotionEventBuffer;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.util.time.SystemClock;
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java
index 74629411c13d..d4f58c324d39 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java
@@ -24,7 +24,6 @@ import android.view.MotionEvent;
import androidx.annotation.NonNull;
import com.android.systemui.Dumpable;
-import com.android.systemui.classifier.brightline.BrightLineFalsingManager;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dump.DumpManager;
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingModule.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingModule.java
index 937bcbaa6222..7b7f17e1568b 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingModule.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingModule.java
@@ -16,16 +16,69 @@
package com.android.systemui.classifier;
+import android.content.res.Resources;
+import android.view.ViewConfiguration;
+
+import com.android.systemui.R;
import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.statusbar.phone.NotificationTapHelper;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.inject.Named;
import dagger.Binds;
import dagger.Module;
+import dagger.Provides;
+import dagger.multibindings.ElementsIntoSet;
/** Dagger Module for Falsing. */
@Module
public interface FalsingModule {
+ String BRIGHT_LINE_GESTURE_CLASSIFERS = "bright_line_gesture_classifiers";
+ String SINGLE_TAP_TOUCH_SLOP = "falsing_single_tap_touch_slop";
+ String DOUBLE_TAP_TOUCH_SLOP = "falsing_double_tap_touch_slop";
+ String DOUBLE_TAP_TIMEOUT_MS = "falsing_double_tap_timeout_ms";
+
/** */
@Binds
@SysUISingleton
FalsingCollector bindsFalsingCollector(FalsingCollectorImpl impl);
+
+ /** */
+ @Provides
+ @ElementsIntoSet
+ @Named(BRIGHT_LINE_GESTURE_CLASSIFERS)
+ static Set<FalsingClassifier> providesBrightLineGestureClassifiers(
+ DistanceClassifier distanceClassifier, ProximityClassifier proximityClassifier,
+ PointerCountClassifier pointerCountClassifier, TypeClassifier typeClassifier,
+ DiagonalClassifier diagonalClassifier, ZigZagClassifier zigZagClassifier) {
+ return new HashSet<>(Arrays.asList(
+ pointerCountClassifier, typeClassifier, diagonalClassifier, distanceClassifier,
+ proximityClassifier, zigZagClassifier));
+ }
+
+ /** */
+ @Provides
+ @Named(DOUBLE_TAP_TIMEOUT_MS)
+ static long providesDoubleTapTimeoutMs() {
+ return NotificationTapHelper.DOUBLE_TAP_TIMEOUT_MS;
+ }
+
+ /** */
+ @Provides
+ @Named(DOUBLE_TAP_TOUCH_SLOP)
+ static float providesDoubleTapTouchSlop(@Main Resources resources) {
+ return resources.getDimension(R.dimen.double_tap_slop);
+ }
+
+ /** */
+ @Provides
+ @Named(SINGLE_TAP_TOUCH_SLOP)
+ static float providesSingleTapTouchSlop(ViewConfiguration viewConfiguration) {
+ return viewConfiguration.getScaledTouchSlop();
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/brightline/PointerCountClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/PointerCountClassifier.java
index dd5d8a8f557b..0565165e1e8d 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/brightline/PointerCountClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/PointerCountClassifier.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,17 +14,17 @@
* limitations under the License.
*/
-package com.android.systemui.classifier.brightline;
+package com.android.systemui.classifier;
import static com.android.systemui.classifier.Classifier.NOTIFICATION_DRAG_DOWN;
import static com.android.systemui.classifier.Classifier.QUICK_SETTINGS;
import android.view.MotionEvent;
-import com.android.systemui.classifier.FalsingDataProvider;
-
import java.util.Locale;
+import javax.inject.Inject;
+
/**
* False touch if more than one finger touches the screen.
*
@@ -37,6 +37,7 @@ class PointerCountClassifier extends FalsingClassifier {
private static final int MAX_ALLOWED_POINTERS_SWIPE_DOWN = 2;
private int mMaxPointerCount;
+ @Inject
PointerCountClassifier(FalsingDataProvider dataProvider) {
super(dataProvider);
}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/brightline/ProximityClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/ProximityClassifier.java
index 3551c241e71e..6e73fc06de4c 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/brightline/ProximityClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/ProximityClassifier.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.classifier.brightline;
+package com.android.systemui.classifier;
import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.BRIGHTLINE_FALSING_PROXIMITY_PERCENT_COVERED_THRESHOLD;
import static com.android.systemui.classifier.Classifier.QUICK_SETTINGS;
@@ -22,12 +22,13 @@ import static com.android.systemui.classifier.Classifier.QUICK_SETTINGS;
import android.provider.DeviceConfig;
import android.view.MotionEvent;
-import com.android.systemui.classifier.FalsingDataProvider;
import com.android.systemui.util.DeviceConfigProxy;
import com.android.systemui.util.sensors.ProximitySensor;
import java.util.Locale;
+import javax.inject.Inject;
+
/**
* False touch if proximity sensor is covered for more than a certain percentage of the gesture.
@@ -47,10 +48,11 @@ class ProximityClassifier extends FalsingClassifier {
private long mNearDurationNs;
private float mPercentNear;
+ @Inject
ProximityClassifier(DistanceClassifier distanceClassifier,
FalsingDataProvider dataProvider, DeviceConfigProxy deviceConfigProxy) {
super(dataProvider);
- this.mDistanceClassifier = distanceClassifier;
+ mDistanceClassifier = distanceClassifier;
mPercentCoveredThreshold = deviceConfigProxy.getFloat(
DeviceConfig.NAMESPACE_SYSTEMUI,
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/brightline/SingleTapClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/SingleTapClassifier.java
index 8c7648149e44..6b7a1413bc74 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/brightline/SingleTapClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/SingleTapClassifier.java
@@ -14,14 +14,17 @@
* limitations under the License.
*/
-package com.android.systemui.classifier.brightline;
+package com.android.systemui.classifier;
-import android.view.MotionEvent;
+import static com.android.systemui.classifier.FalsingModule.SINGLE_TAP_TOUCH_SLOP;
-import com.android.systemui.classifier.FalsingDataProvider;
+import android.view.MotionEvent;
import java.util.List;
+import javax.inject.Inject;
+import javax.inject.Named;
+
/**
* Falsing classifier that accepts or rejects a single gesture as a tap.
*/
@@ -29,7 +32,9 @@ public class SingleTapClassifier extends FalsingClassifier {
private final float mTouchSlop;
private String mReason;
- SingleTapClassifier(FalsingDataProvider dataProvider, float touchSlop) {
+ @Inject
+ SingleTapClassifier(FalsingDataProvider dataProvider,
+ @Named(SINGLE_TAP_TOUCH_SLOP) float touchSlop) {
super(dataProvider);
mTouchSlop = touchSlop;
}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/brightline/TimeLimitedMotionEventBuffer.java b/packages/SystemUI/src/com/android/systemui/classifier/TimeLimitedMotionEventBuffer.java
index 7430a1eda920..7969b4e83ac0 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/brightline/TimeLimitedMotionEventBuffer.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/TimeLimitedMotionEventBuffer.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.classifier.brightline;
+package com.android.systemui.classifier;
import android.view.MotionEvent;
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/brightline/TypeClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/TypeClassifier.java
index f62871f383b3..711a0fc0f478 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/brightline/TypeClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/TypeClassifier.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.classifier.brightline;
+package com.android.systemui.classifier;
import static com.android.systemui.classifier.Classifier.BOUNCER_UNLOCK;
@@ -26,12 +26,13 @@ import static com.android.systemui.classifier.Classifier.QUICK_SETTINGS;
import static com.android.systemui.classifier.Classifier.RIGHT_AFFORDANCE;
import static com.android.systemui.classifier.Classifier.UNLOCK;
-import com.android.systemui.classifier.FalsingDataProvider;
+import javax.inject.Inject;
/**
* Ensure that the swipe direction generally matches that of the interaction type.
*/
public class TypeClassifier extends FalsingClassifier {
+ @Inject
TypeClassifier(FalsingDataProvider dataProvider) {
super(dataProvider);
}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/brightline/ZigZagClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/ZigZagClassifier.java
index 9ca77d364bc4..383dda498b49 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/brightline/ZigZagClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/ZigZagClassifier.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.classifier.brightline;
+package com.android.systemui.classifier;
import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.BRIGHTLINE_FALSING_ZIGZAG_X_PRIMARY_DEVIANCE;
import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.BRIGHTLINE_FALSING_ZIGZAG_X_SECONDARY_DEVIANCE;
@@ -25,13 +25,14 @@ import android.graphics.Point;
import android.provider.DeviceConfig;
import android.view.MotionEvent;
-import com.android.systemui.classifier.FalsingDataProvider;
import com.android.systemui.util.DeviceConfigProxy;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
+import javax.inject.Inject;
+
/**
* Penalizes gestures that change direction in either the x or y too much.
*/
@@ -56,6 +57,7 @@ class ZigZagClassifier extends FalsingClassifier {
private float mLastMaxXDeviance;
private float mLastMaxYDeviance;
+ @Inject
ZigZagClassifier(FalsingDataProvider dataProvider, DeviceConfigProxy deviceConfigProxy) {
super(dataProvider);
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java b/packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java
index 13ff3f5c4e6c..ec4a91c24464 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java
@@ -22,6 +22,7 @@ import com.android.systemui.ForegroundServicesDialog;
import com.android.systemui.keyguard.WorkLockActivity;
import com.android.systemui.screenrecord.ScreenRecordDialog;
import com.android.systemui.settings.brightness.BrightnessDialog;
+import com.android.systemui.statusbar.tv.notifications.TvNotificationPanelActivity;
import com.android.systemui.tuner.TunerActivity;
import com.android.systemui.usb.UsbDebuggingActivity;
import com.android.systemui.usb.UsbDebuggingSecondaryUserActivity;
@@ -85,4 +86,10 @@ public abstract class DefaultActivityBinder {
@IntoMap
@ClassKey(CreateUserActivity.class)
public abstract Activity bindCreateUserActivity(CreateUserActivity activity);
+
+ /** Inject into TvNotificationPanelActivity. */
+ @Binds
+ @IntoMap
+ @ClassKey(TvNotificationPanelActivity.class)
+ public abstract Activity bindTvNotificationPanelActivity(TvNotificationPanelActivity activity);
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
index 7127f26a7ed2..275bfaa1023c 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
@@ -30,7 +30,6 @@ import android.os.HandlerThread;
import android.os.Looper;
import android.os.ServiceManager;
import android.os.UserHandle;
-import android.util.DisplayMetrics;
import android.view.Choreographer;
import android.view.IWindowManager;
import android.view.LayoutInflater;
@@ -141,16 +140,6 @@ public class DependencyProvider {
return networkController.getDataSaverController();
}
- /** */
- @Provides
- @SysUISingleton
- public DisplayMetrics provideDisplayMetrics(Context context, WindowManager windowManager) {
- DisplayMetrics displayMetrics = new DisplayMetrics();
- context.getDisplay().getMetrics(displayMetrics);
- return displayMetrics;
- }
-
- /** */
@Provides
@SysUISingleton
public INotificationManager provideINotificationManager() {
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java b/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java
index c3f2e1848abd..2c06c7b96831 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java
@@ -151,6 +151,12 @@ public class FrameworkServicesModule {
@Provides
@Singleton
+ static ActivityTaskManager provideActivityTaskManager() {
+ return ActivityTaskManager.getInstance();
+ }
+
+ @Provides
+ @Singleton
static IActivityTaskManager provideIActivityTaskManager() {
return ActivityTaskManager.getService();
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/GlobalModule.java b/packages/SystemUI/src/com/android/systemui/dagger/GlobalModule.java
index 53383d65e379..a89c7acea984 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/GlobalModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/GlobalModule.java
@@ -16,13 +16,14 @@
package com.android.systemui.dagger;
+import android.app.ActivityManager;
import android.content.Context;
import android.util.DisplayMetrics;
import com.android.internal.logging.UiEventLogger;
import com.android.internal.logging.UiEventLoggerImpl;
+import com.android.systemui.dagger.qualifiers.TestHarness;
import com.android.systemui.util.concurrency.GlobalConcurrencyModule;
-import com.android.wm.shell.animation.FlingAnimationUtils;
import javax.inject.Singleton;
@@ -49,15 +50,12 @@ import dagger.Provides;
GlobalConcurrencyModule.class})
public class GlobalModule {
- // TODO(b/162923491): This should not be a singleton at all, the display metrics can change and
- // callers should be creating a new builder on demand
- @Singleton
+ /** */
@Provides
- static FlingAnimationUtils.Builder provideFlingAnimationUtilsBuilder(
- Context context) {
+ public DisplayMetrics provideDisplayMetrics(Context context) {
DisplayMetrics displayMetrics = new DisplayMetrics();
context.getDisplay().getMetrics(displayMetrics);
- return new FlingAnimationUtils.Builder(displayMetrics);
+ return displayMetrics;
}
/** Provides an instance of {@link com.android.internal.logging.UiEventLogger} */
@@ -66,4 +64,10 @@ public class GlobalModule {
static UiEventLogger provideUiEventLogger() {
return new UiEventLoggerImpl();
}
+
+ @Provides
+ @TestHarness
+ static boolean provideIsTestHarness() {
+ return ActivityManager.isRunningInUserTestHarness();
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java
index c0013d8cb981..9f6c19bdf06f 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java
@@ -34,8 +34,8 @@ import com.android.systemui.shortcut.ShortcutKeyDispatcher;
import com.android.systemui.statusbar.dagger.StatusBarModule;
import com.android.systemui.statusbar.notification.InstantAppNotifier;
import com.android.systemui.statusbar.phone.StatusBar;
-import com.android.systemui.statusbar.tv.TvNotificationPanel;
import com.android.systemui.statusbar.tv.TvStatusBar;
+import com.android.systemui.statusbar.tv.notifications.TvNotificationPanel;
import com.android.systemui.theme.ThemeOverlayController;
import com.android.systemui.toast.ToastUI;
import com.android.systemui.util.leak.GarbageMonitor;
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/qualifiers/TestHarness.java b/packages/SystemUI/src/com/android/systemui/dagger/qualifiers/TestHarness.java
new file mode 100644
index 000000000000..f68ab188c93c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/dagger/qualifiers/TestHarness.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.dagger.qualifiers;
+
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+
+import javax.inject.Qualifier;
+
+
+/**
+ * An annotation for injecting whether or not we are running in a test environment.
+ */
+@Qualifier
+@Documented
+@Retention(RUNTIME)
+public @interface TestHarness {
+}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/util/BurnInHelper.kt b/packages/SystemUI/src/com/android/systemui/doze/util/BurnInHelper.kt
index d1e5059756ed..73abf4519f73 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/util/BurnInHelper.kt
+++ b/packages/SystemUI/src/com/android/systemui/doze/util/BurnInHelper.kt
@@ -21,6 +21,7 @@ import android.util.MathUtils
private const val MILLIS_PER_MINUTES = 1000 * 60f
private const val BURN_IN_PREVENTION_PERIOD_Y = 521f
private const val BURN_IN_PREVENTION_PERIOD_X = 83f
+private const val BURN_IN_PREVENTION_PERIOD_SCALE = 180f
/**
* Returns the translation offset that should be used to avoid burn in at
@@ -36,6 +37,14 @@ fun getBurnInOffset(amplitude: Int, xAxis: Boolean): Int {
}
/**
+ * Returns a value to scale a view in order to avoid burn in.
+ */
+fun getBurnInScale(): Float {
+ return 0.8f + zigzag(System.currentTimeMillis() / MILLIS_PER_MINUTES,
+ 0.2f, BURN_IN_PREVENTION_PERIOD_SCALE)
+}
+
+/**
* Implements a continuous, piecewise linear, periodic zig-zag function
*
* Can be thought of as a linear approximation of abs(sin(x)))
diff --git a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.java b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.java
index 3295595955eb..5cd3b33a1b5f 100644
--- a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.java
@@ -19,10 +19,10 @@ package com.android.systemui.people;
import android.app.Activity;
import android.app.INotificationManager;
import android.app.people.IPeopleManager;
+import android.app.people.PeopleSpaceTile;
import android.content.Context;
import android.content.pm.LauncherApps;
import android.content.pm.PackageManager;
-import android.content.pm.ShortcutInfo;
import android.os.Bundle;
import android.os.ServiceManager;
import android.util.Log;
@@ -68,13 +68,13 @@ public class PeopleSpaceActivity extends Activity {
*/
private void setTileViewsWithPriorityConversations() {
try {
- List<Map.Entry<Long, ShortcutInfo>> shortcutInfos = PeopleSpaceUtils.getShortcutInfos(
- mContext, mNotificationManager, mPeopleManager);
- for (Map.Entry<Long, ShortcutInfo> entry : shortcutInfos) {
- ShortcutInfo shortcutInfo = entry.getValue();
+ List<Map.Entry<Long, PeopleSpaceTile>> tiles = PeopleSpaceUtils.getTiles(
+ mContext, mNotificationManager, mPeopleManager, mLauncherApps);
+ for (Map.Entry<Long, PeopleSpaceTile> entry : tiles) {
+ PeopleSpaceTile tile = entry.getValue();
PeopleSpaceTileView tileView = new PeopleSpaceTileView(mContext, mPeopleSpaceLayout,
- shortcutInfo.getId());
- setTileView(tileView, shortcutInfo, entry.getKey());
+ tile.getId());
+ setTileView(tileView, tile, entry.getKey());
}
} catch (Exception e) {
Log.e(TAG, "Couldn't retrieve conversations", e);
@@ -82,18 +82,18 @@ public class PeopleSpaceActivity extends Activity {
}
/** Sets {@code tileView} with the data in {@code conversation}. */
- private void setTileView(PeopleSpaceTileView tileView, ShortcutInfo shortcutInfo,
+ private void setTileView(PeopleSpaceTileView tileView, PeopleSpaceTile tile,
long lastInteraction) {
try {
- String pkg = shortcutInfo.getPackage();
+ String pkg = tile.getPackageName();
String status =
PeopleSpaceUtils.getLastInteractionString(mContext, lastInteraction);
tileView.setStatus(status);
- tileView.setName(shortcutInfo.getLabel().toString());
+ tileView.setName(tile.getUserName().toString());
tileView.setPackageIcon(mPackageManager.getApplicationIcon(pkg));
- tileView.setPersonIcon(mLauncherApps.getShortcutIconDrawable(shortcutInfo, 0));
- tileView.setOnClickListener(mLauncherApps, shortcutInfo);
+ tileView.setPersonIcon(tile.getUserIcon());
+ tileView.setOnClickListener(mLauncherApps, tile);
} catch (Exception e) {
Log.e(TAG, "Couldn't retrieve shortcut information", e);
}
diff --git a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceTileView.java b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceTileView.java
index d5ef190d5ff1..4aea5b8d6446 100644
--- a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceTileView.java
+++ b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceTileView.java
@@ -16,10 +16,12 @@
package com.android.systemui.people;
+import android.app.people.PeopleSpaceTile;
import android.content.Context;
import android.content.pm.LauncherApps;
-import android.content.pm.ShortcutInfo;
import android.graphics.drawable.Drawable;
+import android.graphics.drawable.Icon;
+import android.os.UserHandle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -71,13 +73,15 @@ public class PeopleSpaceTileView extends LinearLayout {
mPackageIconView.setImageDrawable(drawable);
}
- /** Sets the person drawable on the tile. */
- public void setPersonIcon(Drawable drawable) {
- mPersonIconView.setImageDrawable(drawable);
+ /** Sets the person bitmap on the tile. */
+ public void setPersonIcon(Icon icon) {
+ mPersonIconView.setImageIcon(icon);
}
/** Sets the click listener of the tile. */
- public void setOnClickListener(LauncherApps launcherApps, ShortcutInfo shortcutInfo) {
- mTileView.setOnClickListener(v -> launcherApps.startShortcut(shortcutInfo, null, null));
+ public void setOnClickListener(LauncherApps launcherApps, PeopleSpaceTile tile) {
+ mTileView.setOnClickListener(v ->
+ launcherApps.startShortcut(tile.getPackageName(), tile.getId(), null, null,
+ UserHandle.getUserHandleForUid(tile.getUid())));
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java
index 35e445b968ba..fe262b446a3c 100644
--- a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java
+++ b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java
@@ -19,8 +19,9 @@ package com.android.systemui.people;
import android.app.INotificationManager;
import android.app.people.ConversationChannel;
import android.app.people.IPeopleManager;
+import android.app.people.PeopleSpaceTile;
import android.content.Context;
-import android.content.pm.ShortcutInfo;
+import android.content.pm.LauncherApps;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.drawable.BitmapDrawable;
@@ -51,30 +52,34 @@ public class PeopleSpaceUtils {
private static final int MIN_HOUR = 1;
private static final int ONE_DAY = 1;
-
/** Returns a list of map entries corresponding to user's conversations. */
- public static List<Map.Entry<Long, ShortcutInfo>> getShortcutInfos(Context context,
- INotificationManager notificationManager, IPeopleManager peopleManager)
+ public static List<Map.Entry<Long, PeopleSpaceTile>> getTiles(
+ Context context, INotificationManager notificationManager, IPeopleManager peopleManager,
+ LauncherApps launcherApps)
throws Exception {
boolean showAllConversations = Settings.Global.getInt(context.getContentResolver(),
Settings.Global.PEOPLE_SPACE_CONVERSATION_TYPE, 0) == 0;
List<ConversationChannelWrapper> conversations = notificationManager.getConversations(
true).getList();
- List<Map.Entry<Long, ShortcutInfo>> shortcutInfos = getSortedShortcutInfos(peopleManager,
- conversations.stream().map(c -> c.getShortcutInfo()));
+ List<Map.Entry<Long, PeopleSpaceTile>> tiles = getSortedTiles(peopleManager,
+ conversations.stream().map(c ->
+ new PeopleSpaceTile.Builder(c.getShortcutInfo(), launcherApps).build()));
if (showAllConversations) {
List<ConversationChannel> recentConversations =
peopleManager.getRecentConversations().getList();
- List<Map.Entry<Long, ShortcutInfo>> recentShortcutInfos = getSortedShortcutInfos(
- peopleManager, recentConversations.stream().map(c -> c.getShortcutInfo()));
- shortcutInfos.addAll(recentShortcutInfos);
+ List<Map.Entry<Long, PeopleSpaceTile>> recentTiles =
+ getSortedTiles(peopleManager, recentConversations.stream().map(c ->
+ new PeopleSpaceTile
+ .Builder(c.getShortcutInfo(), launcherApps)
+ .build()));
+ tiles.addAll(recentTiles);
}
- return shortcutInfos;
+ return tiles;
}
/** Returns a list sorted by ascending last interaction time from {@code stream}. */
- private static List<Map.Entry<Long, ShortcutInfo>> getSortedShortcutInfos(
- IPeopleManager peopleManager, Stream<ShortcutInfo> stream) {
+ private static List<Map.Entry<Long, PeopleSpaceTile>> getSortedTiles(
+ IPeopleManager peopleManager, Stream<PeopleSpaceTile> stream) {
return stream
.filter(c -> shouldKeepConversation(c))
.map(c -> Map.entry(getLastInteraction(peopleManager, c), c))
@@ -82,13 +87,13 @@ public class PeopleSpaceUtils {
.collect(Collectors.toList());
}
- /** Returns the last interaction time with the user specified by {@code shortcutInfo}. */
+ /** Returns the last interaction time with the user specified by {@code PeopleSpaceTile}. */
private static Long getLastInteraction(IPeopleManager peopleManager,
- ShortcutInfo shortcutInfo) {
+ PeopleSpaceTile tile) {
try {
- int userId = UserHandle.getUserHandleForUid(shortcutInfo.getUserId()).getIdentifier();
- String pkg = shortcutInfo.getPackage();
- return peopleManager.getLastInteraction(pkg, userId, shortcutInfo.getId());
+ int userId = UserHandle.getUserHandleForUid(tile.getUid()).getIdentifier();
+ String pkg = tile.getPackageName();
+ return peopleManager.getLastInteraction(pkg, userId, tile.getId());
} catch (Exception e) {
Log.e(TAG, "Couldn't retrieve last interaction time", e);
return 0L;
@@ -157,13 +162,13 @@ public class PeopleSpaceUtils {
*
* <p>A valid {@code conversation} must:
* <ul>
- * <li>Have a non-null {@link ShortcutInfo}
- * <li>Have an associated label in the {@link ShortcutInfo}
+ * <li>Have a non-null {@link PeopleSpaceTile}
+ * <li>Have an associated label in the {@link PeopleSpaceTile}
* </ul>
* </li>
*/
- public static boolean shouldKeepConversation(ShortcutInfo shortcutInfo) {
- return shortcutInfo != null && shortcutInfo.getLabel().length() != 0;
+ public static boolean shouldKeepConversation(PeopleSpaceTile tile) {
+ return tile != null && tile.getUserName().length() != 0;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/people/widget/LaunchConversationActivity.java b/packages/SystemUI/src/com/android/systemui/people/widget/LaunchConversationActivity.java
index 44f173bc5175..0b0308f7dcda 100644
--- a/packages/SystemUI/src/com/android/systemui/people/widget/LaunchConversationActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/people/widget/LaunchConversationActivity.java
@@ -19,8 +19,8 @@ package com.android.systemui.people.widget;
import android.app.Activity;
import android.content.Intent;
import android.content.pm.LauncherApps;
-import android.content.pm.ShortcutInfo;
import android.os.Bundle;
+import android.os.UserHandle;
import android.util.Log;
import com.android.systemui.people.PeopleSpaceUtils;
@@ -36,18 +36,19 @@ public class LaunchConversationActivity extends Activity {
if (DEBUG) Log.d(TAG, "onCreate called");
Intent intent = getIntent();
- ShortcutInfo shortcutInfo = (ShortcutInfo) intent.getParcelableExtra(
- PeopleSpaceWidgetProvider.EXTRA_SHORTCUT_INFO
- );
- if (shortcutInfo != null) {
+ String tileId = intent.getStringExtra(PeopleSpaceWidgetProvider.EXTRA_TILE_ID);
+ String packageName = intent.getStringExtra(PeopleSpaceWidgetProvider.EXTRA_PACKAGE_NAME);
+ int uid = intent.getIntExtra(PeopleSpaceWidgetProvider.EXTRA_UID, 0);
+
+ if (tileId != null && !tileId.isEmpty()) {
if (DEBUG) {
- Log.d(TAG, "Launching conversation with shortcutInfo id " + shortcutInfo.getId());
+ Log.d(TAG, "Launching conversation with shortcutInfo id " + tileId);
}
try {
LauncherApps launcherApps =
getApplicationContext().getSystemService(LauncherApps.class);
launcherApps.startShortcut(
- shortcutInfo, null, null);
+ packageName, tileId, null, null, UserHandle.getUserHandleForUid(uid));
} catch (Exception e) {
Log.e(TAG, "Exception starting shortcut:" + e);
}
diff --git a/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetProvider.java b/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetProvider.java
index aa98b61ff947..9f84514f8c47 100644
--- a/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetProvider.java
@@ -32,7 +32,9 @@ public class PeopleSpaceWidgetProvider extends AppWidgetProvider {
private static final String TAG = "PeopleSpaceWidgetPvd";
private static final boolean DEBUG = PeopleSpaceUtils.DEBUG;
- public static final String EXTRA_SHORTCUT_INFO = "extra_shortcut_info";
+ public static final String EXTRA_TILE_ID = "extra_tile_id";
+ public static final String EXTRA_PACKAGE_NAME = "extra_package_name";
+ public static final String EXTRA_UID = "extra_uid";
/** Called when widget updates. */
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
diff --git a/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetRemoteViewsFactory.java b/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetRemoteViewsFactory.java
index a4527c3ef86f..1e6c213db852 100644
--- a/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetRemoteViewsFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetRemoteViewsFactory.java
@@ -18,11 +18,11 @@ package com.android.systemui.people.widget;
import android.app.INotificationManager;
import android.app.people.IPeopleManager;
+import android.app.people.PeopleSpaceTile;
import android.content.Context;
import android.content.Intent;
import android.content.pm.LauncherApps;
import android.content.pm.PackageManager;
-import android.content.pm.ShortcutInfo;
import android.os.ServiceManager;
import android.util.Log;
import android.widget.RemoteViews;
@@ -45,7 +45,7 @@ public class PeopleSpaceWidgetRemoteViewsFactory implements RemoteViewsService.R
private INotificationManager mNotificationManager;
private PackageManager mPackageManager;
private LauncherApps mLauncherApps;
- private List<Map.Entry<Long, ShortcutInfo>> mShortcutInfos = new ArrayList<>();
+ private List<Map.Entry<Long, PeopleSpaceTile>> mTiles = new ArrayList<>();
private Context mContext;
public PeopleSpaceWidgetRemoteViewsFactory(Context context, Intent intent) {
@@ -70,8 +70,8 @@ public class PeopleSpaceWidgetRemoteViewsFactory implements RemoteViewsService.R
*/
private void setTileViewsWithPriorityConversations() {
try {
- mShortcutInfos = PeopleSpaceUtils.getShortcutInfos(mContext, mNotificationManager,
- mPeopleManager);
+ mTiles = PeopleSpaceUtils.getTiles(mContext, mNotificationManager,
+ mPeopleManager, mLauncherApps);
} catch (Exception e) {
Log.e(TAG, "Couldn't retrieve conversations", e);
}
@@ -85,12 +85,12 @@ public class PeopleSpaceWidgetRemoteViewsFactory implements RemoteViewsService.R
@Override
public void onDestroy() {
- mShortcutInfos.clear();
+ mTiles.clear();
}
@Override
public int getCount() {
- return mShortcutInfos.size();
+ return mTiles.size();
}
@Override
@@ -100,30 +100,28 @@ public class PeopleSpaceWidgetRemoteViewsFactory implements RemoteViewsService.R
RemoteViews personView = new RemoteViews(mContext.getPackageName(),
R.layout.people_space_widget_item);
try {
- Map.Entry<Long, ShortcutInfo> entry = mShortcutInfos.get(i);
- ShortcutInfo shortcutInfo = entry.getValue();
+ Map.Entry<Long, PeopleSpaceTile> entry = mTiles.get(i);
+ PeopleSpaceTile tile = entry.getValue();
long lastInteraction = entry.getKey();
String status = PeopleSpaceUtils.getLastInteractionString(mContext, lastInteraction);
personView.setTextViewText(R.id.status, status);
- personView.setTextViewText(R.id.name, shortcutInfo.getLabel().toString());
+ personView.setTextViewText(R.id.name, tile.getUserName().toString());
personView.setImageViewBitmap(
R.id.package_icon,
PeopleSpaceUtils.convertDrawableToBitmap(
- mPackageManager.getApplicationIcon(shortcutInfo.getPackage())
- )
- );
- personView.setImageViewBitmap(
- R.id.person_icon,
- PeopleSpaceUtils.convertDrawableToBitmap(
- mLauncherApps.getShortcutIconDrawable(shortcutInfo, 0)
+ mPackageManager.getApplicationIcon(tile.getPackageName())
)
);
+ personView.setImageViewIcon(R.id.person_icon, tile.getUserIcon());
Intent fillInIntent = new Intent();
- fillInIntent.putExtra(PeopleSpaceWidgetProvider.EXTRA_SHORTCUT_INFO, shortcutInfo);
+ fillInIntent.putExtra(PeopleSpaceWidgetProvider.EXTRA_TILE_ID, tile.getId());
+ fillInIntent.putExtra(
+ PeopleSpaceWidgetProvider.EXTRA_PACKAGE_NAME, tile.getPackageName());
+ fillInIntent.putExtra(PeopleSpaceWidgetProvider.EXTRA_UID, tile.getUid());
personView.setOnClickFillInIntent(R.id.item, fillInIntent);
} catch (Exception e) {
Log.e(TAG, "Couldn't retrieve shortcut information", e);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java b/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java
index 478923994af8..5afe526be918 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java
@@ -68,6 +68,7 @@ class QSSecurityFooter implements OnClickListener, DialogInterface.OnClickListen
private final View mRootView;
private final TextView mFooterText;
private final ImageView mFooterIcon;
+ private final ImageView mPrimaryFooterIcon;
private final Context mContext;
private final Callback mCallback = new Callback();
private final SecurityController mSecurityController;
@@ -83,6 +84,7 @@ class QSSecurityFooter implements OnClickListener, DialogInterface.OnClickListen
private CharSequence mFooterTextContent = null;
private int mFooterTextId;
private int mFooterIconId;
+ private Drawable mPrimaryFooterIconDrawable;
@Inject
QSSecurityFooter(@Named(QS_SECURITY_FOOTER_VIEW) View rootView, Context context,
@@ -92,6 +94,7 @@ class QSSecurityFooter implements OnClickListener, DialogInterface.OnClickListen
mRootView.setOnClickListener(this);
mFooterText = mRootView.findViewById(R.id.footer_text);
mFooterIcon = mRootView.findViewById(R.id.footer_icon);
+ mPrimaryFooterIcon = mRootView.findViewById(R.id.primary_footer_icon);
mFooterIconId = R.drawable.ic_info_outline;
mContext = context;
mMainHandler = mainHandler;
@@ -188,6 +191,18 @@ class QSSecurityFooter implements OnClickListener, DialogInterface.OnClickListen
mFooterIconId = footerIconId;
mMainHandler.post(mUpdateIcon);
}
+
+ // Update the primary icon
+ if (isParentalControlsEnabled) {
+ if (mPrimaryFooterIconDrawable == null) {
+ DeviceAdminInfo info = mSecurityController.getDeviceAdminInfo();
+ mPrimaryFooterIconDrawable = mSecurityController.getIcon(info);
+ }
+ } else {
+ mPrimaryFooterIconDrawable = null;
+ }
+ mMainHandler.post(mUpdatePrimaryIcon);
+
mMainHandler.post(mUpdateDisplayState);
}
@@ -532,6 +547,15 @@ class QSSecurityFooter implements OnClickListener, DialogInterface.OnClickListen
}
};
+ private final Runnable mUpdatePrimaryIcon = new Runnable() {
+ @Override
+ public void run() {
+ mPrimaryFooterIcon.setVisibility(mPrimaryFooterIconDrawable != null
+ ? View.VISIBLE : View.GONE);
+ mPrimaryFooterIcon.setImageDrawable(mPrimaryFooterIconDrawable);
+ }
+ };
+
private final Runnable mUpdateDisplayState = new Runnable() {
@Override
public void run() {
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
index 35874cd8bb28..d7f9c6163b1d 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
@@ -16,20 +16,20 @@
package com.android.systemui.screenshot;
-import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
+import static android.view.WindowManager.LayoutParams.TYPE_SCREENSHOT;
import static java.util.Objects.requireNonNull;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.annotation.Nullable;
-import android.annotation.SuppressLint;
import android.app.Notification;
import android.content.ComponentName;
import android.content.Context;
-import android.content.res.Configuration;
+import android.content.pm.ActivityInfo;
import android.graphics.Bitmap;
import android.graphics.Insets;
import android.graphics.PixelFormat;
@@ -52,7 +52,8 @@ import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.SurfaceControl;
import android.view.View;
-import android.view.ViewGroup;
+import android.view.Window;
+import android.view.WindowInsets;
import android.view.WindowManager;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
@@ -60,6 +61,8 @@ import android.widget.Toast;
import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
import com.android.internal.logging.UiEventLogger;
+import com.android.internal.policy.PhoneWindow;
+import com.android.settingslib.applications.InterestingConfigChanges;
import com.android.systemui.R;
import com.android.systemui.util.DeviceConfigProxy;
@@ -141,12 +144,13 @@ public class ScreenshotController {
private final WindowManager mWindowManager;
private final WindowManager.LayoutParams mWindowLayoutParams;
- private final Display mDisplay;
private final DisplayMetrics mDisplayMetrics;
private final AccessibilityManager mAccessibilityManager;
private final MediaActionSound mCameraSound;
private final ScrollCaptureClient mScrollCaptureClient;
private final DeviceConfigProxy mConfigProxy;
+ private final PhoneWindow mWindow;
+ private final View mDecorView;
private final Binder mWindowToken;
private ScreenshotView mScreenshotView;
@@ -156,9 +160,6 @@ public class ScreenshotController {
private Animator mScreenshotAnimation;
private Runnable mOnCompleteRunnable;
- private boolean mInDarkMode;
- private boolean mDirectionLTR;
- private boolean mOrientationPortrait;
private final Handler mScreenshotHandler = new Handler(Looper.getMainLooper()) {
@Override
@@ -174,6 +175,15 @@ public class ScreenshotController {
}
};
+ /** Tracks config changes that require re-creating UI */
+ private final InterestingConfigChanges mConfigChanges = new InterestingConfigChanges(
+ ActivityInfo.CONFIG_ORIENTATION
+ | ActivityInfo.CONFIG_LAYOUT_DIRECTION
+ | ActivityInfo.CONFIG_LOCALE
+ | ActivityInfo.CONFIG_UI_MODE
+ | ActivityInfo.CONFIG_SCREEN_LAYOUT
+ | ActivityInfo.CONFIG_ASSETS_PATHS);
+
@Inject
ScreenshotController(
Context context,
@@ -188,25 +198,20 @@ public class ScreenshotController {
mUiEventLogger = uiEventLogger;
final DisplayManager dm = requireNonNull(context.getSystemService(DisplayManager.class));
- mDisplay = dm.getDisplay(DEFAULT_DISPLAY);
- mContext = context.createDisplayContext(mDisplay);
+ final Display display = dm.getDisplay(DEFAULT_DISPLAY);
+ final Context displayContext = context.createDisplayContext(display);
+ mContext = displayContext.createWindowContext(TYPE_SCREENSHOT, null);
mWindowManager = mContext.getSystemService(WindowManager.class);
mAccessibilityManager = AccessibilityManager.getInstance(mContext);
mConfigProxy = configProxy;
- reloadAssets();
- Configuration config = mContext.getResources().getConfiguration();
- mInDarkMode = config.isNightModeActive();
- mDirectionLTR = config.getLayoutDirection() == View.LAYOUT_DIRECTION_LTR;
- mOrientationPortrait = config.orientation == ORIENTATION_PORTRAIT;
mWindowToken = new Binder("ScreenshotController");
mScrollCaptureClient.setHostWindowToken(mWindowToken);
// Setup the window that we are going to use
mWindowLayoutParams = new WindowManager.LayoutParams(
- ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT, 0, 0,
- WindowManager.LayoutParams.TYPE_SCREENSHOT,
+ MATCH_PARENT, MATCH_PARENT, /* xpos */ 0, /* ypos */ 0, TYPE_SCREENSHOT,
WindowManager.LayoutParams.FLAG_FULLSCREEN
| WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
| WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
@@ -217,13 +222,21 @@ public class ScreenshotController {
mWindowLayoutParams.setTitle("ScreenshotAnimation");
mWindowLayoutParams.layoutInDisplayCutoutMode =
WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
- mWindowLayoutParams.setFitInsetsTypes(0 /* types */);
mWindowLayoutParams.token = mWindowToken;
// This is needed to let touches pass through outside the touchable areas
mWindowLayoutParams.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY;
+ mWindow = new PhoneWindow(mContext);
+ mWindow.setWindowManager(mWindowManager, null, null);
+ mWindow.requestFeature(Window.FEATURE_NO_TITLE);
+ mWindow.requestFeature(Window.FEATURE_ACTIVITY_TRANSITIONS);
+ mWindow.setBackgroundDrawableResource(android.R.color.transparent);
+ mDecorView = mWindow.getDecorView();
+
+ reloadAssets();
+
mDisplayMetrics = new DisplayMetrics();
- mDisplay.getRealMetrics(mDisplayMetrics);
+ display.getRealMetrics(mDisplayMetrics);
// Setup the Camera shutter sound
mCameraSound = new MediaActionSound();
@@ -233,7 +246,6 @@ public class ScreenshotController {
void takeScreenshotFullscreen(Consumer<Uri> finisher, Runnable onComplete) {
mOnCompleteRunnable = onComplete;
- mDisplay.getRealMetrics(mDisplayMetrics);
takeScreenshotInternal(
finisher,
new Rect(0, 0, mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels));
@@ -254,19 +266,18 @@ public class ScreenshotController {
return;
}
- if (aspectRatiosMatch(screenshot, visibleInsets, screenshotScreenBounds)) {
- saveScreenshot(screenshot, finisher, screenshotScreenBounds, visibleInsets, false);
- } else {
- saveScreenshot(screenshot, finisher,
- new Rect(0, 0, screenshot.getWidth(), screenshot.getHeight()), Insets.NONE,
- true);
+ boolean showFlash = false;
+ if (!aspectRatiosMatch(screenshot, visibleInsets, screenshotScreenBounds)) {
+ showFlash = true;
+ visibleInsets = Insets.NONE;
+ screenshotScreenBounds.set(0, 0, screenshot.getWidth(), screenshot.getHeight());
}
+ saveScreenshot(screenshot, finisher, screenshotScreenBounds, visibleInsets, showFlash);
}
/**
* Displays a screenshot selector
*/
- @SuppressLint("ClickableViewAccessibility")
void takeScreenshotPartial(final Consumer<Uri> finisher, Runnable onComplete) {
dismissScreenshot(true);
mOnCompleteRunnable = onComplete;
@@ -296,70 +307,27 @@ public class ScreenshotController {
}
}
- private void onConfigChanged(Configuration newConfig) {
- boolean needsUpdate = false;
- // dark mode
- if (newConfig.isNightModeActive()) {
- // Night mode is active, we're using dark theme
- if (!mInDarkMode) {
- mInDarkMode = true;
- needsUpdate = true;
- }
- } else {
- // Night mode is not active, we're using the light theme
- if (mInDarkMode) {
- mInDarkMode = false;
- needsUpdate = true;
- }
- }
-
- // RTL configuration
- switch (newConfig.getLayoutDirection()) {
- case View.LAYOUT_DIRECTION_LTR:
- if (!mDirectionLTR) {
- mDirectionLTR = true;
- needsUpdate = true;
- }
- break;
- case View.LAYOUT_DIRECTION_RTL:
- if (mDirectionLTR) {
- mDirectionLTR = false;
- needsUpdate = true;
- }
- break;
- }
-
- // portrait/landscape orientation
- switch (newConfig.orientation) {
- case ORIENTATION_PORTRAIT:
- if (!mOrientationPortrait) {
- mOrientationPortrait = true;
- needsUpdate = true;
- }
- break;
- case ORIENTATION_LANDSCAPE:
- if (mOrientationPortrait) {
- mOrientationPortrait = false;
- needsUpdate = true;
- }
- break;
- }
-
- if (needsUpdate) {
- reloadAssets();
- }
- }
-
/**
* Update assets (called when the dark theme status changes). We only need to update the dismiss
* button and the actions container background, since the buttons are re-inflated on demand.
*/
private void reloadAssets() {
- boolean wasAttached = mScreenshotView != null && mScreenshotView.isAttachedToWindow();
+ boolean wasAttached = mDecorView.isAttachedToWindow();
if (wasAttached) {
- mWindowManager.removeView(mScreenshotView);
+ mWindowManager.removeView(mDecorView);
}
+ // respect the display cutout in landscape (since we'd otherwise overlap) but not portrait
+ int orientation = mContext.getResources().getConfiguration().orientation;
+ mWindowLayoutParams.setFitInsetsTypes(
+ orientation == ORIENTATION_PORTRAIT ? 0 : WindowInsets.Type.displayCutout());
+
+ // ignore system bar insets for the purpose of window layout
+ mDecorView.setOnApplyWindowInsetsListener((v, insets) -> v.onApplyWindowInsets(
+ new WindowInsets.Builder(insets)
+ .setInsets(WindowInsets.Type.all(), Insets.NONE)
+ .build()));
+
// Inflate the screenshot layout
mScreenshotView = (ScreenshotView)
LayoutInflater.from(mContext).inflate(R.layout.global_screenshot, null);
@@ -382,9 +350,8 @@ public class ScreenshotController {
return false;
});
- if (wasAttached) {
- mWindowManager.addView(mScreenshotView, mWindowLayoutParams);
- }
+ // view is added to window manager in startAnimation
+ mWindow.setContentView(mScreenshotView, mWindowLayoutParams);
}
/**
@@ -448,7 +415,9 @@ public class ScreenshotController {
mScreenBitmap.setHasAlpha(false);
mScreenBitmap.prepareToDraw();
- onConfigChanged(mContext.getResources().getConfiguration());
+ if (mConfigChanges.applyNewConfig(mContext.getResources())) {
+ reloadAssets();
+ }
// The window is focusable by default
setWindowFocusable(true);
@@ -510,10 +479,10 @@ public class ScreenshotController {
mScreenshotHandler.removeMessages(MESSAGE_CORNER_TIMEOUT);
mScreenshotHandler.post(() -> {
if (!mScreenshotView.isAttachedToWindow()) {
- mWindowManager.addView(mScreenshotView, mWindowLayoutParams);
+ mWindowManager.addView(mWindow.getDecorView(), mWindowLayoutParams);
}
- mScreenshotView.prepareForAnimation(mScreenBitmap, screenRect, screenInsets);
+ mScreenshotView.prepareForAnimation(mScreenBitmap, screenInsets);
mScreenshotHandler.post(() -> {
mScreenshotView.getViewTreeObserver().addOnComputeInternalInsetsListener(
@@ -541,7 +510,7 @@ public class ScreenshotController {
private void resetScreenshotView() {
if (mScreenshotView.isAttachedToWindow()) {
- mWindowManager.removeView(mScreenshotView);
+ mWindowManager.removeView(mDecorView);
}
mScreenshotView.reset();
mOnCompleteRunnable.run();
@@ -636,8 +605,8 @@ public class ScreenshotController {
} else {
mWindowLayoutParams.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
}
- if (mScreenshotView.isAttachedToWindow()) {
- mWindowManager.updateViewLayout(mScreenshotView, mWindowLayoutParams);
+ if (mDecorView.isAttachedToWindow()) {
+ mWindowManager.updateViewLayout(mDecorView, mWindowLayoutParams);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java
index b020275ae3ae..3814bd2999e9 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java
@@ -240,8 +240,7 @@ public class ScreenshotView extends FrameLayout implements
setOnApplyWindowInsetsListener((v, insets) -> {
if (QuickStepContract.isGesturalMode(mNavMode)) {
- Insets gestureInsets = insets.getInsets(
- WindowInsets.Type.systemGestures());
+ Insets gestureInsets = insets.getInsets(WindowInsets.Type.systemGestures());
mLeftInset = gestureInsets.left;
mRightInset = gestureInsets.right;
} else {
@@ -272,7 +271,7 @@ public class ScreenshotView extends FrameLayout implements
mScreenshotSelectorView.requestFocus();
}
- void prepareForAnimation(Bitmap bitmap, Rect screenRect, Insets screenInsets) {
+ void prepareForAnimation(Bitmap bitmap, Insets screenInsets) {
mScreenshotPreview.setImageDrawable(createScreenDrawable(mResources, bitmap, screenInsets));
// make static preview invisible (from gone) so we can query its location on screen
mScreenshotPreview.setVisibility(View.INVISIBLE);
@@ -284,6 +283,8 @@ public class ScreenshotView extends FrameLayout implements
Rect previewBounds = new Rect();
mScreenshotPreview.getBoundsOnScreen(previewBounds);
+ int[] previewLocation = new int[2];
+ mScreenshotPreview.getLocationInWindow(previewLocation);
float cornerScale =
mCornerSizeX / (mOrientationPortrait ? bounds.width() : bounds.height());
@@ -310,7 +311,8 @@ public class ScreenshotView extends FrameLayout implements
// animate from the current location, to the static preview location
final PointF startPos = new PointF(bounds.centerX(), bounds.centerY());
- final PointF finalPos = new PointF(previewBounds.centerX(), previewBounds.centerY());
+ final PointF finalPos = new PointF(previewLocation[0] + previewBounds.width() / 2f,
+ previewLocation[1] + previewBounds.height() / 2f);
ValueAnimator toCorner = ValueAnimator.ofFloat(0, 1);
toCorner.setDuration(SCREENSHOT_TO_CORNER_Y_DURATION_MS);
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
index 2c82bcb24ad0..4aaea8041abd 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
@@ -41,6 +41,8 @@ import android.os.UserManager;
import android.util.Log;
import android.view.WindowManager;
+import androidx.annotation.NonNull;
+
import com.android.internal.logging.UiEventLogger;
import com.android.internal.util.ScreenshotHelper;
import com.android.systemui.R;
@@ -57,9 +59,8 @@ public class TakeScreenshotService extends Service {
private final UserManager mUserManager;
private final UiEventLogger mUiEventLogger;
private final ScreenshotNotificationsController mNotificationsController;
-
- private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
-
+ private final Handler mHandler;
+ private final BroadcastReceiver mCloseSystemDialogs = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (ACTION_CLOSE_SYSTEM_DIALOGS.equals(intent.getAction()) && mScreenshot != null) {
@@ -68,72 +69,11 @@ public class TakeScreenshotService extends Service {
}
};
- private Handler mHandler = new Handler(Looper.myLooper()) {
- @Override
- public void handleMessage(Message msg) {
- final Messenger callback = msg.replyTo;
- Consumer<Uri> uriConsumer = uri -> {
- Message reply = Message.obtain(null, SCREENSHOT_MSG_URI, uri);
- try {
- callback.send(reply);
- } catch (RemoteException e) {
- }
- };
- Runnable onComplete = () -> {
- Message reply = Message.obtain(null, SCREENSHOT_MSG_PROCESS_COMPLETE);
- try {
- callback.send(reply);
- } catch (RemoteException e) {
- }
- };
-
- // If the storage for this user is locked, we have no place to store
- // the screenshot, so skip taking it instead of showing a misleading
- // animation and error notification.
- if (!mUserManager.isUserUnlocked()) {
- Log.w(TAG, "Skipping screenshot because storage is locked!");
- mNotificationsController.notifyScreenshotError(
- R.string.screenshot_failed_to_save_user_locked_text);
- post(() -> uriConsumer.accept(null));
- post(onComplete);
- return;
- }
-
- ScreenshotHelper.ScreenshotRequest screenshotRequest =
- (ScreenshotHelper.ScreenshotRequest) msg.obj;
-
- mUiEventLogger.log(ScreenshotEvent.getScreenshotSource(screenshotRequest.getSource()));
-
- switch (msg.what) {
- case WindowManager.TAKE_SCREENSHOT_FULLSCREEN:
- mScreenshot.takeScreenshotFullscreen(uriConsumer, onComplete);
- break;
- case WindowManager.TAKE_SCREENSHOT_SELECTED_REGION:
- mScreenshot.takeScreenshotPartial(uriConsumer, onComplete);
- break;
- case WindowManager.TAKE_SCREENSHOT_PROVIDED_IMAGE:
- Bitmap screenshot = BitmapUtil.bundleToHardwareBitmap(
- screenshotRequest.getBitmapBundle());
- Rect screenBounds = screenshotRequest.getBoundsInScreen();
- Insets insets = screenshotRequest.getInsets();
- int taskId = screenshotRequest.getTaskId();
- int userId = screenshotRequest.getUserId();
- ComponentName topComponent = screenshotRequest.getTopComponent();
- mScreenshot.handleImageAsScreenshot(screenshot, screenBounds, insets,
- taskId, userId, topComponent, uriConsumer, onComplete);
- break;
- default:
- Log.d(TAG, "Invalid screenshot option: " + msg.what);
- }
- }
- };
-
@Inject
- public TakeScreenshotService(
- ScreenshotController screenshotController,
- UserManager userManager,
+ public TakeScreenshotService(ScreenshotController screenshotController, UserManager userManager,
UiEventLogger uiEventLogger,
ScreenshotNotificationsController notificationsController) {
+ mHandler = new Handler(Looper.getMainLooper(), this::handleMessage);
mScreenshot = screenshotController;
mUserManager = userManager;
mUiEventLogger = uiEventLogger;
@@ -141,13 +81,9 @@ public class TakeScreenshotService extends Service {
}
@Override
- public IBinder onBind(Intent intent) {
- // register broadcast receiver
- IntentFilter filter = new IntentFilter(ACTION_CLOSE_SYSTEM_DIALOGS);
- registerReceiver(mBroadcastReceiver, filter);
-
+ public IBinder onBind(@NonNull Intent intent) {
+ registerReceiver(mCloseSystemDialogs, new IntentFilter(ACTION_CLOSE_SYSTEM_DIALOGS));
return new Messenger(mHandler).getBinder();
-
}
@Override
@@ -155,7 +91,73 @@ public class TakeScreenshotService extends Service {
if (mScreenshot != null) {
mScreenshot.dismissScreenshot(true);
}
- unregisterReceiver(mBroadcastReceiver);
+ unregisterReceiver(mCloseSystemDialogs);
+ return false;
+ }
+
+ /** Respond to incoming Message via Binder (Messenger) */
+ private boolean handleMessage(Message msg) {
+ final Messenger replyTo = msg.replyTo;
+ final Runnable onComplete = () -> sendComplete(replyTo);
+ final Consumer<Uri> uriConsumer = (uri) -> reportUri(replyTo, uri);
+
+ // If the storage for this user is locked, we have no place to store
+ // the screenshot, so skip taking it instead of showing a misleading
+ // animation and error notification.
+ if (!mUserManager.isUserUnlocked()) {
+ Log.w(TAG, "Skipping screenshot because storage is locked!");
+ mNotificationsController.notifyScreenshotError(
+ R.string.screenshot_failed_to_save_user_locked_text);
+ uriConsumer.accept(null);
+ onComplete.run();
+ return true;
+ }
+
+ ScreenshotHelper.ScreenshotRequest screenshotRequest =
+ (ScreenshotHelper.ScreenshotRequest) msg.obj;
+
+ mUiEventLogger.log(ScreenshotEvent.getScreenshotSource(screenshotRequest.getSource()));
+
+ switch (msg.what) {
+ case WindowManager.TAKE_SCREENSHOT_FULLSCREEN:
+ mScreenshot.takeScreenshotFullscreen(uriConsumer, onComplete);
+ break;
+ case WindowManager.TAKE_SCREENSHOT_SELECTED_REGION:
+ mScreenshot.takeScreenshotPartial(uriConsumer, onComplete);
+ break;
+ case WindowManager.TAKE_SCREENSHOT_PROVIDED_IMAGE:
+ Bitmap screenshot = BitmapUtil.bundleToHardwareBitmap(
+ screenshotRequest.getBitmapBundle());
+ Rect screenBounds = screenshotRequest.getBoundsInScreen();
+ Insets insets = screenshotRequest.getInsets();
+ int taskId = screenshotRequest.getTaskId();
+ int userId = screenshotRequest.getUserId();
+ ComponentName topComponent = screenshotRequest.getTopComponent();
+ mScreenshot.handleImageAsScreenshot(screenshot, screenBounds, insets,
+ taskId, userId, topComponent, uriConsumer, onComplete);
+ break;
+ default:
+ Log.w(TAG, "Invalid screenshot option: " + msg.what);
+ return false;
+ }
return true;
+ };
+
+ private void sendComplete(Messenger target) {
+ try {
+ Log.d(TAG, "sendComplete: " + target);
+ target.send(Message.obtain(null, SCREENSHOT_MSG_PROCESS_COMPLETE));
+ } catch (RemoteException e) {
+ Log.d(TAG, "ignored remote exception", e);
+ }
+ }
+
+ private void reportUri(Messenger target, Uri uri) {
+ try {
+ Log.d(TAG, "reportUri: " + target + " -> " + uri);
+ target.send(Message.obtain(null, SCREENSHOT_MSG_URI, uri));
+ } catch (RemoteException e) {
+ Log.d(TAG, "ignored remote exception", e);
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index a252a7a12274..3765e5a26e8e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -69,7 +69,6 @@ import com.android.systemui.util.wakelock.WakeLock;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.text.NumberFormat;
-import java.util.IllegalFormatConversionException;
import javax.inject.Inject;
@@ -575,24 +574,12 @@ public class KeyguardIndicationController implements StateListener,
String percentage = NumberFormat.getPercentInstance()
.format(mBatteryLevel / 100f);
if (hasChargingTime) {
- // We now have battery percentage in these strings and it's expected that all
- // locales will also have it in the future. For now, we still have to support the old
- // format until all languages get the new translations.
String chargingTimeFormatted = Formatter.formatShortElapsedTimeRoundingUpToMinutes(
mContext, mChargingTimeRemaining);
- try {
- return mContext.getResources().getString(chargingId, chargingTimeFormatted,
- percentage);
- } catch (IllegalFormatConversionException e) {
- return mContext.getResources().getString(chargingId, chargingTimeFormatted);
- }
+ return mContext.getResources().getString(chargingId, chargingTimeFormatted,
+ percentage);
} else {
- // Same as above
- try {
- return mContext.getResources().getString(chargingId, percentage);
- } catch (IllegalFormatConversionException e) {
- return mContext.getResources().getString(chargingId);
- }
+ return mContext.getResources().getString(chargingId, percentage);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationHeaderUtil.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGroupingUtil.java
index 84818eea8a23..dbee0ee8f5d5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationHeaderUtil.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGroupingUtil.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2015 The Android Open Source Project
+ * Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -11,19 +11,22 @@
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT 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.systemui.statusbar;
import android.app.Notification;
+import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
import android.text.TextUtils;
+import android.view.NotificationHeaderView;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
+import com.android.internal.R;
import com.android.internal.widget.CachingIconView;
import com.android.internal.widget.ConversationLayout;
import com.android.internal.widget.NotificationExpandButton;
@@ -36,35 +39,38 @@ import java.util.List;
import java.util.Objects;
/**
- * A Util to manage {@link android.view.NotificationHeaderView} objects and their redundancies.
+ * A utility to manage notification views when they are placed in a group by adjusting elements
+ * to reduce redundancies and occasionally tweak layouts to highlight the unique content.
*/
-public class NotificationHeaderUtil {
-
- private static final TextViewComparator sTextViewComparator = new TextViewComparator();
- private static final TextViewComparator sAppNameComparator = new AppNameComparator();
- private static final VisibilityApplicator sVisibilityApplicator = new VisibilityApplicator();
- private static final VisibilityApplicator sAppNameApplicator = new AppNameApplicator();
- private static final DataExtractor sIconExtractor = new DataExtractor() {
+public class NotificationGroupingUtil {
+
+ private static final TextViewComparator TEXT_VIEW_COMPARATOR = new TextViewComparator();
+ private static final TextViewComparator APP_NAME_COMPARATOR = new AppNameComparator();
+ private static final ViewComparator BADGE_COMPARATOR = new BadgeComparator();
+ private static final VisibilityApplicator VISIBILITY_APPLICATOR = new VisibilityApplicator();
+ private static final VisibilityApplicator APP_NAME_APPLICATOR = new AppNameApplicator();
+ private static final ResultApplicator LEFT_ICON_APPLICATOR = new LeftIconApplicator();
+ private static final DataExtractor ICON_EXTRACTOR = new DataExtractor() {
@Override
public Object extractData(ExpandableNotificationRow row) {
return row.getEntry().getSbn().getNotification();
}
};
- private static final IconComparator sIconVisibilityComparator = new IconComparator() {
+ private static final IconComparator ICON_VISIBILITY_COMPARATOR = new IconComparator() {
public boolean compare(View parent, View child, Object parentData,
Object childData) {
return hasSameIcon(parentData, childData)
&& hasSameColor(parentData, childData);
}
};
- private static final IconComparator sGreyComparator = new IconComparator() {
+ private static final IconComparator GREY_COMPARATOR = new IconComparator() {
public boolean compare(View parent, View child, Object parentData,
Object childData) {
return !hasSameIcon(parentData, childData)
|| hasSameColor(parentData, childData);
}
};
- private final static ResultApplicator mGreyApplicator = new ResultApplicator() {
+ private static final ResultApplicator GREY_APPLICATOR = new ResultApplicator() {
@Override
public void apply(View parent, View view, boolean apply, boolean reset) {
CachingIconView icon = view.findViewById(com.android.internal.R.id.icon);
@@ -80,87 +86,79 @@ public class NotificationHeaderUtil {
};
private final ExpandableNotificationRow mRow;
- private final ArrayList<HeaderProcessor> mComparators = new ArrayList<>();
+ private final ArrayList<Processor> mProcessors = new ArrayList<>();
private final HashSet<Integer> mDividers = new HashSet<>();
- public NotificationHeaderUtil(ExpandableNotificationRow row) {
+ public NotificationGroupingUtil(ExpandableNotificationRow row) {
mRow = row;
// To hide the icons if they are the same and the color is the same
- mComparators.add(new HeaderProcessor(mRow,
+ mProcessors.add(new Processor(mRow,
com.android.internal.R.id.icon,
- sIconExtractor,
- sIconVisibilityComparator,
- sVisibilityApplicator));
+ ICON_EXTRACTOR,
+ ICON_VISIBILITY_COMPARATOR,
+ VISIBILITY_APPLICATOR));
// To grey them out the icons and expand button when the icons are not the same
- mComparators.add(new HeaderProcessor(mRow,
- com.android.internal.R.id.notification_header,
- sIconExtractor,
- sGreyComparator,
- mGreyApplicator));
- mComparators.add(new HeaderProcessor(mRow,
+ mProcessors.add(new Processor(mRow,
+ com.android.internal.R.id.status_bar_latest_event_content,
+ ICON_EXTRACTOR,
+ GREY_COMPARATOR,
+ GREY_APPLICATOR));
+ mProcessors.add(new Processor(mRow,
+ com.android.internal.R.id.status_bar_latest_event_content,
+ ICON_EXTRACTOR,
+ ICON_VISIBILITY_COMPARATOR,
+ LEFT_ICON_APPLICATOR));
+ mProcessors.add(new Processor(mRow,
com.android.internal.R.id.profile_badge,
null /* Extractor */,
- new ViewComparator() {
- @Override
- public boolean compare(View parent, View child, Object parentData,
- Object childData) {
- return parent.getVisibility() != View.GONE;
- }
-
- @Override
- public boolean isEmpty(View view) {
- if (view instanceof ImageView) {
- return ((ImageView) view).getDrawable() == null;
- }
- return false;
- }
- },
- sVisibilityApplicator));
- mComparators.add(new HeaderProcessor(
- mRow,
+ BADGE_COMPARATOR,
+ VISIBILITY_APPLICATOR));
+ mProcessors.add(new Processor(mRow,
com.android.internal.R.id.app_name_text,
null,
- sAppNameComparator,
- sAppNameApplicator));
- mComparators.add(HeaderProcessor.forTextView(mRow,
- com.android.internal.R.id.header_text));
+ APP_NAME_COMPARATOR,
+ APP_NAME_APPLICATOR));
+ mProcessors.add(Processor.forTextView(mRow, com.android.internal.R.id.header_text));
mDividers.add(com.android.internal.R.id.header_text_divider);
mDividers.add(com.android.internal.R.id.header_text_secondary_divider);
mDividers.add(com.android.internal.R.id.time_divider);
}
- public void updateChildrenHeaderAppearance() {
+ /**
+ * Update the appearance of the children in this group to reduce redundancies.
+ */
+ public void updateChildrenAppearance() {
List<ExpandableNotificationRow> notificationChildren = mRow.getAttachedChildren();
- if (notificationChildren == null) {
+ if (notificationChildren == null || !mRow.isSummaryWithChildren()) {
return;
}
- // Initialize the comparators
- for (int compI = 0; compI < mComparators.size(); compI++) {
- mComparators.get(compI).init();
+ // Initialize the processors
+ for (int compI = 0; compI < mProcessors.size(); compI++) {
+ mProcessors.get(compI).init();
}
// Compare all notification headers
for (int i = 0; i < notificationChildren.size(); i++) {
ExpandableNotificationRow row = notificationChildren.get(i);
- for (int compI = 0; compI < mComparators.size(); compI++) {
- mComparators.get(compI).compareToHeader(row);
+ for (int compI = 0; compI < mProcessors.size(); compI++) {
+ mProcessors.get(compI).compareToGroupParent(row);
}
}
// Apply the comparison to the row
for (int i = 0; i < notificationChildren.size(); i++) {
ExpandableNotificationRow row = notificationChildren.get(i);
- for (int compI = 0; compI < mComparators.size(); compI++) {
- mComparators.get(compI).apply(row);
+ for (int compI = 0; compI < mProcessors.size(); compI++) {
+ mProcessors.get(compI).apply(row);
}
// We need to sanitize the dividers since they might be off-balance now
- sanitizeHeaderViews(row);
+ sanitizeTopLineViews(row);
}
}
- private void sanitizeHeaderViews(ExpandableNotificationRow row) {
+ private void sanitizeTopLineViews(ExpandableNotificationRow row) {
if (row.isSummaryWithChildren()) {
- sanitizeHeader(row.getNotificationViewWrapper().getNotificationHeader());
+ sanitizeTopLine(row.getNotificationViewWrapper().getNotificationHeader());
return;
}
final NotificationContentView layout = row.getPrivateLayout();
@@ -171,13 +169,11 @@ public class NotificationHeaderUtil {
private void sanitizeChild(View child) {
if (child != null) {
- ViewGroup header = child.findViewById(
- com.android.internal.R.id.notification_top_line);
- sanitizeHeader(header);
+ sanitizeTopLine(child.findViewById(R.id.notification_top_line));
}
}
- private void sanitizeHeader(ViewGroup rowHeader) {
+ private void sanitizeTopLine(ViewGroup rowHeader) {
if (rowHeader == null) {
return;
}
@@ -225,28 +221,31 @@ public class NotificationHeaderUtil {
}
}
- public void restoreNotificationHeader(ExpandableNotificationRow row) {
- for (int compI = 0; compI < mComparators.size(); compI++) {
- mComparators.get(compI).apply(row, true /* reset */);
+ /**
+ * Reset the modifications to this row for removing it from the group.
+ */
+ public void restoreChildNotification(ExpandableNotificationRow row) {
+ for (int compI = 0; compI < mProcessors.size(); compI++) {
+ mProcessors.get(compI).apply(row, true /* reset */);
}
- sanitizeHeaderViews(row);
+ sanitizeTopLineViews(row);
}
- private static class HeaderProcessor {
+ private static class Processor {
private final int mId;
private final DataExtractor mExtractor;
+ private final ViewComparator mComparator;
private final ResultApplicator mApplicator;
private final ExpandableNotificationRow mParentRow;
private boolean mApply;
private View mParentView;
- private ViewComparator mComparator;
private Object mParentData;
- public static HeaderProcessor forTextView(ExpandableNotificationRow row, int id) {
- return new HeaderProcessor(row, id, null, sTextViewComparator, sVisibilityApplicator);
+ public static Processor forTextView(ExpandableNotificationRow row, int id) {
+ return new Processor(row, id, null, TEXT_VIEW_COMPARATOR, VISIBILITY_APPLICATOR);
}
- HeaderProcessor(ExpandableNotificationRow row, int id, DataExtractor extractor,
+ Processor(ExpandableNotificationRow row, int id, DataExtractor extractor,
ViewComparator comparator,
ResultApplicator applicator) {
mId = id;
@@ -257,12 +256,12 @@ public class NotificationHeaderUtil {
}
public void init() {
- mParentView = mParentRow.getNotificationViewWrapper().getNotificationHeader()
- .findViewById(mId);
+ View header = mParentRow.getNotificationViewWrapper().getNotificationHeader();
+ mParentView = header == null ? null : header.findViewById(mId);
mParentData = mExtractor == null ? null : mExtractor.extractData(mParentRow);
mApply = !mComparator.isEmpty(mParentView);
}
- public void compareToHeader(ExpandableNotificationRow row) {
+ public void compareToGroupParent(ExpandableNotificationRow row) {
if (!mApply) {
return;
}
@@ -308,8 +307,8 @@ public class NotificationHeaderUtil {
private interface ViewComparator {
/**
- * @param parent the parent view
- * @param child the child view
+ * @param parent the view with the given id in the group header
+ * @param child the view with the given id in the child notification
* @param parentData optional data for the parent
* @param childData optional data for the child
* @return whether to views are the same
@@ -322,6 +321,21 @@ public class NotificationHeaderUtil {
Object extractData(ExpandableNotificationRow row);
}
+ private static class BadgeComparator implements ViewComparator {
+ @Override
+ public boolean compare(View parent, View child, Object parentData, Object childData) {
+ return parent.getVisibility() != View.GONE;
+ }
+
+ @Override
+ public boolean isEmpty(View view) {
+ if (view instanceof ImageView) {
+ return ((ImageView) view).getDrawable() == null;
+ }
+ return false;
+ }
+ }
+
private static class TextViewComparator implements ViewComparator {
@Override
public boolean compare(View parent, View child, Object parentData, Object childData) {
@@ -338,7 +352,7 @@ public class NotificationHeaderUtil {
}
}
- private static abstract class IconComparator implements ViewComparator {
+ private abstract static class IconComparator implements ViewComparator {
@Override
public boolean compare(View parent, View child, Object parentData, Object childData) {
return false;
@@ -366,6 +380,12 @@ public class NotificationHeaderUtil {
}
private interface ResultApplicator {
+ /**
+ * @param parent the root view of the child notification
+ * @param view the view with the given id in the child notification
+ * @param apply whether the state should be applied or removed
+ * @param reset if [de]application is the result of a reset
+ */
void apply(View parent, View view, boolean apply, boolean reset);
}
@@ -403,4 +423,54 @@ public class NotificationHeaderUtil {
return super.compare(parent, child, parentData, childData);
}
}
+
+ private static class LeftIconApplicator implements ResultApplicator {
+
+ public static final int[] MARGIN_ADJUSTED_VIEWS = {
+ R.id.notification_headerless_view_column,
+ R.id.line1,
+ R.id.notification_main_column,
+ R.id.notification_header};
+
+ @Override
+ public void apply(View parent, View child, boolean apply, boolean reset) {
+ ImageView rightIcon = child.findViewById(com.android.internal.R.id.right_icon);
+ ImageView leftIcon = child.findViewById(com.android.internal.R.id.left_icon);
+ if (rightIcon == null || leftIcon == null) {
+ return;
+ }
+ Drawable iconDrawable = rightIcon.getDrawable();
+ if (iconDrawable == null) {
+ return;
+ }
+ rightIcon.setVisibility(apply ? View.GONE : View.VISIBLE);
+ leftIcon.setVisibility(apply ? View.VISIBLE : View.GONE);
+ leftIcon.setImageDrawable(apply ? iconDrawable : null);
+
+ for (int viewId : MARGIN_ADJUSTED_VIEWS) {
+ adjustMargins(!apply, child.findViewById(viewId));
+ }
+ }
+
+ void adjustMargins(boolean iconVisible, View target) {
+ if (target == null) {
+ return;
+ }
+ Integer value = (Integer) target.getTag(iconVisible
+ ? com.android.internal.R.id.tag_margin_end_when_icon_visible
+ : com.android.internal.R.id.tag_margin_end_when_icon_gone);
+ if (value == null) {
+ return;
+ }
+ if (target instanceof NotificationHeaderView) {
+ ((NotificationHeaderView) target).setTopLineExtraMarginEnd(value);
+ } else {
+ ViewGroup.LayoutParams layoutParams = target.getLayoutParams();
+ if (layoutParams instanceof ViewGroup.MarginLayoutParams) {
+ ((ViewGroup.MarginLayoutParams) layoutParams).setMarginEnd(value);
+ target.setLayoutParams(layoutParams);
+ }
+ }
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/AnimatableProperty.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/AnimatableProperty.java
index 967524ce308d..ecd0c41ff82d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/AnimatableProperty.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/AnimatableProperty.java
@@ -40,6 +40,14 @@ public abstract class AnimatableProperty {
View.TRANSLATION_X, R.id.x_animator_tag, R.id.x_animator_tag_start_value,
R.id.x_animator_tag_end_value);
+ public static final AnimatableProperty SCALE_X = AnimatableProperty.from(
+ View.SCALE_X, R.id.scale_x_animator_tag, R.id.scale_x_animator_start_value_tag,
+ R.id.scale_x_animator_end_value_tag);
+
+ public static final AnimatableProperty SCALE_Y = AnimatableProperty.from(
+ View.SCALE_Y, R.id.scale_y_animator_tag, R.id.scale_y_animator_start_value_tag,
+ R.id.scale_y_animator_end_value_tag);
+
/**
* Similar to X, however this doesn't allow for any other modifications other than from this
* property. When using X, it's possible that the view is laid out during the animation,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotifications.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotifications.kt
index 44b9bd26aa38..d1ab7ea55d57 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotifications.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotifications.kt
@@ -19,18 +19,25 @@ package com.android.systemui.statusbar.notification
import android.app.Notification
import android.content.Context
import android.content.pm.LauncherApps
+import android.graphics.drawable.AnimatedImageDrawable
import android.os.Handler
import android.service.notification.NotificationListenerService.Ranking
import android.service.notification.NotificationListenerService.RankingMap
import com.android.internal.statusbar.NotificationVisibility
import com.android.internal.widget.ConversationLayout
+import com.android.internal.widget.MessagingImageMessage
+import com.android.internal.widget.MessagingLayout
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
import com.android.systemui.statusbar.notification.row.NotificationContentView
import com.android.systemui.statusbar.notification.stack.StackStateAnimator
+import com.android.systemui.statusbar.policy.HeadsUpManager
+import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener
+import com.android.systemui.util.children
import java.util.concurrent.ConcurrentHashMap
import javax.inject.Inject
@@ -58,6 +65,71 @@ class ConversationNotificationProcessor @Inject constructor(
}
/**
+ * Tracks state related to animated images inside of notifications. Ex: starting and stopping
+ * animations to conserve CPU and memory.
+ */
+@SysUISingleton
+class AnimatedImageNotificationManager @Inject constructor(
+ private val notificationEntryManager: NotificationEntryManager,
+ private val headsUpManager: HeadsUpManager,
+ private val statusBarStateController: StatusBarStateController
+) {
+
+ private var isStatusBarExpanded = false
+
+ /** Begins listening to state changes and updating animations accordingly. */
+ fun bind() {
+ headsUpManager.addListener(object : OnHeadsUpChangedListener {
+ override fun onHeadsUpStateChanged(entry: NotificationEntry, isHeadsUp: Boolean) {
+ entry.row?.let { row ->
+ updateAnimatedImageDrawables(row, animating = isHeadsUp || isStatusBarExpanded)
+ }
+ }
+ })
+ statusBarStateController.addCallback(object : StatusBarStateController.StateListener {
+ override fun onExpandedChanged(isExpanded: Boolean) {
+ isStatusBarExpanded = isExpanded
+ notificationEntryManager.activeNotificationsForCurrentUser.forEach { entry ->
+ entry.row?.let { row ->
+ updateAnimatedImageDrawables(row, animating = isExpanded || row.isHeadsUp)
+ }
+ }
+ }
+ })
+ notificationEntryManager.addNotificationEntryListener(object : NotificationEntryListener {
+ override fun onEntryInflated(entry: NotificationEntry) {
+ entry.row?.let { row ->
+ updateAnimatedImageDrawables(
+ row,
+ animating = isStatusBarExpanded || row.isHeadsUp)
+ }
+ }
+ override fun onEntryReinflated(entry: NotificationEntry) = onEntryInflated(entry)
+ })
+ }
+
+ private fun updateAnimatedImageDrawables(row: ExpandableNotificationRow, animating: Boolean) =
+ (row.layouts?.asSequence() ?: emptySequence())
+ .flatMap { layout -> layout.allViews.asSequence() }
+ .flatMap { view ->
+ (view as? ConversationLayout)?.messagingGroups?.asSequence()
+ ?: (view as? MessagingLayout)?.messagingGroups?.asSequence()
+ ?: emptySequence()
+ }
+ .flatMap { messagingGroup -> messagingGroup.messageContainer.children }
+ .mapNotNull { view ->
+ (view as? MessagingImageMessage)
+ ?.let { imageMessage ->
+ imageMessage.drawable as? AnimatedImageDrawable
+ }
+ }
+ .forEach { animatedImageDrawable ->
+ if (animating) animatedImageDrawable.start()
+ else animatedImageDrawable.stop()
+ }
+}
+
+/**
* Tracks state related to conversation notifications, and updates the UI of existing notifications
* when necessary.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/InstantAppNotifier.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/InstantAppNotifier.java
index 363a08566fd3..1f9bc77b0b2f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/InstantAppNotifier.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/InstantAppNotifier.java
@@ -364,18 +364,13 @@ public class InstantAppNotifier extends SystemUI
@Nullable
private Intent getTaskIntent(int taskId, int userId) {
- try {
- final List<ActivityManager.RecentTaskInfo> tasks =
- ActivityTaskManager.getService()
- .getRecentTasks(NUM_TASKS_FOR_INSTANT_APP_INFO, 0, userId)
- .getList();
- for (int i = 0; i < tasks.size(); i++) {
- if (tasks.get(i).id == taskId) {
- return tasks.get(i).baseIntent;
- }
+ final List<ActivityManager.RecentTaskInfo> tasks =
+ ActivityTaskManager.getInstance().getRecentTasks(
+ NUM_TASKS_FOR_INSTANT_APP_INFO, 0, userId);
+ for (int i = 0; i < tasks.size(); i++) {
+ if (tasks.get(i).id == taskId) {
+ return tasks.get(i).baseIntent;
}
- } catch (RemoteException e) {
- // Fall through
}
return null;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/MediaNotificationProcessor.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/MediaNotificationProcessor.java
index db5458664023..2586e9403e01 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/MediaNotificationProcessor.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/MediaNotificationProcessor.java
@@ -29,7 +29,7 @@ import androidx.annotation.VisibleForTesting;
import androidx.palette.graphics.Palette;
import com.android.internal.util.ContrastColorUtil;
-import com.android.systemui.R;
+import com.android.settingslib.Utils;
import java.util.List;
@@ -143,7 +143,8 @@ public class MediaNotificationProcessor {
int foregroundColor = selectForegroundColor(backgroundColor, palette);
builder.setColorPalette(backgroundColor, foregroundColor);
} else {
- backgroundColor = mContext.getColor(R.color.notification_material_background_color);
+ backgroundColor = Utils.getColorAttr(mContext, android.R.attr.colorBackground)
+ .getDefaultColor();
}
Bitmap colorized = mColorizer.colorize(drawable, backgroundColor,
mContext.getResources().getConfiguration().getLayoutDirection() ==
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt
index 8f352ad55041..54ce4ede9770 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt
@@ -22,6 +22,7 @@ import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper.Snoo
import com.android.systemui.statusbar.FeatureFlags
import com.android.systemui.statusbar.NotificationListener
import com.android.systemui.statusbar.NotificationPresenter
+import com.android.systemui.statusbar.notification.AnimatedImageNotificationManager
import com.android.systemui.statusbar.notification.NotificationActivityStarter
import com.android.systemui.statusbar.notification.NotificationClicker
import com.android.systemui.statusbar.notification.NotificationEntryManager
@@ -71,7 +72,8 @@ class NotificationsControllerImpl @Inject constructor(
private val headsUpManager: HeadsUpManager,
private val headsUpController: HeadsUpController,
private val headsUpViewBinder: HeadsUpViewBinder,
- private val clickerBuilder: NotificationClicker.Builder
+ private val clickerBuilder: NotificationClicker.Builder,
+ private val animatedImageNotificationManager: AnimatedImageNotificationManager
) : NotificationsController {
override fun initialize(
@@ -100,6 +102,7 @@ class NotificationsControllerImpl @Inject constructor(
bindRowCallback)
headsUpViewBinder.setPresenter(presenter)
notifBindPipelineInitializer.initialize()
+ animatedImageNotificationManager.bind()
if (featureFlags.isNewNotifPipelineEnabled) {
newNotifPipeline.get().initialize(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
index 10273cbbebad..86ebc6b2c4ce 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
@@ -34,6 +34,7 @@ import android.view.animation.Interpolator;
import android.view.animation.PathInterpolator;
import com.android.internal.jank.InteractionJankMonitor;
+import com.android.settingslib.Utils;
import com.android.systemui.Gefingerpoken;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
@@ -169,13 +170,14 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
}
private void updateColors() {
- mNormalColor = mContext.getColor(R.color.notification_material_background_color);
+ mNormalColor = Utils.getColorAttr(mContext, android.R.attr.colorBackground)
+ .getDefaultColor();
mTintedRippleColor = mContext.getColor(
R.color.notification_ripple_tinted_color);
mNormalRippleColor = mContext.getColor(
R.color.notification_ripple_untinted_color);
mDimmedAlpha = Color.alpha(mContext.getColor(
- R.color.notification_material_background_dimmed_color));
+ R.color.notification_background_dimmed_color));
}
private void initDimens() {
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 5ed17f1ee07f..10118e4733ba 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
@@ -558,7 +558,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
setChronometerRunning(true);
}
if (mNotificationParent != null) {
- mNotificationParent.updateChildrenHeaderAppearance();
+ mNotificationParent.updateChildrenAppearance();
}
onAttachedChildrenCountChanged();
// The public layouts expand button is always visible
@@ -2337,7 +2337,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
}
getShowingLayout().updateBackgroundColor(false /* animate */);
mPrivateLayout.updateExpandButtons(isExpandable());
- updateChildrenHeaderAppearance();
+ updateChildrenAppearance();
updateChildrenVisibility();
applyChildrenRoundness();
}
@@ -2382,9 +2382,12 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
return channels;
}
- public void updateChildrenHeaderAppearance() {
+ /**
+ * If this is a group, update the appearance of the children.
+ */
+ public void updateChildrenAppearance() {
if (mIsSummaryWithChildren) {
- mChildrenContainer.updateChildrenHeaderAppearance();
+ mChildrenContainer.updateChildrenAppearance();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGuts.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGuts.java
index 7071b73c2ebf..8ac5b933e4f9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGuts.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGuts.java
@@ -19,7 +19,6 @@ package com.android.systemui.statusbar.notification.row;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.content.Context;
-import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
@@ -35,7 +34,6 @@ import android.widget.FrameLayout;
import androidx.annotation.Nullable;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.systemui.Dependency;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
@@ -168,9 +166,6 @@ public class NotificationGuts extends FrameLayout {
}
}
};
- final TypedArray ta = context.obtainStyledAttributes(attrs,
- com.android.internal.R.styleable.Theme, 0, 0);
- ta.recycle();
}
public NotificationGuts(Context context) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageResolver.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageResolver.java
index 7bd192d850c1..44ccb68cce4a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageResolver.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageResolver.java
@@ -19,10 +19,7 @@ package com.android.systemui.statusbar.notification.row;
import android.app.ActivityManager;
import android.app.Notification;
import android.content.Context;
-import android.graphics.Bitmap;
-import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
-import android.graphics.drawable.Icon;
import android.net.Uri;
import android.os.Bundle;
import android.os.Parcelable;
@@ -81,7 +78,7 @@ public class NotificationInlineImageResolver implements ImageResolver {
* @return True if has its internal cache, false otherwise.
*/
public boolean hasCache() {
- return mImageCache != null && !ActivityManager.isLowRamDeviceStatic();
+ return mImageCache != null && !isLowRam();
}
private boolean isLowRam() {
@@ -110,11 +107,6 @@ public class NotificationInlineImageResolver implements ImageResolver {
: R.dimen.notification_custom_view_max_image_height);
}
- @VisibleForTesting
- protected BitmapDrawable resolveImageInternal(Uri uri) throws IOException {
- return (BitmapDrawable) LocalImageResolver.resolveImage(uri, mContext);
- }
-
/**
* To resolve image from specified uri directly. If the resulting image is larger than the
* maximum allowed size, scale it down.
@@ -123,13 +115,7 @@ public class NotificationInlineImageResolver implements ImageResolver {
* @throws IOException Throws if failed at resolving the image.
*/
Drawable resolveImage(Uri uri) throws IOException {
- BitmapDrawable image = resolveImageInternal(uri);
- if (image == null || image.getBitmap() == null) {
- throw new IOException("resolveImageInternal returned null for uri: " + uri);
- }
- Bitmap bitmap = image.getBitmap();
- image.setBitmap(Icon.scaleDownIfNecessary(bitmap, mMaxImageWidth, mMaxImageHeight));
- return image;
+ return LocalImageResolver.resolveImage(uri, mContext, mMaxImageWidth, mMaxImageHeight);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java
index 05db67d706cf..37d5da24a704 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java
@@ -64,6 +64,7 @@ public class NotificationHeaderViewWrapper extends NotificationViewWrapper {
private ImageView mWorkProfileImage;
private View mAudiblyAlertedIcon;
private View mFeedbackIcon;
+ private View mLeftIcon;
private View mRightIcon;
private boolean mIsLowPriority;
@@ -108,6 +109,7 @@ public class NotificationHeaderViewWrapper extends NotificationViewWrapper {
mAppNameText = mView.findViewById(com.android.internal.R.id.app_name_text);
mExpandButton = mView.findViewById(com.android.internal.R.id.expand_button);
mAltExpandTarget = mView.findViewById(com.android.internal.R.id.alternate_expand_target);
+ mLeftIcon = mView.findViewById(com.android.internal.R.id.left_icon);
mRightIcon = mView.findViewById(com.android.internal.R.id.right_icon);
mWorkProfileImage = mView.findViewById(com.android.internal.R.id.profile_badge);
mNotificationHeader = mView.findViewById(com.android.internal.R.id.notification_header);
@@ -146,6 +148,9 @@ public class NotificationHeaderViewWrapper extends NotificationViewWrapper {
updateCropToPaddingForImageViews();
Notification notification = row.getEntry().getSbn().getNotification();
mIcon.setTag(ImageTransformState.ICON_TAG, notification.getSmallIcon());
+ if (mLeftIcon != null) {
+ mLeftIcon.setClipToOutline(true);
+ }
if (mRightIcon != null) {
mRightIcon.setClipToOutline(true);
}
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 6920e3f4a7c6..416c5af93400 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
@@ -38,6 +38,7 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.graphics.ColorUtils;
import com.android.internal.util.ContrastColorUtil;
import com.android.internal.widget.CachingIconView;
+import com.android.settingslib.Utils;
import com.android.systemui.statusbar.CrossFadeHelper;
import com.android.systemui.statusbar.TransformableView;
import com.android.systemui.statusbar.notification.TransformState;
@@ -324,8 +325,8 @@ public abstract class NotificationViewWrapper implements TransformableView {
if (customBackgroundColor != 0) {
return customBackgroundColor;
}
- return mView.getContext().getColor(
- com.android.internal.R.color.notification_material_background_color);
+ return Utils.getColorAttr(mView.getContext(), android.R.attr.colorBackground)
+ .getDefaultColor();
}
public void setLegacy(boolean legacy) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
index b04f94ce9c1d..601fc197cfa6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
@@ -34,7 +34,7 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.widget.CachingIconView;
import com.android.systemui.R;
import com.android.systemui.statusbar.CrossFadeHelper;
-import com.android.systemui.statusbar.NotificationHeaderUtil;
+import com.android.systemui.statusbar.NotificationGroupingUtil;
import com.android.systemui.statusbar.notification.NotificationUtils;
import com.android.systemui.statusbar.notification.collection.legacy.VisualStabilityManager;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
@@ -94,7 +94,7 @@ public class NotificationChildrenContainer extends ViewGroup {
private NotificationViewWrapper mNotificationHeaderWrapper;
private NotificationHeaderView mNotificationHeaderLowPriority;
private NotificationViewWrapper mNotificationHeaderWrapperLowPriority;
- private NotificationHeaderUtil mHeaderUtil;
+ private NotificationGroupingUtil mGroupingUtil;
private ViewState mHeaderViewState;
private int mClipBottomAmount;
private boolean mIsLowPriority;
@@ -299,7 +299,7 @@ public class NotificationChildrenContainer extends ViewGroup {
row.setSystemChildExpanded(false);
row.setUserLocked(false);
if (!row.isRemoved()) {
- mHeaderUtil.restoreNotificationHeader(row);
+ mGroupingUtil.restoreChildNotification(row);
}
}
@@ -341,7 +341,7 @@ public class NotificationChildrenContainer extends ViewGroup {
}
recreateLowPriorityHeader(builder, isConversation);
updateHeaderVisibility(false /* animate */);
- updateChildrenHeaderAppearance();
+ updateChildrenAppearance();
}
/**
@@ -389,8 +389,11 @@ public class NotificationChildrenContainer extends ViewGroup {
}
}
- public void updateChildrenHeaderAppearance() {
- mHeaderUtil.updateChildrenHeaderAppearance();
+ /**
+ * Update the appearance of the children to reduce redundancies.
+ */
+ public void updateChildrenAppearance() {
+ mGroupingUtil.updateChildrenAppearance();
}
public void updateGroupOverflow() {
@@ -861,7 +864,7 @@ public class NotificationChildrenContainer extends ViewGroup {
public void setContainingNotification(ExpandableNotificationRow parent) {
mContainingNotification = parent;
- mHeaderUtil = new NotificationHeaderUtil(mContainingNotification);
+ mGroupingUtil = new NotificationGroupingUtil(mContainingNotification);
}
public ExpandableNotificationRow getContainingNotification() {
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 ba5f95e9c4d8..5cc17a08504f 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
@@ -50,7 +50,6 @@ import android.util.DisplayMetrics;
import android.util.Log;
import android.util.MathUtils;
import android.util.Pair;
-import android.view.ContextThemeWrapper;
import android.view.DisplayCutout;
import android.view.InputDevice;
import android.view.LayoutInflater;
@@ -385,7 +384,6 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
*/
private float mBackgroundXFactor = 1f;
- private boolean mUsingLightTheme;
private boolean mQsExpanded;
private boolean mForwardScrollable;
private boolean mBackwardScrollable;
@@ -4122,15 +4120,9 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
* @param lightTheme True if light theme should be used.
*/
@ShadeViewRefactor(RefactorComponent.DECORATOR)
- void updateDecorViews(boolean lightTheme) {
- if (lightTheme == mUsingLightTheme) {
- return;
- }
- mUsingLightTheme = lightTheme;
- Context context = new ContextThemeWrapper(mContext,
- lightTheme ? R.style.Theme_SystemUI_Light : R.style.Theme_SystemUI);
+ void updateDecorViews() {
final @ColorInt int textColor =
- Utils.getColorAttrDefaultColor(context, R.attr.wallpaperTextColor);
+ Utils.getColorAttrDefaultColor(mContext, android.R.attr.textColorPrimary);
mSectionsManager.setHeaderForegroundColor(textColor);
mFooterView.setTextColor(textColor);
mEmptyShadeView.setTextColor(textColor);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
index abbbbb8352f5..8a0330912502 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
@@ -162,7 +162,6 @@ public class NotificationStackScrollLayoutController {
private final KeyguardMediaController mKeyguardMediaController;
private final SysuiStatusBarStateController mStatusBarStateController;
private final KeyguardBypassController mKeyguardBypassController;
- private final SysuiColorExtractor mColorExtractor;
private final NotificationLockscreenUserManager mLockscreenUserManager;
// TODO: StatusBar should be encapsulated behind a Controller
private final StatusBar mStatusBar;
@@ -224,12 +223,14 @@ public class NotificationStackScrollLayoutController {
public void onOverlayChanged() {
updateShowEmptyShadeView();
mView.updateCornerRadius();
+ mView.updateBgColor();
mView.reinflateViews();
}
@Override
public void onUiModeChanged() {
mView.updateBgColor();
+ mView.updateDecorViews();
}
@Override
@@ -577,7 +578,6 @@ public class NotificationStackScrollLayoutController {
mKeyguardMediaController = keyguardMediaController;
mKeyguardBypassController = keyguardBypassController;
mZenModeController = zenModeController;
- mColorExtractor = colorExtractor;
mLockscreenUserManager = lockscreenUserManager;
mMetricsLogger = metricsLogger;
mFalsingCollector = falsingCollector;
@@ -689,12 +689,6 @@ public class NotificationStackScrollLayoutController {
Settings.Secure.NOTIFICATION_DISMISS_RTL,
Settings.Secure.NOTIFICATION_HISTORY_ENABLED);
- mOnColorsChangedListener = (colorExtractor, which) -> {
- final boolean useDarkText = mColorExtractor.getNeutralColors().supportsDarkText();
- mView.updateDecorViews(useDarkText);
- };
- mColorExtractor.addOnColorsChangedListener(mOnColorsChangedListener);
-
mKeyguardMediaController.setVisibilityChangedListener(visible -> {
mView.setKeyguardMediaControllorVisible(visible);
if (visible) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
index 7508dcb487ed..1a2d1cfdcfb4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
@@ -17,6 +17,7 @@
package com.android.systemui.statusbar.phone;
import static com.android.systemui.doze.util.BurnInHelperKt.getBurnInOffset;
+import static com.android.systemui.doze.util.BurnInHelperKt.getBurnInScale;
import static com.android.systemui.statusbar.notification.NotificationUtils.interpolate;
import android.content.res.Resources;
@@ -184,6 +185,7 @@ public class KeyguardClockPositionAlgorithm {
result.stackScrollerPaddingExpanded = mBypassEnabled ? mUnlockedStackScrollerPadding
: getClockY(1.0f) + mKeyguardStatusHeight;
result.clockX = (int) interpolate(0, burnInPreventionOffsetX(), mDarkAmount);
+ result.clockScale = interpolate(getBurnInScale(), 1.0f, 1.0f - mDarkAmount);
}
/**
@@ -304,6 +306,11 @@ public class KeyguardClockPositionAlgorithm {
public float clockAlpha;
/**
+ * Amount to scale the large clock (0.0 - 1.0)
+ */
+ public float clockScale;
+
+ /**
* The top padding of the stack scroller, in pixels.
*/
public int stackScrollerPadding;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
index 54fb863b5de7..0df3347b8f89 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
@@ -49,7 +49,7 @@ public class LockIcon extends KeyguardAffordanceView {
static final int STATE_SCANNING_FACE = 2;
static final int STATE_BIOMETRICS_ERROR = 3;
private float mDozeAmount;
- private int mIconColor;
+ private int mIconColor = Color.TRANSPARENT;
private int mOldState;
private int mState;
private boolean mDozing;
@@ -149,7 +149,10 @@ public class LockIcon extends KeyguardAffordanceView {
updateDarkTint();
}
- void onThemeChange(int iconColor) {
+ void updateColor(int iconColor) {
+ if (mIconColor == iconColor) {
+ return;
+ }
mDrawableCache.clear();
mIconColor = iconColor;
updateDarkTint();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenLockIconController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenLockIconController.java
index 289ff71dcb46..0e7e2fd8173c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenLockIconController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenLockIconController.java
@@ -84,6 +84,7 @@ public class LockscreenLockIconController {
private boolean mDocked;
private boolean mWakeAndUnlockRunning;
private boolean mShowingLaunchAffordance;
+ private boolean mBouncerShowing;
private boolean mBouncerShowingScrimmed;
private boolean mFingerprintUnlock;
private int mStatusBarState = StatusBarState.SHADE;
@@ -142,16 +143,13 @@ public class LockscreenLockIconController {
private int mDensity;
@Override
- public void onThemeChanged() {
- if (mLockIcon == null) {
- return;
- }
+ public void onUiModeChanged() {
+ updateColor();
+ }
- TypedArray typedArray = mLockIcon.getContext().getTheme().obtainStyledAttributes(
- null, new int[]{ R.attr.wallpaperTextColor }, 0, 0);
- int iconColor = typedArray.getColor(0, Color.WHITE);
- typedArray.recycle();
- mLockIcon.onThemeChange(iconColor);
+ @Override
+ public void onOverlayChanged() {
+ updateColor();
}
@Override
@@ -350,6 +348,7 @@ public class LockscreenLockIconController {
*/
public void attach(LockIcon lockIcon) {
mLockIcon = lockIcon;
+ updateColor();
mLockIcon.setOnClickListener(this::handleClick);
mLockIcon.setOnLongClickListener(this::handleLongClick);
@@ -408,11 +407,22 @@ public class LockscreenLockIconController {
}
/** Sets whether the bouncer is showing. */
- public void setBouncerShowingScrimmed(boolean bouncerShowing) {
- mBouncerShowingScrimmed = bouncerShowing;
- if (mKeyguardBypassController.getBypassEnabled()) {
- update();
+ public void setBouncerShowingScrimmed(boolean showing, boolean scrimmed) {
+ mBouncerShowing = showing;
+ mBouncerShowingScrimmed = scrimmed;
+ update();
+ }
+
+ private void updateColor() {
+ if (mLockIcon == null) {
+ return;
}
+
+ TypedArray typedArray = mLockIcon.getContext().getTheme().obtainStyledAttributes(
+ null, new int[]{ android.R.attr.textColorPrimary }, 0, 0);
+ int iconColor = typedArray.getColor(0, Color.WHITE);
+ typedArray.recycle();
+ mLockIcon.updateColor(iconColor);
}
/**
@@ -510,7 +520,10 @@ public class LockscreenLockIconController {
return changed;
}
boolean onAodOrDocked = mStatusBarStateController.isDozing() || mDocked;
- boolean invisible = onAodOrDocked || mWakeAndUnlockRunning || mShowingLaunchAffordance;
+ boolean onKeyguardWithoutBouncer = mStatusBarState == StatusBarState.KEYGUARD
+ && !mBouncerShowing;
+ boolean invisible = onAodOrDocked || mWakeAndUnlockRunning || mShowingLaunchAffordance
+ || onKeyguardWithoutBouncer;
boolean fingerprintOrBypass = mFingerprintUnlock
|| mKeyguardBypassController.getBypassEnabled();
if (fingerprintOrBypass && !mBouncerShowingScrimmed) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
index f7139aa2acce..9c70d52d4076 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -68,6 +68,7 @@ import com.android.internal.jank.InteractionJankMonitor;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.util.LatencyTracker;
+import com.android.keyguard.DisabledUdfpsController;
import com.android.keyguard.KeyguardClockSwitchController;
import com.android.keyguard.KeyguardStatusView;
import com.android.keyguard.KeyguardStatusViewController;
@@ -85,6 +86,7 @@ import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.doze.DozeLog;
import com.android.systemui.fragments.FragmentHostManager;
import com.android.systemui.fragments.FragmentHostManager.FragmentListener;
+import com.android.systemui.media.MediaDataManager;
import com.android.systemui.media.MediaHierarchyManager;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.qs.QS;
@@ -139,6 +141,7 @@ import java.util.function.Consumer;
import java.util.function.Function;
import javax.inject.Inject;
+import javax.inject.Provider;
@StatusBarComponent.StatusBarScope
public class NotificationPanelViewController extends PanelViewController {
@@ -183,7 +186,7 @@ public class NotificationPanelViewController extends PanelViewController {
private final MetricsLogger mMetricsLogger;
private final ActivityManager mActivityManager;
private final ConfigurationController mConfigurationController;
- private final FlingAnimationUtils.Builder mFlingAnimationUtilsBuilder;
+ private final Provider<FlingAnimationUtils.Builder> mFlingAnimationUtilsBuilder;
private final NotificationStackScrollLayoutController mNotificationStackScrollLayoutController;
private final NotificationIconAreaController mNotificationIconAreaController;
@@ -256,7 +259,25 @@ public class NotificationPanelViewController extends PanelViewController {
mFirstBypassAttempt = mKeyguardBypassController.getBypassEnabled();
mDelayShowingKeyguardStatusBar = false;
}
- };
+
+ @Override
+ public void onKeyguardVisibilityChanged(boolean showing) {
+ if (mDisabledUdfpsController == null
+ && mAuthController.getUdfpsRegion() != null
+ && mAuthController.isUdfpsEnrolled(
+ KeyguardUpdateMonitor.getCurrentUser())) {
+ LayoutInflater.from(mView.getContext())
+ .inflate(R.layout.disabled_udfps_view, mView);
+ mDisabledUdfpsController = new DisabledUdfpsController(
+ mView.findViewById(R.id.disabled_udfps_view),
+ mStatusBarStateController,
+ mUpdateMonitor,
+ mAuthController,
+ mStatusBarKeyguardViewManager);
+ mDisabledUdfpsController.init();
+ }
+ }
+ };
private final InjectionInflationController mInjectionInflationController;
private final PowerManager mPowerManager;
@@ -284,7 +305,7 @@ public class NotificationPanelViewController extends PanelViewController {
private QS mQs;
private FrameLayout mQsFrame;
private KeyguardStatusViewController mKeyguardStatusViewController;
- private View mQsNavbarScrim;
+ private DisabledUdfpsController mDisabledUdfpsController;
private NotificationsQuickSettingsContainer mNotificationContainerParent;
private boolean mAnimateNextPositionUpdate;
@@ -435,6 +456,7 @@ public class NotificationPanelViewController extends PanelViewController {
private final CommandQueue mCommandQueue;
private final NotificationLockscreenUserManager mLockscreenUserManager;
private final ShadeController mShadeController;
+ private final MediaDataManager mMediaDataManager;
private int mDisplayId;
/**
@@ -515,7 +537,7 @@ public class NotificationPanelViewController extends PanelViewController {
KeyguardUpdateMonitor keyguardUpdateMonitor, MetricsLogger metricsLogger,
ActivityManager activityManager,
ConfigurationController configurationController,
- FlingAnimationUtils.Builder flingAnimationUtilsBuilder,
+ Provider<FlingAnimationUtils.Builder> flingAnimationUtilsBuilder,
StatusBarTouchableRegionManager statusBarTouchableRegionManager,
ConversationNotificationManager conversationNotificationManager,
MediaHierarchyManager mediaHierarchyManager,
@@ -526,10 +548,11 @@ public class NotificationPanelViewController extends PanelViewController {
NotificationGroupManagerLegacy groupManager,
NotificationIconAreaController notificationIconAreaController,
AuthController authController,
- QSDetailDisplayer qsDetailDisplayer) {
+ QSDetailDisplayer qsDetailDisplayer,
+ MediaDataManager mediaDataManager) {
super(view, falsingManager, dozeLog, keyguardStateController,
(SysuiStatusBarStateController) statusBarStateController, vibratorHelper,
- latencyTracker, flingAnimationUtilsBuilder, statusBarTouchableRegionManager);
+ latencyTracker, flingAnimationUtilsBuilder.get(), statusBarTouchableRegionManager);
mView = view;
mMetricsLogger = metricsLogger;
mActivityManager = activityManager;
@@ -556,6 +579,7 @@ public class NotificationPanelViewController extends PanelViewController {
mPulseExpansionHandler = pulseExpansionHandler;
mDozeParameters = dozeParameters;
mBiometricUnlockController = biometricUnlockController;
+ mMediaDataManager = mediaDataManager;
pulseExpansionHandler.setPulseExpandAbortListener(() -> {
if (mQs != null) {
mQs.animateHeaderSlidingOut();
@@ -630,7 +654,6 @@ public class NotificationPanelViewController extends PanelViewController {
mOnEmptySpaceClickListener);
addTrackingHeadsUpListener(mNotificationStackScrollLayoutController::setTrackingHeadsUp);
mKeyguardBottomArea = mView.findViewById(R.id.keyguard_bottom_area);
- mQsNavbarScrim = mView.findViewById(R.id.qs_navbar_scrim);
mLastOrientation = mResources.getConfiguration().orientation;
initBottomArea();
@@ -668,7 +691,7 @@ public class NotificationPanelViewController extends PanelViewController {
@Override
protected void loadDimens() {
super.loadDimens();
- mFlingAnimationUtils = mFlingAnimationUtilsBuilder.reset()
+ mFlingAnimationUtils = mFlingAnimationUtilsBuilder.get()
.setMaxLengthSeconds(0.4f).build();
mStatusBarMinHeight = mResources.getDimensionPixelSize(
com.android.internal.R.dimen.status_bar_height);
@@ -872,7 +895,8 @@ public class NotificationPanelViewController extends PanelViewController {
int clockPreferredY = mKeyguardStatusViewController.getClockPreferredY(totalHeight);
boolean bypassEnabled = mKeyguardBypassController.getBypassEnabled();
final boolean hasVisibleNotifications = !bypassEnabled
- && mNotificationStackScrollLayoutController.getVisibleNotificationCount() != 0;
+ && (mNotificationStackScrollLayoutController.getVisibleNotificationCount() != 0
+ || mMediaDataManager.hasActiveMedia());
mKeyguardStatusViewController.setHasVisibleNotifications(hasVisibleNotifications);
mClockPositionAlgorithm.setup(mStatusBarMinHeight, totalHeight - bottomPadding,
mNotificationStackScrollLayoutController.getIntrinsicContentHeight(),
@@ -888,7 +912,8 @@ public class NotificationPanelViewController extends PanelViewController {
mUpdateMonitor.isUdfpsEnrolled());
mClockPositionAlgorithm.run(mClockPositionResult);
mKeyguardStatusViewController.updatePosition(
- mClockPositionResult.clockX, mClockPositionResult.clockY, animateClock);
+ mClockPositionResult.clockX, mClockPositionResult.clockY,
+ mClockPositionResult.clockScale, animateClock);
updateNotificationTranslucency();
updateClock();
stackScrollerPadding = mClockPositionResult.stackScrollerPaddingExpanded;
@@ -1709,9 +1734,6 @@ public class NotificationPanelViewController extends PanelViewController {
mBarState != KEYGUARD && (!mQsExpanded
|| mQsExpansionFromOverscroll));
- mQsNavbarScrim.setVisibility(
- mBarState == StatusBarState.SHADE && mQsExpanded && !mStackScrollerOverscrolling
- && mQsScrimEnabled ? View.VISIBLE : View.INVISIBLE);
if (mKeyguardUserSwitcher != null && mQsExpanded && !mStackScrollerOverscrolling) {
mKeyguardUserSwitcher.hideIfNotSimple(true /* animate */);
}
@@ -1736,10 +1758,6 @@ public class NotificationPanelViewController extends PanelViewController {
updateKeyguardBottomAreaAlpha();
updateBigClockAlpha();
}
- if (mBarState == StatusBarState.SHADE && mQsExpanded && !mStackScrollerOverscrolling
- && mQsScrimEnabled) {
- mQsNavbarScrim.setAlpha(getQsExpansionFraction());
- }
if (mAccessibilityManager.isEnabled()) {
mView.setAccessibilityPaneTitle(determineAccessibilityPaneTitle());
@@ -3044,6 +3062,9 @@ public class NotificationPanelViewController extends PanelViewController {
if (mKeyguardStatusBar != null) {
mKeyguardStatusBar.dump(fd, pw, args);
}
+ if (mDisabledUdfpsController != null) {
+ mDisabledUdfpsController.dump(fd, pw, args);
+ }
}
public boolean hasActiveClearableNotifications() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index 4af27877c201..9e7efc12f4f7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -37,22 +37,21 @@ import android.view.animation.Interpolator;
import androidx.annotation.Nullable;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.colorextraction.ColorExtractor;
import com.android.internal.colorextraction.ColorExtractor.GradientColors;
-import com.android.internal.colorextraction.ColorExtractor.OnColorsChangedListener;
import com.android.internal.graphics.ColorUtils;
import com.android.internal.util.function.TriConsumer;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
+import com.android.settingslib.Utils;
import com.android.systemui.DejankUtils;
import com.android.systemui.Dumpable;
import com.android.systemui.R;
-import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dock.DockManager;
import com.android.systemui.statusbar.BlurUtils;
import com.android.systemui.statusbar.ScrimView;
import com.android.systemui.statusbar.notification.stack.ViewState;
+import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.AlarmTimeout;
import com.android.systemui.util.wakelock.DelayedWakeLock;
@@ -71,8 +70,7 @@ import javax.inject.Inject;
* security method gets shown).
*/
@SysUISingleton
-public class ScrimController implements ViewTreeObserver.OnPreDrawListener, OnColorsChangedListener,
- Dumpable {
+public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dumpable {
static final String TAG = "ScrimController";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
@@ -125,12 +123,12 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, OnCo
* The default scrim under the shade and dialogs.
* This should not be lower than 0.54, otherwise we won't pass GAR.
*/
- public static final float BUSY_SCRIM_ALPHA = 0.85f;
+ public static final float BUSY_SCRIM_ALPHA = 1f;
/**
* Same as above, but when blur is supported.
*/
- public static final float BLUR_SCRIM_ALPHA = 0.54f;
+ public static final float BLUR_SCRIM_ALPHA = 0.80f;
static final int TAG_KEY_ANIM = R.id.scrim;
private static final int TAG_START_ALPHA = R.id.scrim_alpha_start;
@@ -153,8 +151,8 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, OnCo
private final AlarmTimeout mTimeTicker;
private final KeyguardVisibilityCallback mKeyguardVisibilityCallback;
private final Handler mHandler;
+ private final BlurUtils mBlurUtils;
- private final SysuiColorExtractor mColorExtractor;
private GradientColors mColors;
private boolean mNeedsDrawableColorUpdate;
@@ -204,12 +202,13 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, OnCo
public ScrimController(LightBarController lightBarController, DozeParameters dozeParameters,
AlarmManager alarmManager, KeyguardStateController keyguardStateController,
DelayedWakeLock.Builder delayedWakeLockBuilder, Handler handler,
- KeyguardUpdateMonitor keyguardUpdateMonitor, SysuiColorExtractor sysuiColorExtractor,
- DockManager dockManager, BlurUtils blurUtils) {
+ KeyguardUpdateMonitor keyguardUpdateMonitor, DockManager dockManager,
+ BlurUtils blurUtils, ConfigurationController configurationController) {
mScrimStateListener = lightBarController::setScrimState;
mDefaultScrimAlpha = blurUtils.supportsBlursOnWindows()
? BLUR_SCRIM_ALPHA : BUSY_SCRIM_ALPHA;
+ mBlurUtils = blurUtils;
mKeyguardStateController = keyguardStateController;
mDarkenWhileDragging = !mKeyguardStateController.canDismissLockScreen();
@@ -230,11 +229,24 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, OnCo
keyguardStateController.getKeyguardFadingAwayDuration());
}
});
+ configurationController.addCallback(new ConfigurationController.ConfigurationListener() {
+ @Override
+ public void onThemeChanged() {
+ ScrimController.this.onThemeChanged();
+ }
- mColorExtractor = sysuiColorExtractor;
- mColorExtractor.addOnColorsChangedListener(this);
- mColors = mColorExtractor.getNeutralColors();
- mNeedsDrawableColorUpdate = true;
+ @Override
+ public void onOverlayChanged() {
+ ScrimController.this.onThemeChanged();
+ }
+
+ @Override
+ public void onUiModeChanged() {
+ ScrimController.this.onThemeChanged();
+ }
+ });
+
+ mColors = new GradientColors();
}
/**
@@ -245,6 +257,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, OnCo
mScrimBehind = scrimBehind;
mScrimInFront = scrimInFront;
mScrimForBubble = scrimForBubble;
+ updateThemeColors();
if (mScrimBehindChangeRunnable != null) {
mScrimBehind.setChangeRunnable(mScrimBehindChangeRunnable);
@@ -619,11 +632,6 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, OnCo
mScrimInFront.setColors(mColors, animateScrimInFront);
mScrimBehind.setColors(mColors, animateScrimBehind);
- // Calculate minimum scrim opacity for white or black text.
- int textColor = mColors.supportsDarkText() ? Color.BLACK : Color.WHITE;
- int mainColor = mColors.getMainColor();
- float minOpacity = ColorUtils.calculateMinimumBackgroundAlpha(textColor, mainColor,
- 4.5f /* minimumContrast */) / 255f;
dispatchScrimState(mScrimBehind.getViewAlpha());
}
@@ -968,10 +976,19 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, OnCo
// Don't care in the base class.
}
- @Override
- public void onColorsChanged(ColorExtractor colorExtractor, int which) {
- mColors = mColorExtractor.getNeutralColors();
+ private void updateThemeColors() {
+ int background = Utils.getColorAttr(mScrimBehind.getContext(),
+ android.R.attr.colorBackgroundFloating).getDefaultColor();
+ int accent = Utils.getColorAccent(mScrimBehind.getContext()).getDefaultColor();
+ mColors.setMainColor(background);
+ mColors.setSecondaryColor(accent);
+ mColors.setSupportsDarkText(
+ ColorUtils.calculateContrast(mColors.getMainColor(), Color.WHITE) > 4.5);
mNeedsDrawableColorUpdate = true;
+ }
+
+ private void onThemeChanged() {
+ updateThemeColors();
scheduleUpdate();
}
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 c8c5a6331a3b..9e872ab65591 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -3782,7 +3782,8 @@ public class StatusBar extends SystemUI implements DemoMode,
mBouncerShowing = bouncerShowing;
mKeyguardBypassController.setBouncerShowing(bouncerShowing);
mPulseExpansionHandler.setBouncerShowing(bouncerShowing);
- mLockscreenLockIconController.setBouncerShowingScrimmed(isBouncerShowingScrimmed());
+ mLockscreenLockIconController.setBouncerShowingScrimmed(bouncerShowing,
+ isBouncerShowingScrimmed());
if (mStatusBarView != null) mStatusBarView.setBouncerShowing(bouncerShowing);
updateHideIconsForBouncer(true /* animate */);
mCommandQueue.recomputeDisableFlags(mDisplayId, true /* animate */);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
index 79f09158fc67..adbc85b8e2e5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
@@ -42,6 +42,7 @@ import android.text.SpannedString;
import android.text.TextWatcher;
import android.util.AttributeSet;
import android.util.Log;
+import android.view.ContentInfo;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.MotionEvent;
@@ -590,12 +591,12 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
new OnReceiveContentListener() {
@Override
@Nullable
- public Payload onReceiveContent(@NonNull View view,
- @NonNull Payload payload) {
- Map<Boolean, Payload> split = payload.partition(
+ public ContentInfo onReceiveContent(@NonNull View view,
+ @NonNull ContentInfo payload) {
+ Map<Boolean, ContentInfo> split = payload.partition(
item -> item.getUri() != null);
- Payload uriItems = split.get(true);
- Payload remainingItems = split.get(false);
+ ContentInfo uriItems = split.get(true);
+ ContentInfo remainingItems = split.get(false);
if (uriItems != null) {
ClipData clip = uriItems.getClip();
ClipDescription description = clip.getDescription();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
index 2795857383e8..bdf2b0c24ba5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
@@ -71,7 +71,6 @@ public class TvStatusBar extends SystemUI implements CommandQueue.Callbacks {
// Creating AudioRecordingDisclosureBar and just letting it run
new AudioRecordingDisclosureBar(mContext);
}
-
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/notifications/TvNotificationAdapter.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/notifications/TvNotificationAdapter.java
new file mode 100644
index 000000000000..3b1a4db067a3
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/notifications/TvNotificationAdapter.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.tv.notifications;
+
+import android.app.Notification;
+import android.app.PendingIntent;
+import android.service.notification.StatusBarNotification;
+import android.util.Log;
+import android.util.SparseArray;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.android.systemui.R;
+
+/**
+ * Adapter for the VerticalGridView of the TvNotificationsPanelView.
+ */
+public class TvNotificationAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
+ private static final String TAG = "TvNotificationAdapter";
+ private SparseArray<StatusBarNotification> mNotifications;
+
+ public TvNotificationAdapter() {
+ setHasStableIds(true);
+ }
+
+ @NonNull
+ @Override
+ public TvNotificationViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+ View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.tv_notification_item,
+ parent, false);
+ return new TvNotificationViewHolder(view);
+ }
+
+ @Override
+ public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int position) {
+ if (mNotifications == null) {
+ Log.e(TAG, "Could not bind view holder because the notification is missing");
+ return;
+ }
+
+ TvNotificationViewHolder holder = (TvNotificationViewHolder) viewHolder;
+ Notification notification = mNotifications.valueAt(position).getNotification();
+ holder.mTitle.setText(notification.extras.getString(Notification.EXTRA_TITLE));
+ holder.mDetails.setText(notification.extras.getString(Notification.EXTRA_TEXT));
+ holder.mPendingIntent = notification.contentIntent;
+ }
+
+ @Override
+ public int getItemCount() {
+ return mNotifications == null ? 0 : mNotifications.size();
+ }
+
+ @Override
+ public long getItemId(int position) {
+ // the item id is the notification id
+ return mNotifications.keyAt(position);
+ }
+
+ /**
+ * Updates the notifications and calls notifyDataSetChanged().
+ */
+ public void setNotifications(SparseArray<StatusBarNotification> notifications) {
+ this.mNotifications = notifications;
+ notifyDataSetChanged();
+ }
+
+ private static class TvNotificationViewHolder extends RecyclerView.ViewHolder implements
+ View.OnClickListener {
+ final TextView mTitle;
+ final TextView mDetails;
+ PendingIntent mPendingIntent;
+
+ protected TvNotificationViewHolder(View itemView) {
+ super(itemView);
+ mTitle = itemView.findViewById(R.id.tv_notification_title);
+ mDetails = itemView.findViewById(R.id.tv_notification_details);
+ itemView.setOnClickListener(this);
+ }
+
+ @Override
+ public void onClick(View v) {
+ try {
+ if (mPendingIntent != null) {
+ mPendingIntent.send();
+ }
+ } catch (PendingIntent.CanceledException e) {
+ Log.d(TAG, "Pending intent canceled for : " + mPendingIntent);
+ }
+ }
+ }
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/notifications/TvNotificationHandler.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/notifications/TvNotificationHandler.java
new file mode 100644
index 000000000000..d985803c2b39
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/notifications/TvNotificationHandler.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.tv.notifications;
+
+import android.annotation.Nullable;
+import android.app.Notification;
+import android.content.Context;
+import android.service.notification.NotificationListenerService;
+import android.service.notification.StatusBarNotification;
+import android.util.Log;
+import android.util.SparseArray;
+
+import com.android.systemui.SystemUI;
+import com.android.systemui.statusbar.NotificationListener;
+
+import javax.inject.Inject;
+
+/**
+ * Keeps track of the notifications on TV.
+ */
+public class TvNotificationHandler extends SystemUI implements
+ NotificationListener.NotificationHandler {
+ private static final String TAG = "TvNotificationHandler";
+ private final NotificationListener mNotificationListener;
+ private final SparseArray<StatusBarNotification> mNotifications = new SparseArray<>();
+ @Nullable
+ private Listener mUpdateListener;
+
+ @Inject
+ public TvNotificationHandler(Context context, NotificationListener notificationListener) {
+ super(context);
+ mNotificationListener = notificationListener;
+ }
+
+ public SparseArray<StatusBarNotification> getCurrentNotifications() {
+ return mNotifications;
+ }
+
+ public void setTvNotificationListener(Listener listener) {
+ mUpdateListener = listener;
+ }
+
+ @Override
+ public void start() {
+ mNotificationListener.addNotificationHandler(this);
+ mNotificationListener.registerAsSystemService();
+ }
+
+ @Override
+ public void onNotificationPosted(StatusBarNotification sbn,
+ NotificationListenerService.RankingMap rankingMap) {
+ if (!new Notification.TvExtender(sbn.getNotification()).isAvailableOnTv()) {
+ Log.v(TAG, "Notification not added because it isn't relevant for tv");
+ return;
+ }
+
+ mNotifications.put(sbn.getId(), sbn);
+ if (mUpdateListener != null) {
+ mUpdateListener.notificationsUpdated(mNotifications);
+ }
+ Log.d(TAG, "Notification added");
+ }
+
+ @Override
+ public void onNotificationRemoved(StatusBarNotification sbn,
+ NotificationListenerService.RankingMap rankingMap) {
+
+ if (mNotifications.contains(sbn.getId())) {
+ mNotifications.remove(sbn.getId());
+ Log.d(TAG, "Notification removed");
+
+ if (mUpdateListener != null) {
+ mUpdateListener.notificationsUpdated(mNotifications);
+ }
+ }
+ }
+
+ @Override
+ public void onNotificationRemoved(StatusBarNotification sbn,
+ NotificationListenerService.RankingMap rankingMap, int reason) {
+ onNotificationRemoved(sbn, rankingMap);
+ }
+
+ @Override
+ public void onNotificationRankingUpdate(NotificationListenerService.RankingMap rankingMap) {
+ // noop
+ }
+
+ @Override
+ public void onNotificationsInitialized() {
+ // noop
+ }
+
+ /**
+ * Get notified when the notifications are updated.
+ */
+ interface Listener {
+ void notificationsUpdated(SparseArray<StatusBarNotification> sbns);
+ }
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvNotificationPanel.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/notifications/TvNotificationPanel.java
index 0bd36240a366..477424c55a73 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvNotificationPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/notifications/TvNotificationPanel.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.statusbar.tv;
+package com.android.systemui.statusbar.tv.notifications;
import android.Manifest;
import android.app.NotificationManager;
@@ -59,9 +59,8 @@ public class TvNotificationPanel extends SystemUI implements CommandQueue.Callba
startNotificationHandlerActivity(
new Intent(NotificationManager.ACTION_TOGGLE_NOTIFICATION_HANDLER_PANEL));
} else {
- Log.w(TAG,
- "Not toggling notification panel: config_notificationHandlerPackage is "
- + "empty");
+ openInternalNotificationPanel(
+ NotificationManager.ACTION_TOGGLE_NOTIFICATION_HANDLER_PANEL);
}
}
@@ -71,9 +70,8 @@ public class TvNotificationPanel extends SystemUI implements CommandQueue.Callba
startNotificationHandlerActivity(
new Intent(NotificationManager.ACTION_OPEN_NOTIFICATION_HANDLER_PANEL));
} else {
- Log.w(TAG,
- "Not expanding notification panel: config_notificationHandlerPackage is "
- + "empty");
+ openInternalNotificationPanel(
+ NotificationManager.ACTION_OPEN_NOTIFICATION_HANDLER_PANEL);
}
}
@@ -86,11 +84,17 @@ public class TvNotificationPanel extends SystemUI implements CommandQueue.Callba
closeNotificationIntent.setPackage(mNotificationHandlerPackage);
mContext.sendBroadcastAsUser(closeNotificationIntent, UserHandle.CURRENT);
} else {
- Log.w(TAG,
- "Not closing notification panel: config_notificationHandlerPackage is empty");
+ openInternalNotificationPanel(
+ NotificationManager.ACTION_CLOSE_NOTIFICATION_HANDLER_PANEL);
}
}
+ private void openInternalNotificationPanel(String action) {
+ Intent intent = new Intent(mContext, TvNotificationPanelActivity.class);
+ intent.setAction(action);
+ mContext.startActivityAsUser(intent, UserHandle.SYSTEM);
+ }
+
/**
* Starts the activity intent if all of the following are true
* <ul>
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/notifications/TvNotificationPanelActivity.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/notifications/TvNotificationPanelActivity.java
new file mode 100644
index 000000000000..30f401b91d25
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/notifications/TvNotificationPanelActivity.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.tv.notifications;
+
+import android.annotation.NonNull;
+import android.app.Activity;
+import android.app.NotificationManager;
+import android.content.Intent;
+import android.os.Bundle;
+import android.service.notification.StatusBarNotification;
+import android.util.SparseArray;
+import android.view.View;
+
+import androidx.leanback.widget.VerticalGridView;
+
+import com.android.systemui.R;
+
+import javax.inject.Inject;
+
+/**
+ * This Activity shows a notification panel for tv. It is used if no other app (e.g. a launcher) can
+ * be found to show the notifications.
+ */
+public class TvNotificationPanelActivity extends Activity implements
+ TvNotificationHandler.Listener {
+ private final TvNotificationHandler mTvNotificationHandler;
+ private TvNotificationAdapter mTvNotificationAdapter;
+ private VerticalGridView mNotificationListView;
+ private View mNotificationPlaceholder;
+ private boolean mPanelAlreadyOpen = false;
+
+ @Inject
+ public TvNotificationPanelActivity(TvNotificationHandler tvNotificationHandler) {
+ super();
+ mTvNotificationHandler = tvNotificationHandler;
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ if (maybeClosePanel(getIntent())) {
+ return;
+ }
+ mPanelAlreadyOpen = true;
+
+ setContentView(R.layout.tv_notification_panel);
+
+ mNotificationPlaceholder = findViewById(R.id.no_tv_notifications);
+ mTvNotificationAdapter = new TvNotificationAdapter();
+
+ mNotificationListView = findViewById(R.id.notifications_list);
+ mNotificationListView.setAdapter(mTvNotificationAdapter);
+ mNotificationListView.setColumnWidth(R.dimen.tv_notification_panel_width);
+
+ mTvNotificationHandler.setTvNotificationListener(this);
+ notificationsUpdated(mTvNotificationHandler.getCurrentNotifications());
+ }
+
+ @Override
+ public void notificationsUpdated(@NonNull SparseArray<StatusBarNotification> notificationList) {
+ mTvNotificationAdapter.setNotifications(notificationList);
+
+ boolean noNotifications = notificationList.size() == 0;
+ mNotificationListView.setVisibility(noNotifications ? View.GONE : View.VISIBLE);
+ mNotificationPlaceholder.setVisibility(noNotifications ? View.VISIBLE : View.GONE);
+ }
+
+ @Override
+ public void onNewIntent(Intent intent) {
+ super.onNewIntent(intent);
+ maybeClosePanel(intent);
+ }
+
+ /**
+ * Handles intents from onCreate and onNewIntent.
+ *
+ * @return true if the panel is being closed, false if it is being opened
+ */
+ private boolean maybeClosePanel(Intent intent) {
+ if (NotificationManager.ACTION_CLOSE_NOTIFICATION_HANDLER_PANEL.equals(intent.getAction())
+ || (mPanelAlreadyOpen
+ && NotificationManager.ACTION_TOGGLE_NOTIFICATION_HANDLER_PANEL.equals(
+ intent.getAction()))) {
+ finish();
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ mTvNotificationHandler.setTvNotificationListener(null);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayApplier.java b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayApplier.java
index 0aa2a739eb82..50cef781d9d0 100644
--- a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayApplier.java
+++ b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayApplier.java
@@ -47,7 +47,7 @@ import java.util.stream.Collectors;
*/
@SysUISingleton
public class ThemeOverlayApplier implements Dumpable {
- private static final String TAG = "ThemeOverlayManager";
+ private static final String TAG = "ThemeOverlayApplier";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
@VisibleForTesting
diff --git a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
index c4e2b5d47ba8..006ecb937922 100644
--- a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
+++ b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
@@ -307,13 +307,13 @@ public class ThemeOverlayController extends SystemUI implements Dumpable {
if (!hasSystemPalette && mSystemOverlayColor != Color.TRANSPARENT) {
categoryToPackage.put(OVERLAY_CATEGORY_SYSTEM_PALETTE,
ThemeOverlayApplier.MONET_SYSTEM_PALETTE_PACKAGE
- + Integer.toHexString(mSystemOverlayColor).toUpperCase());
+ + getColorString(mSystemOverlayColor));
}
// Same for the accent color
if (!hasAccentColor && mAccentOverlayColor != Color.TRANSPARENT) {
categoryToPackage.put(OVERLAY_CATEGORY_ACCENT_COLOR,
ThemeOverlayApplier.MONET_ACCENT_COLOR_PACKAGE
- + Integer.toHexString(mAccentOverlayColor).toUpperCase());
+ + getColorString(mAccentOverlayColor));
}
Set<UserHandle> userHandles = Sets.newHashSet(UserHandle.of(currentUser));
@@ -325,6 +325,14 @@ public class ThemeOverlayController extends SystemUI implements Dumpable {
mThemeManager.applyCurrentUserOverlays(categoryToPackage, userHandles);
}
+ private String getColorString(int color) {
+ String colorString = Integer.toHexString(color).toUpperCase();
+ while (colorString.length() < 6) {
+ colorString = "0" + colorString;
+ }
+ return colorString;
+ }
+
@Override
public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) {
pw.println("mLockColors=" + mLockColors);
diff --git a/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIBinder.java b/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIBinder.java
index 2c3ea4f452bb..353333f714d4 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIBinder.java
@@ -16,14 +16,22 @@
package com.android.systemui.tv;
+import com.android.systemui.SystemUI;
import com.android.systemui.dagger.GlobalRootComponent;
-import com.android.systemui.wmshell.TvPipModule;
+import com.android.systemui.statusbar.tv.notifications.TvNotificationHandler;
import dagger.Binds;
import dagger.Module;
+import dagger.multibindings.ClassKey;
+import dagger.multibindings.IntoMap;
@Module
interface TvSystemUIBinder {
@Binds
GlobalRootComponent bindGlobalRootComponent(TvGlobalRootComponent globalRootComponent);
+
+ @Binds
+ @IntoMap
+ @ClassKey(TvNotificationHandler.class)
+ SystemUI bindTvNotificationHandler(TvNotificationHandler systemui);
}
diff --git a/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java b/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java
index 8ffc7cf568ff..56a4c203e840 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java
@@ -43,6 +43,7 @@ import com.android.systemui.qs.tileimpl.QSFactoryImpl;
import com.android.systemui.recents.Recents;
import com.android.systemui.recents.RecentsImplementation;
import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.statusbar.NotificationListener;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationLockscreenUserManagerImpl;
import com.android.systemui.statusbar.NotificationShadeWindowController;
@@ -62,6 +63,7 @@ import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.DeviceProvisionedControllerImpl;
import com.android.systemui.statusbar.policy.HeadsUpManager;
+import com.android.systemui.statusbar.tv.notifications.TvNotificationHandler;
import javax.inject.Named;
@@ -164,4 +166,11 @@ public abstract class TvSystemUIModule {
@Binds
abstract DozeHost provideDozeHost(DozeServiceHost dozeServiceHost);
+
+ @Provides
+ @SysUISingleton
+ static TvNotificationHandler provideTvNotificationHandler(Context context,
+ NotificationListener notificationListener) {
+ return new TvNotificationHandler(context, notificationListener);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
index 411fbc3ad64c..a879a1ef4b77 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
@@ -53,7 +53,6 @@ import com.android.systemui.statusbar.policy.UserInfoController;
import com.android.systemui.tracing.ProtoTracer;
import com.android.systemui.tracing.nano.SystemUiTraceProto;
import com.android.wm.shell.ShellCommandHandler;
-import com.android.wm.shell.apppairs.AppPairs;
import com.android.wm.shell.hidedisplaycutout.HideDisplayCutout;
import com.android.wm.shell.nano.WmShellTraceProto;
import com.android.wm.shell.onehanded.OneHanded;
@@ -99,13 +98,11 @@ public final class WMShell extends SystemUI
private final Optional<HideDisplayCutout> mHideDisplayCutoutOptional;
private final ProtoTracer mProtoTracer;
private final Optional<ShellCommandHandler> mShellCommandHandler;
- private final Optional<AppPairs> mAppPairsOptional;
private boolean mIsSysUiStateValid;
private KeyguardUpdateMonitorCallback mSplitScreenKeyguardCallback;
private KeyguardUpdateMonitorCallback mPipKeyguardCallback;
private KeyguardUpdateMonitorCallback mOneHandedKeyguardCallback;
- private KeyguardUpdateMonitorCallback mAppPairsKeyguardCallback;
@Inject
public WMShell(Context context, CommandQueue commandQueue,
@@ -119,8 +116,7 @@ public final class WMShell extends SystemUI
Optional<OneHanded> oneHandedOptional,
Optional<HideDisplayCutout> hideDisplayCutoutOptional,
ProtoTracer protoTracer,
- Optional<ShellCommandHandler> shellCommandHandler,
- Optional<AppPairs> appPairsOptional) {
+ Optional<ShellCommandHandler> shellCommandHandler) {
super(context);
mCommandQueue = commandQueue;
mConfigurationController = configurationController;
@@ -135,7 +131,6 @@ public final class WMShell extends SystemUI
mProtoTracer = protoTracer;
mProtoTracer.add(this);
mShellCommandHandler = shellCommandHandler;
- mAppPairsOptional = appPairsOptional;
}
@Override
@@ -145,7 +140,6 @@ public final class WMShell extends SystemUI
mSplitScreenOptional.ifPresent(this::initSplitScreen);
mOneHandedOptional.ifPresent(this::initOneHanded);
mHideDisplayCutoutOptional.ifPresent(this::initHideDisplayCutout);
- mAppPairsOptional.ifPresent(this::initAppPairs);
}
@VisibleForTesting
@@ -294,16 +288,6 @@ public final class WMShell extends SystemUI
});
}
- void initAppPairs(AppPairs appPairs) {
- mAppPairsKeyguardCallback = new KeyguardUpdateMonitorCallback() {
- @Override
- public void onKeyguardVisibilityChanged(boolean showing) {
- appPairs.onKeyguardVisibilityChanged(showing);
- }
- };
- mKeyguardUpdateMonitor.registerCallback(mAppPairsKeyguardCallback);
- }
-
@Override
public void writeToProto(SystemUiTraceProto proto) {
if (proto.wmShell == null) {
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java
index 4505b2a87c78..7a1c05890873 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java
@@ -84,10 +84,8 @@ public class WMShellModule {
@WMSingleton
@Provides
static AppPairs provideAppPairs(ShellTaskOrganizer shellTaskOrganizer,
- SyncTransactionQueue syncQueue, DisplayController displayController,
- TaskStackListenerImpl taskStackListener) {
- return new AppPairsController(shellTaskOrganizer, syncQueue, displayController,
- taskStackListener);
+ SyncTransactionQueue syncQueue, DisplayController displayController) {
+ return new AppPairsController(shellTaskOrganizer, syncQueue, displayController);
}
@WMSingleton
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java
index eef38d316775..b03dc94fde33 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java
@@ -34,6 +34,7 @@ import com.android.internal.logging.UiEventLogger;
import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import org.junit.Before;
@@ -80,6 +81,8 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase {
private KeyguardSecurityViewFlipper mSecurityViewFlipper;
@Mock
private KeyguardSecurityViewFlipperController mKeyguardSecurityViewFlipperController;
+ @Mock
+ private ConfigurationController mConfigurationController;
private KeyguardSecurityContainerController mKeyguardSecurityContainerController;
@@ -92,8 +95,8 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase {
mKeyguardSecurityContainerController = new KeyguardSecurityContainerController.Factory(
mView, mAdminSecondaryLockScreenControllerFactory, mLockPatternUtils,
mKeyguardUpdateMonitor, mKeyguardSecurityModel, mMetricsLogger, mUiEventLogger,
- mKeyguardStateController, mKeyguardSecurityViewFlipperController)
- .create(mSecurityCallback);
+ mKeyguardStateController, mKeyguardSecurityViewFlipperController,
+ mConfigurationController).create(mSecurityCallback);
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/TextAnimatorTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/TextAnimatorTest.kt
index 2e8eb0014f30..53d84dba6fb2 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/TextAnimatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/TextAnimatorTest.kt
@@ -17,7 +17,6 @@
package com.android.keyguard
import android.animation.ValueAnimator
-import android.graphics.Paint
import android.testing.AndroidTestingRunner
import android.text.Layout
import android.text.StaticLayout
@@ -53,7 +52,7 @@ class TextAnimatorTest : SysuiTestCase() {
val layout = makeLayout("Hello, World", PAINT[0])
val valueAnimator = mock(ValueAnimator::class.java)
val textInterpolator = mock(TextInterpolator::class.java)
- val paint = arrayListOf(mock(Paint::class.java))
+ val paint = arrayListOf(mock(TextPaint::class.java))
`when`(textInterpolator.targetPaint).thenReturn(paint)
val textAnimator = TextAnimator(layout, {}).apply {
@@ -85,7 +84,7 @@ class TextAnimatorTest : SysuiTestCase() {
val layout = makeLayout("Hello, World", PAINT[0])
val valueAnimator = mock(ValueAnimator::class.java)
val textInterpolator = mock(TextInterpolator::class.java)
- val paint = arrayListOf(mock(Paint::class.java))
+ val paint = arrayListOf(mock(TextPaint::class.java))
`when`(textInterpolator.targetPaint).thenReturn(paint)
val textAnimator = TextAnimator(layout, {}).apply {
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/TextInterpolatorTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/TextInterpolatorTest.kt
index 002ba364e9d4..1206dab7b56d 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/TextInterpolatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/TextInterpolatorTest.kt
@@ -18,11 +18,12 @@ package com.android.keyguard
import android.graphics.Bitmap
import android.graphics.Canvas
-import android.graphics.Paint
import android.testing.AndroidTestingRunner
import android.text.Layout
import android.text.StaticLayout
import android.text.TextPaint
+import android.text.TextDirectionHeuristic
+import android.text.TextDirectionHeuristics
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.google.common.truth.Truth.assertThat
@@ -31,6 +32,7 @@ import org.junit.runner.RunWith
import kotlin.math.ceil
private const val TEXT = "Hello, World."
+private const val BIDI_TEXT = "abc\u05D0\u05D1\u05D2"
private const val BMP_WIDTH = 400
private const val BMP_HEIGHT = 300
@@ -38,11 +40,11 @@ private val PAINT = TextPaint().apply {
textSize = 32f
}
-private val START_PAINT = arrayListOf<Paint>(TextPaint(PAINT).apply {
+private val START_PAINT = arrayListOf(TextPaint(PAINT).apply {
fontVariationSettings = "'wght' 400"
})
-private val END_PAINT = arrayListOf<Paint>(TextPaint(PAINT).apply {
+private val END_PAINT = arrayListOf(TextPaint(PAINT).apply {
fontVariationSettings = "'wght' 700"
})
@@ -50,9 +52,14 @@ private val END_PAINT = arrayListOf<Paint>(TextPaint(PAINT).apply {
@SmallTest
class TextInterpolatorTest : SysuiTestCase() {
- private fun makeLayout(text: String, paint: TextPaint): Layout {
+ private fun makeLayout(
+ text: String,
+ paint: TextPaint,
+ dir: TextDirectionHeuristic = TextDirectionHeuristics.LTR
+ ): Layout {
val width = ceil(Layout.getDesiredWidth(text, 0, text.length, paint)).toInt()
- return StaticLayout.Builder.obtain(text, 0, text.length, paint, width).build()
+ return StaticLayout.Builder.obtain(text, 0, text.length, paint, width)
+ .setTextDirection(dir).build()
}
@Test
@@ -69,7 +76,7 @@ class TextInterpolatorTest : SysuiTestCase() {
// Just after created TextInterpolator, it should have 0 progress.
assertThat(interp.progress).isEqualTo(0f)
val actual = interp.toBitmap(BMP_WIDTH, BMP_HEIGHT)
- val expected = makeLayout(TEXT, START_PAINT[0] as TextPaint).toBitmap(BMP_WIDTH, BMP_HEIGHT)
+ val expected = makeLayout(TEXT, START_PAINT[0]).toBitmap(BMP_WIDTH, BMP_HEIGHT)
assertThat(expected.sameAs(actual)).isTrue()
}
@@ -87,7 +94,7 @@ class TextInterpolatorTest : SysuiTestCase() {
interp.progress = 1f
val actual = interp.toBitmap(BMP_WIDTH, BMP_HEIGHT)
- val expected = makeLayout(TEXT, END_PAINT[0] as TextPaint).toBitmap(BMP_WIDTH, BMP_HEIGHT)
+ val expected = makeLayout(TEXT, END_PAINT[0]).toBitmap(BMP_WIDTH, BMP_HEIGHT)
assertThat(expected.sameAs(actual)).isTrue()
}
@@ -108,9 +115,9 @@ class TextInterpolatorTest : SysuiTestCase() {
// end state.
interp.progress = 0.5f
val actual = interp.toBitmap(BMP_WIDTH, BMP_HEIGHT)
- assertThat(actual.sameAs(makeLayout(TEXT, START_PAINT[0] as TextPaint)
+ assertThat(actual.sameAs(makeLayout(TEXT, START_PAINT[0])
.toBitmap(BMP_WIDTH, BMP_HEIGHT))).isFalse()
- assertThat(actual.sameAs(makeLayout(TEXT, END_PAINT[0] as TextPaint)
+ assertThat(actual.sameAs(makeLayout(TEXT, END_PAINT[0])
.toBitmap(BMP_WIDTH, BMP_HEIGHT))).isFalse()
}
@@ -135,10 +142,50 @@ class TextInterpolatorTest : SysuiTestCase() {
assertThat(expected.sameAs(actual)).isTrue()
}
+
+ @Test
+ fun testBidi_LTR() {
+ val layout = makeLayout(BIDI_TEXT, PAINT, TextDirectionHeuristics.LTR)
+
+ val interp = TextInterpolator(layout)
+ TextInterpolator.updatePaint(interp.basePaint, START_PAINT)
+ interp.onBasePaintModified()
+
+ TextInterpolator.updatePaint(interp.targetPaint, END_PAINT)
+ interp.onTargetPaintModified()
+
+ // Just after created TextInterpolator, it should have 0 progress.
+ assertThat(interp.progress).isEqualTo(0f)
+ val actual = interp.toBitmap(BMP_WIDTH, BMP_HEIGHT)
+ val expected = makeLayout(BIDI_TEXT, START_PAINT[0], TextDirectionHeuristics.LTR)
+ .toBitmap(BMP_WIDTH, BMP_HEIGHT)
+
+ assertThat(expected.sameAs(actual)).isTrue()
+ }
+
+ @Test
+ fun testBidi_RTL() {
+ val layout = makeLayout(BIDI_TEXT, PAINT, TextDirectionHeuristics.RTL)
+
+ val interp = TextInterpolator(layout)
+ TextInterpolator.updatePaint(interp.basePaint, START_PAINT)
+ interp.onBasePaintModified()
+
+ TextInterpolator.updatePaint(interp.targetPaint, END_PAINT)
+ interp.onTargetPaintModified()
+
+ // Just after created TextInterpolator, it should have 0 progress.
+ assertThat(interp.progress).isEqualTo(0f)
+ val actual = interp.toBitmap(BMP_WIDTH, BMP_HEIGHT)
+ val expected = makeLayout(BIDI_TEXT, START_PAINT[0], TextDirectionHeuristics.RTL)
+ .toBitmap(BMP_WIDTH, BMP_HEIGHT)
+
+ assertThat(expected.sameAs(actual)).isTrue()
+ }
}
private fun Layout.toBitmap(width: Int, height: Int) =
- Bitmap.createBitmap(width, height, Bitmap.Config.ALPHA_8).also { draw(Canvas(it)) }!!
+ Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888).also { draw(Canvas(it)) }!!
private fun TextInterpolator.toBitmap(width: Int, height: Int) =
- Bitmap.createBitmap(width, height, Bitmap.Config.ALPHA_8).also { draw(Canvas(it)) } \ No newline at end of file
+ Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888).also { draw(Canvas(it)) } \ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
index ec0aa4ca89ed..30c4cf6da8d4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
@@ -33,6 +33,7 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.ActivityManager;
+import android.app.ActivityTaskManager;
import android.app.IActivityTaskManager;
import android.content.ComponentName;
import android.content.Context;
@@ -92,7 +93,7 @@ public class AuthControllerTest extends SysuiTestCase {
@Mock
private StatusBarStateController mStatusBarStateController;
@Mock
- private IActivityTaskManager mActivityTaskManager;
+ private ActivityTaskManager mActivityTaskManager;
@Mock
private FingerprintManager mFingerprintManager;
@Mock
@@ -553,7 +554,7 @@ public class AuthControllerTest extends SysuiTestCase {
TestableAuthController(Context context, CommandQueue commandQueue,
StatusBarStateController statusBarStateController,
- IActivityTaskManager activityTaskManager,
+ ActivityTaskManager activityTaskManager,
FingerprintManager fingerprintManager,
FaceManager faceManager,
Provider<UdfpsController> udfpsControllerFactory) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineClassifierTest.java
new file mode 100644
index 000000000000..19f0a15c8936
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineClassifierTest.java
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.classifier;
+
+import static com.android.systemui.util.mockito.KotlinMockitoHelpersKt.any;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.testing.AndroidTestingRunner;
+import android.view.MotionEvent;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.testing.FakeMetricsLogger;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.dock.DockManagerFake;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+public class BrightLineClassifierTest extends SysuiTestCase {
+ private BrightLineFalsingManager mBrightLineFalsingManager;
+ @Mock
+ private FalsingDataProvider mFalsingDataProvider;
+ private final DockManagerFake mDockManager = new DockManagerFake();
+ private final MetricsLogger mMetricsLogger = new FakeMetricsLogger();
+ private final Set<FalsingClassifier> mClassifiers = new HashSet<>();
+ @Mock
+ private SingleTapClassifier mSingleTapClassfier;
+ @Mock
+ private DoubleTapClassifier mDoubleTapClassifier;
+ @Mock
+ private FalsingClassifier mClassifierA;
+ @Mock
+ private FalsingClassifier mClassifierB;
+ private final List<MotionEvent> mMotionEventList = new ArrayList<>();
+
+ @Before
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+ mClassifiers.add(mClassifierA);
+ mClassifiers.add(mClassifierB);
+ when(mFalsingDataProvider.isDirty()).thenReturn(true);
+ when(mFalsingDataProvider.getRecentMotionEvents()).thenReturn(mMotionEventList);
+ mBrightLineFalsingManager = new BrightLineFalsingManager(mFalsingDataProvider, mDockManager,
+ mMetricsLogger, mClassifiers, mSingleTapClassfier, mDoubleTapClassifier, false);
+ }
+
+ @Test
+ public void testRegisterSessionListener() {
+ verify(mFalsingDataProvider).addSessionListener(
+ any(FalsingDataProvider.SessionListener.class));
+
+ mBrightLineFalsingManager.cleanup();
+ verify(mFalsingDataProvider).removeSessionListener(
+ any(FalsingDataProvider.SessionListener.class));
+ }
+
+ @Test
+ public void testIsFalseTouch_NoClassifiers() {
+ mClassifiers.clear();
+
+ assertThat(mBrightLineFalsingManager.isFalseTouch(0)).isFalse();
+ }
+
+ @Test
+ public void testIsFalseTouch_ClassffiersPass() {
+ assertThat(mBrightLineFalsingManager.isFalseTouch(0)).isFalse();
+ }
+
+ @Test
+ public void testIsFalseTouch_ClassifierARejects() {
+ when(mClassifierA.isFalseTouch()).thenReturn(true);
+ assertThat(mBrightLineFalsingManager.isFalseTouch(0)).isTrue();
+ }
+
+ @Test
+ public void testIsFalseTouch_ClassifierBRejects() {
+ when(mClassifierB.isFalseTouch()).thenReturn(true);
+ assertThat(mBrightLineFalsingManager.isFalseTouch(0)).isTrue();
+ }
+
+ @Test
+ public void testIsFalseTouch_FaceAuth() {
+ // Even when the classifiers report a false, we should allow.
+ when(mClassifierA.isFalseTouch()).thenReturn(true);
+ when(mFalsingDataProvider.isJustUnlockedWithFace()).thenReturn(true);
+
+ assertThat(mBrightLineFalsingManager.isFalseTouch(0)).isFalse();
+ }
+
+ @Test
+ public void testIsFalseTouch_Docked() {
+ // Even when the classifiers report a false, we should allow.
+ when(mClassifierA.isFalseTouch()).thenReturn(true);
+ mDockManager.setIsDocked(true);
+
+ assertThat(mBrightLineFalsingManager.isFalseTouch(0)).isFalse();
+ }
+
+ @Test
+ public void testIsFalseTap_BasicCheck() {
+ when(mSingleTapClassfier.isTap(mMotionEventList)).thenReturn(false);
+
+ assertThat(mBrightLineFalsingManager.isFalseTap(false)).isTrue();
+
+ when(mSingleTapClassfier.isTap(mMotionEventList)).thenReturn(true);
+
+ assertThat(mBrightLineFalsingManager.isFalseTap(false)).isFalse();
+ }
+
+ @Test
+ public void testIsFalseTap_RobustCheck_NoFaceAuth() {
+ when(mSingleTapClassfier.isTap(mMotionEventList)).thenReturn(true);
+ mFalsingDataProvider.setJustUnlockedWithFace(false);
+ assertThat(mBrightLineFalsingManager.isFalseTap(true)).isTrue();
+ }
+
+ @Test
+ public void testIsFalseTap_RobustCheck_FaceAuth() {
+ when(mSingleTapClassfier.isTap(mMotionEventList)).thenReturn(true);
+ when(mFalsingDataProvider.isJustUnlockedWithFace()).thenReturn(true);
+ assertThat(mBrightLineFalsingManager.isFalseTap(true)).isFalse();
+ }
+
+ @Test
+ public void testIsFalseDoubleTap() {
+ when(mDoubleTapClassifier.isFalseTouch()).thenReturn(false);
+
+ assertThat(mBrightLineFalsingManager.isFalseDoubleTap()).isFalse();
+
+ when(mDoubleTapClassifier.isFalseTouch()).thenReturn(true);
+
+ assertThat(mBrightLineFalsingManager.isFalseDoubleTap()).isTrue();
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/DiagonalClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/DiagonalClassifierTest.java
index 714d6581ff00..7659db8cc9ef 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/DiagonalClassifierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/DiagonalClassifierTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.classifier.brightline;
+package com.android.systemui.classifier;
import static com.android.systemui.classifier.Classifier.LEFT_AFFORDANCE;
import static com.android.systemui.classifier.Classifier.RIGHT_AFFORDANCE;
@@ -27,8 +27,6 @@ import android.testing.AndroidTestingRunner;
import androidx.test.filters.SmallTest;
-import com.android.systemui.classifier.ClassifierTest;
-import com.android.systemui.classifier.FalsingDataProvider;
import com.android.systemui.util.DeviceConfigProxyFake;
import org.junit.After;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/DistanceClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/DistanceClassifierTest.java
index d66c7a9d43a5..013fa369e876 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/DistanceClassifierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/DistanceClassifierTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.classifier.brightline;
+package com.android.systemui.classifier;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
@@ -23,8 +23,6 @@ import android.testing.AndroidTestingRunner;
import androidx.test.filters.SmallTest;
-import com.android.systemui.classifier.ClassifierTest;
-import com.android.systemui.classifier.FalsingDataProvider;
import com.android.systemui.util.DeviceConfigProxyFake;
import org.junit.After;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/DoubleTapClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/DoubleTapClassifierTest.java
index 288ab0ad6596..4c4108a0cb90 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/DoubleTapClassifierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/DoubleTapClassifierTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.classifier.brightline;
+package com.android.systemui.classifier;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
@@ -27,9 +27,6 @@ import android.view.MotionEvent;
import androidx.test.filters.SmallTest;
-import com.android.systemui.classifier.ClassifierTest;
-import com.android.systemui.classifier.FalsingDataProvider;
-
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/PointerCountClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/PointerCountClassifierTest.java
index b512f0d6ef32..ee289b5b922d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/PointerCountClassifierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/PointerCountClassifierTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.classifier.brightline;
+package com.android.systemui.classifier;
import static com.android.systemui.classifier.Classifier.QUICK_SETTINGS;
@@ -26,8 +26,6 @@ import android.view.MotionEvent;
import androidx.test.filters.SmallTest;
-import com.android.systemui.classifier.ClassifierTest;
-
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/ProximityClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/ProximityClassifierTest.java
index c2e290f166a3..38b025f675ee 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/ProximityClassifierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/ProximityClassifierTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.classifier.brightline;
+package com.android.systemui.classifier;
import static com.android.systemui.classifier.Classifier.GENERIC;
import static com.android.systemui.classifier.Classifier.QUICK_SETTINGS;
@@ -28,8 +28,6 @@ import android.view.MotionEvent;
import androidx.test.filters.SmallTest;
-import com.android.systemui.classifier.ClassifierTest;
-import com.android.systemui.classifier.FalsingDataProvider;
import com.android.systemui.util.DeviceConfigProxyFake;
import com.android.systemui.util.sensors.ProximitySensor;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/SingleTapClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/SingleTapClassifierTest.java
index d67f2b833deb..941e12e475f9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/SingleTapClassifierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/SingleTapClassifierTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.classifier.brightline;
+package com.android.systemui.classifier;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
@@ -25,9 +25,6 @@ import android.view.MotionEvent;
import androidx.test.filters.SmallTest;
-import com.android.systemui.classifier.ClassifierTest;
-import com.android.systemui.classifier.FalsingDataProvider;
-
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/TimeLimitedMotionEventBufferTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/TimeLimitedMotionEventBufferTest.java
index 1dfffb271f02..6e312594a2e4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/TimeLimitedMotionEventBufferTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/TimeLimitedMotionEventBufferTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.classifier.brightline;
+package com.android.systemui.classifier;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/TypeClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/TypeClassifierTest.java
index 5f3b84c2f7ae..6b9bb4fedd16 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/TypeClassifierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/TypeClassifierTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.classifier.brightline;
+package com.android.systemui.classifier;
import static com.android.systemui.classifier.Classifier.BOUNCER_UNLOCK;
import static com.android.systemui.classifier.Classifier.LEFT_AFFORDANCE;
@@ -33,9 +33,6 @@ import android.testing.AndroidTestingRunner;
import androidx.test.filters.SmallTest;
-import com.android.systemui.classifier.ClassifierTest;
-import com.android.systemui.classifier.FalsingDataProvider;
-
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/ZigZagClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/ZigZagClassifierTest.java
index e49262f5099f..339dd9e9e6d2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/ZigZagClassifierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/ZigZagClassifierTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.classifier.brightline;
+package com.android.systemui.classifier;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
@@ -23,7 +23,6 @@ import android.testing.AndroidTestingRunner;
import androidx.test.filters.SmallTest;
-import com.android.systemui.classifier.ClassifierTest;
import com.android.systemui.util.DeviceConfigProxyFake;
import org.junit.After;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dock/DockManagerFake.java b/packages/SystemUI/tests/src/com/android/systemui/dock/DockManagerFake.java
index a6355880c660..37540621557f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dock/DockManagerFake.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dock/DockManagerFake.java
@@ -22,6 +22,7 @@ package com.android.systemui.dock;
public class DockManagerFake implements DockManager {
DockEventListener mCallback;
AlignmentStateListener mAlignmentListener;
+ private boolean mDocked;
@Override
public void addListener(DockEventListener callback) {
@@ -45,7 +46,11 @@ public class DockManagerFake implements DockManager {
@Override
public boolean isDocked() {
- return false;
+ return mDocked;
+ }
+
+ public void setIsDocked(boolean docked) {
+ mDocked = docked;
}
@Override
diff --git a/packages/SystemUI/tests/src/com/android/systemui/people/widget/PeopleSpaceWidgetManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/people/widget/PeopleSpaceWidgetManagerTest.java
index 3e44fa4a9b2b..477fe6316399 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/people/widget/PeopleSpaceWidgetManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/people/widget/PeopleSpaceWidgetManagerTest.java
@@ -16,6 +16,7 @@
package com.android.systemui.people.widget;
+import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
import static android.app.NotificationManager.IMPORTANCE_HIGH;
import static org.mockito.ArgumentMatchers.any;
@@ -164,7 +165,7 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase {
when(mIAppWidgetService.getAppWidgetIds(any())).thenReturn(widgetIdsArray);
NotificationChannel channel =
- mNoMan.createNotificationChannel(TEST_CHANNEL_ID, TEST_CHANNEL_NAME);
+ new NotificationChannel(TEST_CHANNEL_ID, TEST_CHANNEL_NAME, IMPORTANCE_DEFAULT);
mNoMan.issueChannelModification(TEST_PACKAGE_A,
UserHandle.getUserHandleForUid(0), channel, IMPORTANCE_HIGH);
@@ -181,7 +182,7 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase {
when(mIAppWidgetService.getAppWidgetIds(any())).thenReturn(widgetIdsArray);
NotificationChannel channel =
- mNoMan.createNotificationChannel(TEST_CHANNEL_ID, TEST_CHANNEL_NAME);
+ new NotificationChannel(TEST_CHANNEL_ID, TEST_CHANNEL_NAME, IMPORTANCE_DEFAULT);
channel.setConversationId(TEST_PARENT_CHANNEL_ID, TEST_CONVERSATION_ID);
mNoMan.issueChannelModification(TEST_PACKAGE_A,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java
index 6fa6f31984f2..fd0715bbca29 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java
@@ -15,6 +15,7 @@
package com.android.systemui.qs;
import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNotNull;
import static org.junit.Assert.assertFalse;
import static org.mockito.Matchers.any;
@@ -24,6 +25,8 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.pm.UserInfo;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.VectorDrawable;
import android.os.Handler;
import android.os.Looper;
import android.provider.Settings;
@@ -75,6 +78,7 @@ public class QSSecurityFooterTest extends SysuiTestCase {
private ViewGroup mRootView;
private TextView mFooterText;
private TestableImageView mFooterIcon;
+ private TestableImageView mPrimaryFooterIcon;
private QSSecurityFooter mFooter;
@Mock
private SecurityController mSecurityController;
@@ -95,6 +99,7 @@ public class QSSecurityFooterTest extends SysuiTestCase {
mActivityStarter, mSecurityController, looper);
mFooterText = mRootView.findViewById(R.id.footer_text);
mFooterIcon = mRootView.findViewById(R.id.footer_icon);
+ mPrimaryFooterIcon = mRootView.findViewById(R.id.primary_footer_icon);
mFooter.setHostEnvironment(null);
}
@@ -119,6 +124,7 @@ public class QSSecurityFooterTest extends SysuiTestCase {
mFooterText.getText());
assertEquals(View.VISIBLE, mRootView.getVisibility());
assertEquals(View.VISIBLE, mFooterIcon.getVisibility());
+ assertEquals(View.GONE, mPrimaryFooterIcon.getVisibility());
// -1 == never set.
assertEquals(-1, mFooterIcon.getLastImageResource());
}
@@ -136,6 +142,7 @@ public class QSSecurityFooterTest extends SysuiTestCase {
mFooterText.getText());
assertEquals(View.VISIBLE, mRootView.getVisibility());
assertEquals(View.VISIBLE, mFooterIcon.getVisibility());
+ assertEquals(View.GONE, mPrimaryFooterIcon.getVisibility());
// -1 == never set.
assertEquals(-1, mFooterIcon.getLastImageResource());
}
@@ -165,6 +172,7 @@ public class QSSecurityFooterTest extends SysuiTestCase {
assertEquals(mContext.getString(R.string.quick_settings_disclosure_management_monitoring),
mFooterText.getText());
assertEquals(View.VISIBLE, mFooterIcon.getVisibility());
+ assertEquals(View.GONE, mPrimaryFooterIcon.getVisibility());
// -1 == never set.
assertEquals(-1, mFooterIcon.getLastImageResource());
@@ -203,6 +211,7 @@ public class QSSecurityFooterTest extends SysuiTestCase {
VPN_PACKAGE),
mFooterText.getText());
assertEquals(View.VISIBLE, mFooterIcon.getVisibility());
+ assertEquals(View.GONE, mPrimaryFooterIcon.getVisibility());
assertEquals(R.drawable.stat_sys_vpn_ic, mFooterIcon.getLastImageResource());
// Same situation, but with organization name set
@@ -229,6 +238,7 @@ public class QSSecurityFooterTest extends SysuiTestCase {
assertEquals(mContext.getString(R.string.quick_settings_disclosure_management_vpns),
mFooterText.getText());
assertEquals(View.VISIBLE, mFooterIcon.getVisibility());
+ assertEquals(View.GONE, mPrimaryFooterIcon.getVisibility());
assertEquals(R.drawable.stat_sys_vpn_ic, mFooterIcon.getLastImageResource());
// Same situation, but with organization name set
@@ -252,6 +262,7 @@ public class QSSecurityFooterTest extends SysuiTestCase {
TestableLooper.get(this).processAllMessages();
assertEquals(View.VISIBLE, mFooterIcon.getVisibility());
+ assertEquals(View.GONE, mPrimaryFooterIcon.getVisibility());
assertEquals(R.drawable.stat_sys_vpn_ic, mFooterIcon.getLastImageResource());
assertEquals(mContext.getString(R.string.quick_settings_disclosure_management_monitoring),
mFooterText.getText());
@@ -534,12 +545,27 @@ public class QSSecurityFooterTest extends SysuiTestCase {
@Test
public void testParentalControls() {
when(mSecurityController.isParentalControlsEnabled()).thenReturn(true);
+
+ Drawable testDrawable = new VectorDrawable();
+ when(mSecurityController.getIcon(any())).thenReturn(testDrawable);
+ assertNotNull(mSecurityController.getIcon(null));
+
mFooter.refreshState();
TestableLooper.get(this).processAllMessages();
assertEquals(mContext.getString(R.string.quick_settings_disclosure_parental_controls),
mFooterText.getText());
+ assertEquals(View.VISIBLE, mPrimaryFooterIcon.getVisibility());
+
+ assertEquals(testDrawable, mPrimaryFooterIcon.getDrawable());
+
+ // Ensure the primary icon is set to gone when parental controls is disabled.
+ when(mSecurityController.isParentalControlsEnabled()).thenReturn(false);
+ mFooter.refreshState();
+ TestableLooper.get(this).processAllMessages();
+
+ assertEquals(View.GONE, mPrimaryFooterIcon.getVisibility());
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NoManSimulator.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NoManSimulator.java
index 1bfe10c5263b..4507366e3073 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NoManSimulator.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NoManSimulator.java
@@ -16,8 +16,6 @@
package com.android.systemui.statusbar.notification.collection;
-import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
-
import static org.junit.Assert.assertNotNull;
import android.app.NotificationChannel;
@@ -76,10 +74,6 @@ public class NoManSimulator {
}
}
- public NotificationChannel createNotificationChannel(String id, String name) {
- return new NotificationChannel(id, name, IMPORTANCE_DEFAULT);
- }
-
public void issueChannelModification(
String pkg, UserHandle user, NotificationChannel channel, int modificationType) {
for (NotificationHandler listener : mListeners) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageResolverTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageResolverTest.java
index 7f48cd1313fe..edf2b4c30ce4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageResolverTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageResolverTest.java
@@ -69,32 +69,4 @@ public class NotificationInlineImageResolverTest extends SysuiTestCase {
assertEquals("Height matches new config", mResolver.mMaxImageHeight, 20);
assertEquals("Width matches new config", mResolver.mMaxImageWidth, 15);
}
-
- @Test
- public void resolveImage_sizeTooBig() throws IOException {
- doReturn(mBitmapDrawable).when(mResolver).resolveImageInternal(mUri);
- mResolver.mMaxImageHeight = 5;
- mResolver.mMaxImageWidth = 5;
-
- // original bitmap size is 10x10
- BitmapDrawable resolved = (BitmapDrawable) mResolver.resolveImage(mUri);
- Bitmap resolvedBitmap = resolved.getBitmap();
- assertEquals("Bitmap width reduced", 5, resolvedBitmap.getWidth());
- assertEquals("Bitmap height reduced", 5, resolvedBitmap.getHeight());
- assertNotSame("Bitmap replaced", resolvedBitmap, mBitmap);
- }
-
- @Test
- public void resolveImage_sizeOK() throws IOException {
- doReturn(mBitmapDrawable).when(mResolver).resolveImageInternal(mUri);
- mResolver.mMaxImageWidth = 15;
- mResolver.mMaxImageHeight = 15;
-
- // original bitmap size is 10x10
- BitmapDrawable resolved = (BitmapDrawable) mResolver.resolveImage(mUri);
- Bitmap resolvedBitmap = resolved.getBitmap();
- assertEquals("Bitmap width unchanged", 10, resolvedBitmap.getWidth());
- assertEquals("Bitmap height unchanged", 10, resolvedBitmap.getHeight());
- assertSame("Bitmap not replaced", resolvedBitmap, mBitmap);
- }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
index 3d582e74ea4e..d4a94a19af4f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
@@ -63,6 +63,7 @@ import com.android.systemui.biometrics.AuthController;
import com.android.systemui.classifier.FalsingCollectorFake;
import com.android.systemui.classifier.FalsingManagerFake;
import com.android.systemui.doze.DozeLog;
+import com.android.systemui.media.MediaDataManager;
import com.android.systemui.media.MediaHierarchyManager;
import com.android.systemui.qs.QSDetailDisplayer;
import com.android.systemui.statusbar.CommandQueue;
@@ -197,6 +198,8 @@ public class NotificationPanelViewTest extends SysuiTestCase {
private NotificationStackScrollLayoutController mNotificationStackScrollLayoutController;
@Mock
private AuthController mAuthController;
+ @Mock
+ private MediaDataManager mMediaDataManager;
private NotificationPanelViewController mNotificationPanelViewController;
private View.AccessibilityDelegate mAccessibiltyDelegate;
@@ -267,7 +270,7 @@ public class NotificationPanelViewTest extends SysuiTestCase {
mDozeParameters, mCommandQueue, mVibratorHelper,
mLatencyTracker, mPowerManager, mAccessibilityManager, 0, mUpdateMonitor,
mMetricsLogger, mActivityManager, mConfigurationController,
- flingAnimationUtilsBuilder, mStatusBarTouchableRegionManager,
+ () -> flingAnimationUtilsBuilder, mStatusBarTouchableRegionManager,
mConversationNotificationManager, mMediaHiearchyManager,
mBiometricUnlockController, mStatusBarKeyguardViewManager,
mNotificationStackScrollLayoutController,
@@ -275,7 +278,8 @@ public class NotificationPanelViewTest extends SysuiTestCase {
mGroupManager,
mNotificationAreaController,
mAuthController,
- new QSDetailDisplayer());
+ new QSDetailDisplayer(),
+ mMediaDataManager);
mNotificationPanelViewController.initDependencies(
mStatusBar,
mNotificationShelfController);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
index 23f263746fb3..eaf31ed17bb2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
@@ -48,10 +48,10 @@ import com.android.internal.colorextraction.ColorExtractor.GradientColors;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.DejankUtils;
import com.android.systemui.SysuiTestCase;
-import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.dock.DockManager;
import com.android.systemui.statusbar.BlurUtils;
import com.android.systemui.statusbar.ScrimView;
+import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.wakelock.DelayedWakeLock;
import com.android.systemui.utils.os.FakeHandler;
@@ -99,11 +99,11 @@ public class ScrimControllerTest extends SysuiTestCase {
@Mock
KeyguardUpdateMonitor mKeyguardUpdateMonitor;
@Mock
- private SysuiColorExtractor mSysuiColorExtractor;
- @Mock
private DockManager mDockManager;
@Mock
private BlurUtils mBlurUtils;
+ @Mock
+ private ConfigurationController mConfigurationController;
private static class AnimatorListener implements Animator.AnimatorListener {
@@ -196,6 +196,7 @@ public class ScrimControllerTest extends SysuiTestCase {
when(mDozeParamenters.getAlwaysOn()).thenAnswer(invocation -> mAlwaysOnEnabled);
when(mDozeParamenters.getDisplayNeedsBlanking()).thenReturn(true);
+ when(mBlurUtils.supportsBlursOnWindows()).thenReturn(true);
doAnswer((Answer<Void>) invocation -> {
mScrimState = invocation.getArgument(0);
@@ -211,14 +212,12 @@ public class ScrimControllerTest extends SysuiTestCase {
.thenReturn(mDelayedWakeLockBuilder);
when(mDelayedWakeLockBuilder.build()).thenReturn(mWakeLock);
- when(mSysuiColorExtractor.getNeutralColors()).thenReturn(new GradientColors());
-
when(mDockManager.isDocked()).thenReturn(false);
mScrimController = new ScrimController(mLightBarController,
mDozeParamenters, mAlarmManager, mKeyguardStateController, mDelayedWakeLockBuilder,
- new FakeHandler(mLooper.getLooper()), mKeyguardUpdateMonitor, mSysuiColorExtractor,
- mDockManager, mBlurUtils);
+ new FakeHandler(mLooper.getLooper()), mKeyguardUpdateMonitor,
+ mDockManager, mBlurUtils, mConfigurationController);
mScrimController.setScrimVisibleListener(visible -> mScrimVisibility = visible);
mScrimController.attachViews(mScrimBehind, mScrimInFront, mScrimForBubble);
mScrimController.setAnimatorListener(mAnimatorListener);
@@ -520,10 +519,10 @@ public class ScrimControllerTest extends SysuiTestCase {
Assert.assertEquals(ScrimController.TRANSPARENT,
mScrimInFront.getViewAlpha(), 0.0f);
// Back scrim should be visible
- Assert.assertEquals(ScrimController.BUSY_SCRIM_ALPHA,
+ Assert.assertEquals(ScrimController.BLUR_SCRIM_ALPHA,
mScrimBehind.getViewAlpha(), 0.0f);
// Bubble scrim should be visible
- Assert.assertEquals(ScrimController.BUSY_SCRIM_ALPHA,
+ Assert.assertEquals(ScrimController.BLUR_SCRIM_ALPHA,
mScrimBehind.getViewAlpha(), 0.0f);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
index aee884022d95..c826cbcb5389 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
@@ -107,7 +107,7 @@ public class ThemeOverlayControllerTest extends SysuiTestCase {
eq(UserHandle.USER_ALL));
verify(mDumpManager).registerDumpable(any(), any());
- List<Integer> colorList = List.of(Color.RED, Color.BLUE);
+ List<Integer> colorList = List.of(Color.RED, Color.BLUE, 0x0CCCCC, 0x000111);
when(mThemeOverlayApplier.getAvailableAccentColors()).thenReturn(colorList);
when(mThemeOverlayApplier.getAvailableSystemColors()).thenReturn(colorList);
}
@@ -148,6 +148,23 @@ public class ThemeOverlayControllerTest extends SysuiTestCase {
}
@Test
+ public void onWallpaperColorsChanged_addsLeadingZerosToColors() {
+ // Should ask for a new theme when wallpaper colors change
+ WallpaperColors mainColors = new WallpaperColors(Color.valueOf(0x0CCCCC),
+ Color.valueOf(0x000111), null);
+ mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_SYSTEM);
+ ArgumentCaptor<Map<String, String>> themeOverlays = ArgumentCaptor.forClass(Map.class);
+
+ verify(mThemeOverlayApplier).applyCurrentUserOverlays(themeOverlays.capture(), any());
+
+ // Assert that we received the colors that we were expecting
+ assertThat(themeOverlays.getValue().get(OVERLAY_CATEGORY_SYSTEM_PALETTE))
+ .isEqualTo(MONET_SYSTEM_PALETTE_PACKAGE + "0CCCCC");
+ assertThat(themeOverlays.getValue().get(OVERLAY_CATEGORY_ACCENT_COLOR))
+ .isEqualTo(MONET_ACCENT_COLOR_PACKAGE + "000111");
+ }
+
+ @Test
public void onWallpaperColorsChanged_preservesWallpaperPickerTheme() {
// Should ask for a new theme when wallpaper colors change
WallpaperColors mainColors = new WallpaperColors(Color.valueOf(Color.RED),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java
index 822a6f2ad810..ef25b73fd748 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java
@@ -34,7 +34,6 @@ import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.tracing.ProtoTracer;
import com.android.wm.shell.ShellCommandHandler;
-import com.android.wm.shell.apppairs.AppPairs;
import com.android.wm.shell.hidedisplaycutout.HideDisplayCutout;
import com.android.wm.shell.onehanded.OneHanded;
import com.android.wm.shell.onehanded.OneHandedGestureHandler;
@@ -69,7 +68,6 @@ public class WMShellTest extends SysuiTestCase {
@Mock HideDisplayCutout mHideDisplayCutout;
@Mock ProtoTracer mProtoTracer;
@Mock ShellCommandHandler mShellCommandHandler;
- @Mock AppPairs mAppPairs;
@Before
public void setUp() {
@@ -79,7 +77,7 @@ public class WMShellTest extends SysuiTestCase {
mKeyguardUpdateMonitor, mNavigationModeController,
mScreenLifecycle, mSysUiState, Optional.of(mPip), Optional.of(mSplitScreen),
Optional.of(mOneHanded), Optional.of(mHideDisplayCutout), mProtoTracer,
- Optional.of(mShellCommandHandler), Optional.of(mAppPairs));
+ Optional.of(mShellCommandHandler));
when(mPip.getPipTouchHandler()).thenReturn(mPipTouchHandler);
}
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
index be7643ecbd4e..61de53a2a483 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
@@ -558,12 +558,13 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo
if (mAms.getMagnificationMode(displayId)
== Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW) {
magnificationGestureHandler = new WindowMagnificationGestureHandler(displayContext,
- mAms.getWindowMagnificationMgr(), mAms::onMagnificationScaleChanged,
- detectControlGestures, triggerable, displayId);
+ mAms.getWindowMagnificationMgr(), mAms.getMagnificationController(),
+ detectControlGestures, triggerable,
+ displayId);
} else {
magnificationGestureHandler = new FullScreenMagnificationGestureHandler(displayContext,
- mAms.getFullScreenMagnificationController(),
- mAms::onMagnificationScaleChanged, detectControlGestures, triggerable,
+ mAms.getFullScreenMagnificationController(), mAms.getMagnificationController(),
+ detectControlGestures, triggerable,
new WindowMagnificationPromptController(displayContext, mUserId), displayId);
}
return magnificationGestureHandler;
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 4c85490a8086..be2f8f16a412 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -119,7 +119,6 @@ import com.android.server.LocalServices;
import com.android.server.SystemService;
import com.android.server.accessibility.magnification.FullScreenMagnificationController;
import com.android.server.accessibility.magnification.MagnificationController;
-import com.android.server.accessibility.magnification.MagnificationGestureHandler;
import com.android.server.accessibility.magnification.WindowMagnificationManager;
import com.android.server.pm.UserManagerInternal;
import com.android.server.wm.ActivityTaskManagerInternal;
@@ -153,7 +152,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
AccessibilityUserState.ServiceInfoChangeListener,
AccessibilityWindowManager.AccessibilityEventSender,
AccessibilitySecurityPolicy.AccessibilityUserManager,
- MagnificationGestureHandler.ScaleChangedListener,
SystemActionPerformer.SystemActionsChangedListener {
private static final boolean DEBUG = false;
@@ -1066,17 +1064,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
}
}
- @Override
- public void onMagnificationScaleChanged(int displayId, int mode) {
- synchronized (mLock) {
- final int capabilities =
- getCurrentUserStateLocked().getMagnificationCapabilitiesLocked();
- if (capabilities == Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_ALL) {
- getWindowMagnificationMgr().showMagnificationButton(displayId, mode);
- }
- }
- }
-
/**
* Called by AccessibilityInputFilter when it creates or destroys the motionEventInjector.
* Not using a getter because the AccessibilityInputFilter isn't thread-safe
@@ -3000,6 +2987,17 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
}
}
+ /**
+ * Getter of {@link MagnificationController}.
+ *
+ * @return MagnificationController
+ */
+ MagnificationController getMagnificationController() {
+ synchronized (mLock) {
+ return mMagnificationController;
+ }
+ }
+
@Override
public void associateEmbeddedHierarchy(@NonNull IBinder host, @NonNull IBinder embedded) {
synchronized (mLock) {
@@ -3584,6 +3582,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN, userState.mUserId);
if (capabilities != userState.getMagnificationCapabilitiesLocked()) {
userState.setMagnificationCapabilitiesLocked(capabilities);
+ mMagnificationController.setMagnificationCapabilities(capabilities);
return true;
}
return false;
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandler.java b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandler.java
index efb9d87a0bfd..7483ff3ef3f4 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandler.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandler.java
@@ -62,9 +62,6 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.server.accessibility.AccessibilityManagerService;
import com.android.server.accessibility.gestures.GestureUtils;
-import java.util.ArrayDeque;
-import java.util.Queue;
-
/**
* This class handles full screen magnification in response to touch events.
*
@@ -115,13 +112,10 @@ import java.util.Queue;
*/
@SuppressWarnings("WeakerAccess")
public class FullScreenMagnificationGestureHandler extends MagnificationGestureHandler {
- private static final String LOG_TAG = "FullScreenMagnificationGestureHandler";
- private static final boolean DEBUG_ALL = false;
private static final boolean DEBUG_STATE_TRANSITIONS = false | DEBUG_ALL;
private static final boolean DEBUG_DETECTING = false | DEBUG_ALL;
private static final boolean DEBUG_PANNING_SCALING = false | DEBUG_ALL;
- private static final boolean DEBUG_EVENT_STREAM = false | DEBUG_ALL;
// The MIN_SCALE is different from MagnificationController.MIN_SCALE due
// to AccessibilityService.MagnificationController#setScale() has
@@ -139,41 +133,12 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH
private final ScreenStateReceiver mScreenStateReceiver;
private final WindowMagnificationPromptController mPromptController;
- /**
- * {@code true} if this detector should detect and respond to triple-tap
- * gestures for engaging and disengaging magnification,
- * {@code false} if it should ignore such gestures
- */
- final boolean mDetectTripleTap;
-
- /**
- * Whether {@link DetectingState#mShortcutTriggered shortcut} is enabled
- */
- final boolean mDetectShortcutTrigger;
-
@VisibleForTesting State mCurrentState;
@VisibleForTesting State mPreviousState;
private PointerCoords[] mTempPointerCoords;
private PointerProperties[] mTempPointerProperties;
- private final int mDisplayId;
-
- private final Queue<MotionEvent> mDebugInputEventHistory;
- private final Queue<MotionEvent> mDebugOutputEventHistory;
-
- /**
- * @param context Context for resolving various magnification-related resources
- * @param fullScreenMagnificationController the {@link FullScreenMagnificationController}
- *
- * @param detectTripleTap {@code true} if this detector should detect and respond to triple-tap
- * gestures for engaging and disengaging magnification,
- * {@code false} if it should ignore such gestures
- * @param detectShortcutTrigger {@code true} if this detector should be "triggerable" by some
- * external shortcut invoking {@link #notifyShortcutTriggered},
- * {@code false} if it should ignore such triggers.
- * @param displayId The logical display id.
- */
public FullScreenMagnificationGestureHandler(Context context,
FullScreenMagnificationController fullScreenMagnificationController,
ScaleChangedListener listener,
@@ -181,23 +146,20 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH
boolean detectShortcutTrigger,
@NonNull WindowMagnificationPromptController promptController,
int displayId) {
- super(listener);
+ super(displayId, detectTripleTap, detectShortcutTrigger, listener);
if (DEBUG_ALL) {
- Log.i(LOG_TAG,
+ Log.i(mLogTag,
"FullScreenMagnificationGestureHandler(detectTripleTap = " + detectTripleTap
+ ", detectShortcutTrigger = " + detectShortcutTrigger + ")");
}
mFullScreenMagnificationController = fullScreenMagnificationController;
mPromptController = promptController;
- mDisplayId = displayId;
mDelegatingState = new DelegatingState();
mDetectingState = new DetectingState(context);
mViewportDraggingState = new ViewportDraggingState();
mPanningScalingState = new PanningScalingState(context);
- mDetectTripleTap = detectTripleTap;
- mDetectShortcutTrigger = detectShortcutTrigger;
if (mDetectShortcutTrigger) {
mScreenStateReceiver = new ScreenStateReceiver(context, this);
mScreenStateReceiver.register();
@@ -205,36 +167,11 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH
mScreenStateReceiver = null;
}
- mDebugInputEventHistory = DEBUG_EVENT_STREAM ? new ArrayDeque<>() : null;
- mDebugOutputEventHistory = DEBUG_EVENT_STREAM ? new ArrayDeque<>() : null;
-
transitionTo(mDetectingState);
}
@Override
- public void onMotionEvent(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
- if (DEBUG_EVENT_STREAM) {
- storeEventInto(mDebugInputEventHistory, event);
- try {
- onMotionEventInternal(event, rawEvent, policyFlags);
- } catch (Exception e) {
- throw new RuntimeException(
- "Exception following input events: " + mDebugInputEventHistory, e);
- }
- } else {
- onMotionEventInternal(event, rawEvent, policyFlags);
- }
- }
-
- private void onMotionEventInternal(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
- if (DEBUG_ALL) Slog.i(LOG_TAG, "onMotionEvent(" + event + ")");
-
- if ((!mDetectTripleTap && !mDetectShortcutTrigger)
- || !event.isFromSource(SOURCE_TOUCHSCREEN)) {
- dispatchTransformedEvent(event, rawEvent, policyFlags);
- return;
- }
-
+ void onMotionEventInternal(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
handleEventWith(mCurrentState, event, rawEvent, policyFlags);
}
@@ -259,7 +196,7 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH
@Override
public void onDestroy() {
if (DEBUG_STATE_TRANSITIONS) {
- Slog.i(LOG_TAG, "onDestroy(); delayed = "
+ Slog.i(mLogTag, "onDestroy(); delayed = "
+ MotionEventInfo.toString(mDetectingState.mDelayedEventQueue));
}
@@ -299,31 +236,6 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH
mPanningScalingState.clear();
}
- private void dispatchTransformedEvent(MotionEvent event, MotionEvent rawEvent,
- int policyFlags) {
- if (DEBUG_EVENT_STREAM) {
- storeEventInto(mDebugOutputEventHistory, event);
- try {
- super.onMotionEvent(event, rawEvent, policyFlags);
- } catch (Exception e) {
- throw new RuntimeException(
- "Exception downstream following input events: " + mDebugInputEventHistory
- + "\nTransformed into output events: " + mDebugOutputEventHistory,
- e);
- }
- } else {
- super.onMotionEvent(event, rawEvent, policyFlags);
- }
- }
-
- private static void storeEventInto(Queue<MotionEvent> queue, MotionEvent event) {
- queue.add(MotionEvent.obtain(event));
- // Prune old events
- while (!queue.isEmpty() && (event.getEventTime() - queue.peek().getEventTime() > 5000)) {
- queue.remove().recycle();
- }
- }
-
private PointerCoords[] getTempPointerCoordsWithMinSize(int size) {
final int oldSize = (mTempPointerCoords != null) ? mTempPointerCoords.length : 0;
if (oldSize < size) {
@@ -358,7 +270,7 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH
private void transitionTo(State state) {
if (DEBUG_STATE_TRANSITIONS) {
- Slog.i(LOG_TAG,
+ Slog.i(mLogTag,
(State.nameOf(mCurrentState) + " -> " + State.nameOf(state)
+ " at " + asList(copyOfRange(new RuntimeException().getStackTrace(), 1, 5)))
.replace(getClass().getName(), ""));
@@ -440,7 +352,7 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH
return true;
}
if (DEBUG_PANNING_SCALING) {
- Slog.i(LOG_TAG, "Panned content by scrollX: " + distanceX
+ Slog.i(mLogTag, "Panned content by scrollX: " + distanceX
+ " scrollY: " + distanceY);
}
mFullScreenMagnificationController.offsetMagnifiedRegion(mDisplayId, distanceX,
@@ -480,7 +392,7 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH
final float pivotX = detector.getFocusX();
final float pivotY = detector.getFocusY();
- if (DEBUG_PANNING_SCALING) Slog.i(LOG_TAG, "Scaled content to: " + scale + "x");
+ if (DEBUG_PANNING_SCALING) Slog.i(mLogTag, "Scaled content to: " + scale + "x");
mFullScreenMagnificationController.setScale(mDisplayId, scale, pivotX, pivotY, false,
AccessibilityManagerService.MAGNIFICATION_GESTURE_HANDLER_ID);
mListener.onMagnificationScaleChanged(mDisplayId, getMode());
@@ -945,7 +857,7 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH
private void onTripleTap(MotionEvent up) {
if (DEBUG_DETECTING) {
- Slog.i(LOG_TAG, "onTripleTap(); delayed: "
+ Slog.i(mLogTag, "onTripleTap(); delayed: "
+ MotionEventInfo.toString(mDelayedEventQueue));
}
clear();
@@ -965,7 +877,7 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH
void transitionToViewportDraggingStateAndClear(MotionEvent down) {
- if (DEBUG_DETECTING) Slog.i(LOG_TAG, "onTripleTapAndHold()");
+ if (DEBUG_DETECTING) Slog.i(mLogTag, "onTripleTapAndHold()");
clear();
mViewportDraggingState.mZoomedInBeforeDrag =
@@ -997,7 +909,7 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH
if (mShortcutTriggered == state) {
return;
}
- if (DEBUG_DETECTING) Slog.i(LOG_TAG, "setShortcutTriggered(" + state + ")");
+ if (DEBUG_DETECTING) Slog.i(mLogTag, "setShortcutTriggered(" + state + ")");
mShortcutTriggered = state;
mFullScreenMagnificationController.setForceShowMagnifiableBounds(mDisplayId, state);
@@ -1030,7 +942,7 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH
}
private void zoomOn(float centerX, float centerY) {
- if (DEBUG_DETECTING) Slog.i(LOG_TAG, "zoomOn(" + centerX + ", " + centerY + ")");
+ if (DEBUG_DETECTING) Slog.i(mLogTag, "zoomOn(" + centerX + ", " + centerY + ")");
final float scale = MathUtils.constrain(
mFullScreenMagnificationController.getPersistedScale(),
@@ -1042,7 +954,7 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH
}
private void zoomOff() {
- if (DEBUG_DETECTING) Slog.i(LOG_TAG, "zoomOff()");
+ if (DEBUG_DETECTING) Slog.i(mLogTag, "zoomOff()");
mFullScreenMagnificationController.reset(mDisplayId, /* animate */ true);
}
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java
index 6f81b5cfe3e6..df88ceb95d9e 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java
@@ -37,7 +37,8 @@ import com.android.server.accessibility.AccessibilityManagerService;
* Handles all magnification controllers initialization, generic interactions
* and magnification mode transition.
*/
-public class MagnificationController implements WindowMagnificationManager.Callback {
+public class MagnificationController implements WindowMagnificationManager.Callback,
+ MagnificationGestureHandler.ScaleChangedListener {
private static final boolean DEBUG = false;
private static final String TAG = "MagnificationController";
@@ -50,6 +51,7 @@ public class MagnificationController implements WindowMagnificationManager.Callb
private FullScreenMagnificationController mFullScreenMagnificationController;
private WindowMagnificationManager mWindowMagnificationMgr;
+ private int mMagnificationCapabilities = ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN;
/**
* A callback to inform the magnification transition result.
@@ -82,10 +84,18 @@ public class MagnificationController implements WindowMagnificationManager.Callb
public void onPerformScaleAction(int displayId, float scale) {
getWindowMagnificationMgr().setScale(displayId, scale);
getWindowMagnificationMgr().persistScale(displayId);
- mAms.onMagnificationScaleChanged(displayId,
+ onMagnificationScaleChanged(displayId,
Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW);
}
+ @Override
+ public void onMagnificationScaleChanged(int displayId, int mode) {
+ if (mMagnificationCapabilities != Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_ALL) {
+ return;
+ }
+ getWindowMagnificationMgr().showMagnificationButton(displayId, mode);
+ }
+
/**
* Transitions to the target Magnification mode with current center of the magnification mode
* if it is available.
@@ -182,6 +192,10 @@ public class MagnificationController implements WindowMagnificationManager.Callb
}
}
+ public void setMagnificationCapabilities(int capabilities) {
+ mMagnificationCapabilities = capabilities;
+ }
+
private DisableMagnificationCallback getDisableMagnificationEndRunnableLocked(
int displayId) {
return mMagnificationEndRunnableSparseArray.get(displayId);
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationGestureHandler.java b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationGestureHandler.java
index d6f53d2c225c..386d0bbf35ec 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationGestureHandler.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationGestureHandler.java
@@ -16,32 +16,127 @@
package com.android.server.accessibility.magnification;
+import static android.view.InputDevice.SOURCE_TOUCHSCREEN;
+
+import android.annotation.NonNull;
+import android.util.Log;
+import android.util.Slog;
+import android.view.MotionEvent;
+
import com.android.server.accessibility.BaseEventStreamTransformation;
+import java.util.ArrayDeque;
+import java.util.Queue;
+
/**
* A base class that detects gestures and defines common methods for magnification.
*/
public abstract class MagnificationGestureHandler extends BaseEventStreamTransformation {
- protected final ScaleChangedListener mListener;
+ protected final String mLogTag = this.getClass().getSimpleName();
+ protected static final boolean DEBUG_ALL = Log.isLoggable("MagnificationGestureHandler",
+ Log.DEBUG);
+ protected static final boolean DEBUG_EVENT_STREAM = false | DEBUG_ALL;
+ private final Queue<MotionEvent> mDebugInputEventHistory;
+ private final Queue<MotionEvent> mDebugOutputEventHistory;
- protected MagnificationGestureHandler(ScaleChangedListener listener) {
- mListener = listener;
- }
+ /**
+ * The logical display id.
+ */
+ protected final int mDisplayId;
/**
- * Interface for listening to the magnification scaling gesture.
+ * {@code true} if this detector should be "triggerable" by some
+ * external shortcut invoking {@link #notifyShortcutTriggered},
+ * {@code false} if it should ignore such triggers.
*/
+ protected final boolean mDetectShortcutTrigger;
+
+ /**
+ * {@code true} if this detector should detect and respond to triple-tap
+ * gestures for engaging and disengaging magnification,
+ * {@code false} if it should ignore such gestures
+ */
+ protected final boolean mDetectTripleTap;
+
+ /** Interface for listening to the magnification scaling gesture. */
public interface ScaleChangedListener {
/**
* Called when the magnification scale is changed by users.
*
* @param displayId The logical display id
- * @param mode The magnification mode
+ * @param mode The magnification mode
*/
void onMagnificationScaleChanged(int displayId, int mode);
}
+ protected final ScaleChangedListener mListener;
+
+ protected MagnificationGestureHandler(int displayId, boolean detectTripleTap,
+ boolean detectShortcutTrigger,
+ @NonNull ScaleChangedListener listener) {
+ mDisplayId = displayId;
+ mDetectTripleTap = detectTripleTap;
+ mDetectShortcutTrigger = detectShortcutTrigger;
+ mListener = listener;
+
+ mDebugInputEventHistory = DEBUG_EVENT_STREAM ? new ArrayDeque<>() : null;
+ mDebugOutputEventHistory = DEBUG_EVENT_STREAM ? new ArrayDeque<>() : null;
+ }
+
+ @Override
+ public final void onMotionEvent(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
+ if (DEBUG_ALL) {
+ Slog.i(mLogTag, "onMotionEvent(" + event + ")");
+ }
+ if (DEBUG_EVENT_STREAM) {
+ storeEventInto(mDebugInputEventHistory, event);
+ }
+ if (shouldDispatchTransformedEvent(event)) {
+ dispatchTransformedEvent(event, rawEvent, policyFlags);
+ } else {
+ onMotionEventInternal(event, rawEvent, policyFlags);
+ }
+ }
+
+ private boolean shouldDispatchTransformedEvent(MotionEvent event) {
+ if ((!mDetectTripleTap && !mDetectShortcutTrigger) || !event.isFromSource(
+ SOURCE_TOUCHSCREEN)) {
+ return true;
+ }
+ return false;
+ }
+
+ final void dispatchTransformedEvent(MotionEvent event, MotionEvent rawEvent,
+ int policyFlags) {
+ if (DEBUG_EVENT_STREAM) {
+ storeEventInto(mDebugOutputEventHistory, event);
+ try {
+ super.onMotionEvent(event, rawEvent, policyFlags);
+ return;
+ } catch (Exception e) {
+ throw new RuntimeException(
+ "Exception downstream following input events: " + mDebugInputEventHistory
+ + "\nTransformed into output events: " + mDebugOutputEventHistory,
+ e);
+ }
+ }
+ super.onMotionEvent(event, rawEvent, policyFlags);
+ }
+
+ private static void storeEventInto(Queue<MotionEvent> queue, MotionEvent event) {
+ queue.add(MotionEvent.obtain(event));
+ // Prune old events
+ while (!queue.isEmpty() && (event.getEventTime() - queue.peek().getEventTime() > 5000)) {
+ queue.remove().recycle();
+ }
+ }
+
+ /**
+ * Called when this MagnificationGestureHandler handles the motion event.
+ */
+ abstract void onMotionEventInternal(MotionEvent event, MotionEvent rawEvent, int policyFlags);
+
/**
* Called when the shortcut target is magnification.
*/
@@ -51,7 +146,6 @@ public abstract class MagnificationGestureHandler extends BaseEventStreamTransfo
* Indicates the magnification mode.
*
* @return the magnification mode of the handler
- *
* @see android.provider.Settings.Secure#ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN
* @see android.provider.Settings.Secure#ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW
*/
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java
index 7d6067c8e1da..7f26b2755900 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java
@@ -27,7 +27,6 @@ import android.annotation.Nullable;
import android.content.Context;
import android.graphics.Point;
import android.provider.Settings;
-import android.util.Log;
import android.util.MathUtils;
import android.util.Slog;
import android.view.Display;
@@ -38,9 +37,7 @@ import com.android.server.accessibility.EventStreamTransformation;
import com.android.server.accessibility.gestures.MultiTap;
import com.android.server.accessibility.gestures.MultiTapAndHold;
-import java.util.ArrayDeque;
import java.util.List;
-import java.util.Queue;
/**
* This class handles window magnification in response to touch events and shortcut.
@@ -64,12 +61,9 @@ import java.util.Queue;
*/
@SuppressWarnings("WeakerAccess")
public class WindowMagnificationGestureHandler extends MagnificationGestureHandler {
- private static final String LOG_TAG = "WindowMagnificationGestureHandler";
- private static final boolean DEBUG_ALL = Log.isLoggable(LOG_TAG, Log.DEBUG);
private static final boolean DEBUG_STATE_TRANSITIONS = false | DEBUG_ALL;
private static final boolean DEBUG_DETECTING = false | DEBUG_ALL;
- private static final boolean DEBUG_EVENT_STREAM = false | DEBUG_ALL;
//Ensure the range has consistency with FullScreenMagnificationGestureHandler.
private static final float MIN_SCALE = 2.0f;
@@ -88,38 +82,26 @@ public class WindowMagnificationGestureHandler extends MagnificationGestureHandl
@VisibleForTesting
State mPreviousState;
- final boolean mDetectShortcutTrigger;
-
private MotionEventDispatcherDelegate mMotionEventDispatcherDelegate;
- private final int mDisplayId;
private final Context mContext;
private final Point mTempPoint = new Point();
- private final Queue<MotionEvent> mDebugOutputEventHistory;
-
- /**
- * @param context Context for resolving various magnification-related resources
- * @param windowMagnificationMgr The {@link WindowMagnificationManager}
- * @param displayId The logical display id.
- */
public WindowMagnificationGestureHandler(Context context,
WindowMagnificationManager windowMagnificationMgr,
- ScaleChangedListener listener, boolean detectTripleTap,
- boolean detectShortcutTrigger, int displayId) {
- super(listener);
+ ScaleChangedListener listener,
+ boolean detectTripleTap, boolean detectShortcutTrigger, int displayId) {
+ super(displayId, detectTripleTap, detectShortcutTrigger, listener);
if (DEBUG_ALL) {
- Slog.i(LOG_TAG,
+ Slog.i(mLogTag,
"WindowMagnificationGestureHandler() , displayId = " + displayId + ")");
}
mContext = context;
mWindowMagnificationMgr = windowMagnificationMgr;
- mDetectShortcutTrigger = detectShortcutTrigger;
- mDisplayId = displayId;
mMotionEventDispatcherDelegate = new MotionEventDispatcherDelegate(context,
- (event, rawEvent, policyFlags) -> super.onMotionEvent(
- event, rawEvent, policyFlags));
+ (event, rawEvent, policyFlags) -> dispatchTransformedEvent(event, rawEvent,
+ policyFlags));
mDelegatingState = new DelegatingState(mMotionEventDispatcherDelegate);
- mDetectingState = new DetectingState(context, detectTripleTap);
+ mDetectingState = new DetectingState(context, mDetectTripleTap);
mObservePanningScalingState = new PanningScalingGestureState(
new PanningScalingHandler(context, MAX_SCALE, MIN_SCALE, true,
new PanningScalingHandler.MagnificationDelegate() {
@@ -142,24 +124,14 @@ public class WindowMagnificationGestureHandler extends MagnificationGestureHandl
}
}));
- mDebugOutputEventHistory = DEBUG_EVENT_STREAM ? new ArrayDeque<>() : null;
-
transitionTo(mDetectingState);
}
@Override
- public void onMotionEvent(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
- if (DEBUG_ALL) {
- Slog.i(LOG_TAG, "onMotionEvent(" + event + ")");
- }
- if (!event.isFromSource(SOURCE_TOUCHSCREEN)) {
- dispatchTransformedEvent(event, rawEvent, policyFlags);
- return;
- } else {
- // To keep InputEventConsistencyVerifiers within GestureDetectors happy.
- mObservePanningScalingState.mPanningScalingHandler.onTouchEvent(event);
- mCurrentState.onMotionEvent(event, rawEvent, policyFlags);
- }
+ void onMotionEventInternal(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
+ // To keep InputEventConsistencyVerifiers within GestureDetectors happy.
+ mObservePanningScalingState.mPanningScalingHandler.onTouchEvent(event);
+ mCurrentState.onMotionEvent(event, rawEvent, policyFlags);
}
@Override
@@ -173,7 +145,7 @@ public class WindowMagnificationGestureHandler extends MagnificationGestureHandl
@Override
public void onDestroy() {
if (DEBUG_ALL) {
- Slog.i(LOG_TAG, "onDestroy(); delayed = "
+ Slog.i(mLogTag, "onDestroy(); delayed = "
+ mDetectingState.toString());
}
mWindowMagnificationMgr.disableWindowMagnification(mDisplayId, true);
@@ -183,7 +155,7 @@ public class WindowMagnificationGestureHandler extends MagnificationGestureHandl
@Override
public void notifyShortcutTriggered() {
if (DEBUG_ALL) {
- Slog.i(LOG_TAG, "notifyShortcutTriggered():");
+ Slog.i(mLogTag, "notifyShortcutTriggered():");
}
if (!mDetectShortcutTrigger) {
return;
@@ -205,7 +177,7 @@ public class WindowMagnificationGestureHandler extends MagnificationGestureHandl
private void enableWindowMagnifier(float centerX, float centerY) {
if (DEBUG_ALL) {
- Slog.i(LOG_TAG, "enableWindowMagnifier :" + centerX + ", " + centerY);
+ Slog.i(mLogTag, "enableWindowMagnifier :" + centerX + ", " + centerY);
}
final float scale = MathUtils.constrain(
@@ -216,7 +188,7 @@ public class WindowMagnificationGestureHandler extends MagnificationGestureHandl
private void disableWindowMagnifier() {
if (DEBUG_ALL) {
- Slog.i(LOG_TAG, "disableWindowMagnifier()");
+ Slog.i(mLogTag, "disableWindowMagnifier()");
}
mWindowMagnificationMgr.disableWindowMagnification(mDisplayId, false);
}
@@ -231,7 +203,7 @@ public class WindowMagnificationGestureHandler extends MagnificationGestureHandl
private void onTripleTap(MotionEvent up) {
if (DEBUG_DETECTING) {
- Slog.i(LOG_TAG, "onTripleTap()");
+ Slog.i(mLogTag, "onTripleTap()");
}
toggleMagnification(up.getX(), up.getY());
}
@@ -240,30 +212,6 @@ public class WindowMagnificationGestureHandler extends MagnificationGestureHandl
transitionTo(mDetectingState);
}
- private void dispatchTransformedEvent(MotionEvent event, MotionEvent rawEvent,
- int policyFlags) {
- if (DEBUG_EVENT_STREAM) {
- storeEventInto(mDebugOutputEventHistory, event);
- try {
- super.onMotionEvent(event, rawEvent, policyFlags);
- } catch (Exception e) {
- throw new RuntimeException(
- "Exception downstream following input events: " + mDebugOutputEventHistory,
- e);
- }
- } else {
- super.onMotionEvent(event, rawEvent, policyFlags);
- }
- }
-
- private static void storeEventInto(Queue<MotionEvent> queue, MotionEvent event) {
- queue.add(MotionEvent.obtain(event));
- // Prune old events.
- while (!queue.isEmpty() && (event.getEventTime() - queue.peek().getEventTime() > 5000)) {
- queue.remove().recycle();
- }
- }
-
/**
* An interface to intercept the {@link MotionEvent} for gesture detection. The intercepted
* events should be delivered to next {@link EventStreamTransformation} with {
@@ -293,7 +241,7 @@ public class WindowMagnificationGestureHandler extends MagnificationGestureHandl
private void transitionTo(State state) {
if (DEBUG_STATE_TRANSITIONS) {
- Slog.i(LOG_TAG, "state transition: " + (State.nameOf(mCurrentState) + " -> "
+ Slog.i(mLogTag, "state transition: " + (State.nameOf(mCurrentState) + " -> "
+ State.nameOf(state) + " at "
+ asList(copyOfRange(new RuntimeException().getStackTrace(), 1, 5)))
.replace(getClass().getName(), ""));
@@ -451,10 +399,10 @@ public class WindowMagnificationGestureHandler extends MagnificationGestureHandl
List<MotionEventInfo> delayedEventQueue,
MotionEvent motionEvent) {
if (DEBUG_DETECTING) {
- Slog.d(LOG_TAG, "onGestureDetected : gesture = "
+ Slog.d(mLogTag, "onGestureDetected : gesture = "
+ MagnificationGestureMatcher.gestureIdToString(
gestureId));
- Slog.d(LOG_TAG,
+ Slog.d(mLogTag,
"onGestureDetected : delayedEventQueue = " + delayedEventQueue);
}
if (gestureId == MagnificationGestureMatcher.GESTURE_TWO_FINGER_DOWN
@@ -474,7 +422,7 @@ public class WindowMagnificationGestureHandler extends MagnificationGestureHandl
List<MotionEventInfo> delayedEventQueue,
MotionEvent motionEvent) {
if (DEBUG_DETECTING) {
- Slog.d(LOG_TAG,
+ Slog.d(mLogTag,
"onGestureCancelled : delayedEventQueue = " + delayedEventQueue);
}
mMotionEventDispatcherDelegate.sendDelayedMotionEvents(delayedEventQueue,
diff --git a/services/autofill/java/com/android/server/autofill/TEST_MAPPING b/services/autofill/java/com/android/server/autofill/TEST_MAPPING
new file mode 100644
index 000000000000..cf058add0262
--- /dev/null
+++ b/services/autofill/java/com/android/server/autofill/TEST_MAPPING
@@ -0,0 +1,15 @@
+{
+ "presubmit": [
+ {
+ "name": "CtsAutoFillServiceTestCases",
+ "options": [
+ {
+ "include-annotation": "android.platform.test.annotations.Presubmit"
+ },
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ }
+ ]
+ }
+ ]
+}
diff --git a/services/core/Android.bp b/services/core/Android.bp
index fec7ac0dd5bd..17e3456e565b 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -145,6 +145,7 @@ java_library_static {
"SurfaceFlingerProperties",
"com.android.sysprop.watchdog",
],
+ javac_shard_size: 50,
}
java_genrule {
@@ -188,6 +189,13 @@ prebuilt_etc {
src: ":services.core.json.gz",
}
+filegroup {
+ name: "services.core-sources-deviceconfig-interface",
+ srcs: [
+ "java/com/android/server/utils/DeviceConfigInterface.java"
+ ],
+}
+
// TODO: Move connectivity service sources to independent directory.
filegroup {
name: "connectivity-service-srcs",
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 031cc42f99b9..f0677a23765c 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -41,6 +41,7 @@ import static android.net.INetworkMonitor.NETWORK_VALIDATION_RESULT_VALID;
import static android.net.NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL;
import static android.net.NetworkCapabilities.NET_CAPABILITY_FOREGROUND;
import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING;
@@ -4821,15 +4822,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
}
- private void updateVpnCapabilities(Vpn vpn, @Nullable NetworkCapabilities nc) {
- ensureRunningOnConnectivityServiceThread();
- NetworkAgentInfo vpnNai = getNetworkAgentInfoForNetId(vpn.getNetId());
- if (vpnNai == null || nc == null) {
- return;
- }
- updateCapabilities(vpnNai.getCurrentScore(), vpnNai, nc);
- }
-
@Override
public boolean updateLockdownVpn() {
if (Binder.getCallingUid() != Process.SYSTEM_UID) {
@@ -5140,7 +5132,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
}
- private void onUserStart(int userId) {
+ private void onUserStarted(int userId) {
synchronized (mVpns) {
Vpn userVpn = mVpns.get(userId);
if (userVpn != null) {
@@ -5155,7 +5147,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
}
- private void onUserStop(int userId) {
+ private void onUserStopped(int userId) {
synchronized (mVpns) {
Vpn userVpn = mVpns.get(userId);
if (userVpn == null) {
@@ -5169,28 +5161,22 @@ public class ConnectivityService extends IConnectivityManager.Stub
private void onUserAdded(int userId) {
mPermissionMonitor.onUserAdded(userId);
- Network defaultNetwork = getNetwork(getDefaultNetwork());
synchronized (mVpns) {
final int vpnsSize = mVpns.size();
for (int i = 0; i < vpnsSize; i++) {
Vpn vpn = mVpns.valueAt(i);
vpn.onUserAdded(userId);
- NetworkCapabilities nc = vpn.updateCapabilities(defaultNetwork);
- updateVpnCapabilities(vpn, nc);
}
}
}
private void onUserRemoved(int userId) {
mPermissionMonitor.onUserRemoved(userId);
- Network defaultNetwork = getNetwork(getDefaultNetwork());
synchronized (mVpns) {
final int vpnsSize = mVpns.size();
for (int i = 0; i < vpnsSize; i++) {
Vpn vpn = mVpns.valueAt(i);
vpn.onUserRemoved(userId);
- NetworkCapabilities nc = vpn.updateCapabilities(defaultNetwork);
- updateVpnCapabilities(vpn, nc);
}
}
}
@@ -5272,9 +5258,9 @@ public class ConnectivityService extends IConnectivityManager.Stub
if (userId == UserHandle.USER_NULL) return;
if (Intent.ACTION_USER_STARTED.equals(action)) {
- onUserStart(userId);
+ onUserStarted(userId);
} else if (Intent.ACTION_USER_STOPPED.equals(action)) {
- onUserStop(userId);
+ onUserStopped(userId);
} else if (Intent.ACTION_USER_ADDED.equals(action)) {
onUserAdded(userId);
} else if (Intent.ACTION_USER_REMOVED.equals(action)) {
@@ -6369,18 +6355,71 @@ public class ConnectivityService extends IConnectivityManager.Stub
nai.declaredMetered = !nc.hasCapability(NET_CAPABILITY_NOT_METERED);
}
- /** Propagates to |nc| the capabilities declared by the underlying networks of |nai|. */
- private void mixInUnderlyingCapabilities(NetworkAgentInfo nai, NetworkCapabilities nc) {
- Network[] underlyingNetworks = nai.declaredUnderlyingNetworks;
- Network defaultNetwork = getNetwork(getDefaultNetwork());
+ /** Modifies |caps| based on the capabilities of the specified underlying networks. */
+ @VisibleForTesting
+ void applyUnderlyingCapabilities(@Nullable Network[] underlyingNetworks,
+ @NonNull NetworkCapabilities caps, boolean declaredMetered) {
+ final Network defaultNetwork = getNetwork(getDefaultNetwork());
if (underlyingNetworks == null && defaultNetwork != null) {
// null underlying networks means to track the default.
underlyingNetworks = new Network[] { defaultNetwork };
}
+ int[] transportTypes = new int[] { NetworkCapabilities.TRANSPORT_VPN };
+ int downKbps = NetworkCapabilities.LINK_BANDWIDTH_UNSPECIFIED;
+ int upKbps = NetworkCapabilities.LINK_BANDWIDTH_UNSPECIFIED;
+ boolean metered = declaredMetered; // metered if any underlying is metered, or agentMetered
+ boolean roaming = false; // roaming if any underlying is roaming
+ boolean congested = false; // congested if any underlying is congested
+ boolean suspended = true; // suspended if all underlying are suspended
+
+ boolean hadUnderlyingNetworks = false;
+ if (null != underlyingNetworks) {
+ for (Network underlyingNetwork : underlyingNetworks) {
+ final NetworkAgentInfo underlying =
+ getNetworkAgentInfoForNetwork(underlyingNetwork);
+ if (underlying == null) continue;
+
+ final NetworkCapabilities underlyingCaps = underlying.networkCapabilities;
+ hadUnderlyingNetworks = true;
+ for (int underlyingType : underlyingCaps.getTransportTypes()) {
+ transportTypes = ArrayUtils.appendInt(transportTypes, underlyingType);
+ }
- // TODO(b/124469351): Get capabilities directly from ConnectivityService instead.
- final ConnectivityManager cm = mContext.getSystemService(ConnectivityManager.class);
- Vpn.applyUnderlyingCapabilities(cm, underlyingNetworks, nc, nai.declaredMetered);
+ // Merge capabilities of this underlying network. For bandwidth, assume the
+ // worst case.
+ downKbps = NetworkCapabilities.minBandwidth(downKbps,
+ underlyingCaps.getLinkDownstreamBandwidthKbps());
+ upKbps = NetworkCapabilities.minBandwidth(upKbps,
+ underlyingCaps.getLinkUpstreamBandwidthKbps());
+ // If this underlying network is metered, the VPN is metered (it may cost money
+ // to send packets on this network).
+ metered |= !underlyingCaps.hasCapability(NET_CAPABILITY_NOT_METERED);
+ // If this underlying network is roaming, the VPN is roaming (the billing structure
+ // is different than the usual, local one).
+ roaming |= !underlyingCaps.hasCapability(NET_CAPABILITY_NOT_ROAMING);
+ // If this underlying network is congested, the VPN is congested (the current
+ // condition of the network affects the performance of this network).
+ congested |= !underlyingCaps.hasCapability(NET_CAPABILITY_NOT_CONGESTED);
+ // If this network is not suspended, the VPN is not suspended (the VPN
+ // is able to transfer some data).
+ suspended &= !underlyingCaps.hasCapability(NET_CAPABILITY_NOT_SUSPENDED);
+ }
+ }
+ if (!hadUnderlyingNetworks) {
+ // No idea what the underlying networks are; assume reasonable defaults
+ metered = true;
+ roaming = false;
+ congested = false;
+ suspended = false;
+ }
+
+ caps.setTransportTypes(transportTypes);
+ caps.setLinkDownstreamBandwidthKbps(downKbps);
+ caps.setLinkUpstreamBandwidthKbps(upKbps);
+ caps.setCapability(NET_CAPABILITY_NOT_METERED, !metered);
+ caps.setCapability(NET_CAPABILITY_NOT_ROAMING, !roaming);
+ caps.setCapability(NET_CAPABILITY_NOT_CONGESTED, !congested);
+ caps.setCapability(NET_CAPABILITY_NOT_SUSPENDED, !suspended);
}
/**
@@ -6437,7 +6476,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
if (nai.supportsUnderlyingNetworks()) {
- mixInUnderlyingCapabilities(nai, newNc);
+ applyUnderlyingCapabilities(nai.declaredUnderlyingNetworks, newNc, nai.declaredMetered);
}
return newNc;
@@ -8276,13 +8315,12 @@ public class ConnectivityService extends IConnectivityManager.Stub
return false;
}
- final Network[] underlyingNetworks;
- synchronized (mVpns) {
- final Vpn vpn = getVpnIfOwner(callbackUid);
- underlyingNetworks = (vpn == null) ? null : vpn.getUnderlyingNetworks();
- }
- if (underlyingNetworks != null) {
- if (Arrays.asList(underlyingNetworks).contains(nai.network)) return true;
+ for (NetworkAgentInfo virtual : mNetworkAgentInfos.values()) {
+ if (virtual.supportsUnderlyingNetworks()
+ && virtual.networkCapabilities.getOwnerUid() == callbackUid
+ && ArrayUtils.contains(virtual.declaredUnderlyingNetworks, nai.network)) {
+ return true;
+ }
}
// Administrator UIDs also contains the Owner UID
diff --git a/services/core/java/com/android/server/PackageWatchdog.java b/services/core/java/com/android/server/PackageWatchdog.java
index f3c5fd8d1064..9bf63cbbb25e 100644
--- a/services/core/java/com/android/server/PackageWatchdog.java
+++ b/services/core/java/com/android/server/PackageWatchdog.java
@@ -1043,7 +1043,7 @@ public class PackageWatchdog {
TypedXmlSerializer out = Xml.resolveSerializer(stream);
out.startDocument(null, true);
out.startTag(null, TAG_PACKAGE_WATCHDOG);
- out.attribute(null, ATTR_VERSION, Integer.toString(DB_VERSION));
+ out.attributeInt(null, ATTR_VERSION, DB_VERSION);
for (int oIndex = 0; oIndex < mAllObservers.size(); oIndex++) {
mAllObservers.valueAt(oIndex).writeLocked(out);
}
@@ -1107,7 +1107,7 @@ public class PackageWatchdog {
* Does not persist any package failure thresholds.
*/
@GuardedBy("mLock")
- public boolean writeLocked(XmlSerializer out) {
+ public boolean writeLocked(TypedXmlSerializer out) {
try {
out.startTag(null, TAG_OBSERVER);
out.attribute(null, ATTR_NAME, name);
@@ -1225,7 +1225,7 @@ public class PackageWatchdog {
* #loadFromFile which in turn is only called on construction of the
* singleton PackageWatchdog.
**/
- public static ObserverInternal read(XmlPullParser parser, PackageWatchdog watchdog) {
+ public static ObserverInternal read(TypedXmlPullParser parser, PackageWatchdog watchdog) {
String observerName = null;
if (TAG_OBSERVER.equals(parser.getName())) {
observerName = parser.getAttributeValue(null, ATTR_NAME);
@@ -1240,14 +1240,14 @@ public class PackageWatchdog {
while (XmlUtils.nextElementWithin(parser, innerDepth)) {
if (TAG_PACKAGE.equals(parser.getName())) {
try {
- String packageName = parser.getAttributeValue(null, ATTR_NAME);
- long duration = Long.parseLong(
- parser.getAttributeValue(null, ATTR_DURATION));
- long healthCheckDuration = Long.parseLong(
- parser.getAttributeValue(null,
- ATTR_EXPLICIT_HEALTH_CHECK_DURATION));
- boolean hasPassedHealthCheck = Boolean.parseBoolean(
- parser.getAttributeValue(null, ATTR_PASSED_HEALTH_CHECK));
+ String packageName = parser.getAttributeValue(
+ null, ATTR_NAME);
+ long duration = parser.getAttributeLong(
+ null, ATTR_DURATION);
+ long healthCheckDuration = parser.getAttributeLong(
+ null, ATTR_EXPLICIT_HEALTH_CHECK_DURATION);
+ boolean hasPassedHealthCheck = parser.getAttributeBoolean(
+ null, ATTR_PASSED_HEALTH_CHECK, false);
MonitoredPackage pkg = watchdog.newMonitoredPackage(packageName,
duration, healthCheckDuration, hasPassedHealthCheck);
if (pkg != null) {
@@ -1364,14 +1364,12 @@ public class PackageWatchdog {
/** Writes the salient fields to disk using {@code out}. */
@GuardedBy("mLock")
- public void writeLocked(XmlSerializer out) throws IOException {
+ public void writeLocked(TypedXmlSerializer out) throws IOException {
out.startTag(null, TAG_PACKAGE);
out.attribute(null, ATTR_NAME, getName());
- out.attribute(null, ATTR_DURATION, String.valueOf(mDurationMs));
- out.attribute(null, ATTR_EXPLICIT_HEALTH_CHECK_DURATION,
- String.valueOf(mHealthCheckDurationMs));
- out.attribute(null, ATTR_PASSED_HEALTH_CHECK,
- String.valueOf(mHasPassedHealthCheck));
+ out.attributeLong(null, ATTR_DURATION, mDurationMs);
+ out.attributeLong(null, ATTR_EXPLICIT_HEALTH_CHECK_DURATION, mHealthCheckDurationMs);
+ out.attributeBoolean(null, ATTR_PASSED_HEALTH_CHECK, mHasPassedHealthCheck);
out.endTag(null, TAG_PACKAGE);
}
diff --git a/services/core/java/com/android/server/SensorPrivacyService.java b/services/core/java/com/android/server/SensorPrivacyService.java
index 2455e76d69a8..d30e9fb002e0 100644
--- a/services/core/java/com/android/server/SensorPrivacyService.java
+++ b/services/core/java/com/android/server/SensorPrivacyService.java
@@ -107,7 +107,7 @@ public final class SensorPrivacyService extends SystemService {
TypedXmlSerializer serializer = Xml.resolveSerializer(outputStream);
serializer.startDocument(null, true);
serializer.startTag(null, XML_TAG_SENSOR_PRIVACY);
- serializer.attribute(null, XML_ATTRIBUTE_ENABLED, String.valueOf(enable));
+ serializer.attributeBoolean(null, XML_ATTRIBUTE_ENABLED, enable);
serializer.endTag(null, XML_TAG_SENSOR_PRIVACY);
serializer.endDocument();
mAtomicFile.finishWrite(outputStream);
@@ -180,7 +180,7 @@ public final class SensorPrivacyService extends SystemService {
TypedXmlSerializer serializer = Xml.resolveSerializer(outputStream);
serializer.startDocument(null, true);
serializer.startTag(null, XML_TAG_SENSOR_PRIVACY);
- serializer.attribute(null, XML_ATTRIBUTE_ENABLED, String.valueOf(mEnabled));
+ serializer.attributeBoolean(null, XML_ATTRIBUTE_ENABLED, mEnabled);
serializer.endTag(null, XML_TAG_SENSOR_PRIVACY);
serializer.endDocument();
mAtomicFile.finishWrite(outputStream);
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 04a52e049474..dbd27af49b17 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -38,13 +38,8 @@ import static android.os.storage.OnObbStateChangeListener.ERROR_NOT_MOUNTED;
import static android.os.storage.OnObbStateChangeListener.ERROR_PERMISSION_DENIED;
import static android.os.storage.OnObbStateChangeListener.MOUNTED;
import static android.os.storage.OnObbStateChangeListener.UNMOUNTED;
-import static android.os.storage.StorageManager.PROP_FORCED_SCOPED_STORAGE_WHITELIST;
-import static com.android.internal.util.XmlUtils.readIntAttribute;
-import static com.android.internal.util.XmlUtils.readLongAttribute;
import static com.android.internal.util.XmlUtils.readStringAttribute;
-import static com.android.internal.util.XmlUtils.writeIntAttribute;
-import static com.android.internal.util.XmlUtils.writeLongAttribute;
import static com.android.internal.util.XmlUtils.writeStringAttribute;
import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
@@ -144,7 +139,6 @@ import com.android.internal.os.Zygote;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.CollectionUtils;
import com.android.internal.util.DumpUtils;
-import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.HexDump;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.Preconditions;
@@ -160,9 +154,7 @@ import com.android.server.wm.ActivityTaskManagerInternal.ScreenObserver;
import libcore.io.IoUtils;
import libcore.util.EmptyArray;
-import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
import java.io.File;
import java.io.FileDescriptor;
@@ -172,7 +164,6 @@ import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.math.BigInteger;
-import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.security.spec.KeySpec;
import java.util.ArrayList;
@@ -186,7 +177,6 @@ import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.Set;
-import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
@@ -212,21 +202,34 @@ class StorageManagerService extends IStorageManager.Stub
private static final String ZRAM_ENABLED_PROPERTY =
"persist.sys.zram_enabled";
- private static final boolean ENABLE_ISOLATED_STORAGE = StorageManager.hasIsolatedStorage();
-
// A system property to control if obb app data isolation is enabled in vold.
private static final String ANDROID_VOLD_APP_DATA_ISOLATION_ENABLED_PROPERTY =
"persist.sys.vold_app_data_isolation_enabled";
+ // TODO(b/169327180): Will be fetched from the server, but for now, we emulate this in
+ // the system_server since it can write to DeviceConfig and MediaProvider can read it
+ private static final String PROP_TRANSCODE_ENABLED = "transcode_enabled";
+ private static final String PROP_TRANSCODE_DEFAULT = "transcode_default";
+ private static final String PROP_TRANSCODE_COMPAT_MANIFEST = "transcode_compat_manifest";
+ private static final boolean TRANSCODE_ENABLED_VALUE = false;
+ // Determines the default behavior of apps when transcode is enabled, AKA, Option A/Option B.
+ // If true, transcode by default (Option B). If false, don't transcode by default (Option A)
+ // For dogfood, we go with Option B
+ private static final boolean TRANSCODE_DEFAULT_VALUE = true;
+ // Format is <package_name>,<media_capability_bit_mask>,...
+ // media_capability_bit_mask is defined in MediaProvider/../TranscodeHelper.java:
+ // FLAG_HEVC = 1 << 0;
+ // FLAG_SLOW_MOTION = 1 << 1;
+ // FLAG_HDR_10 = 1 << 2;
+ // FLAG_HDR_10_PLUS = 1 << 3;
+ // FLAG_HDR_HLG = 1 << 4;
+ // FLAG_HDR_DOLBY_VISION = 1 << 5;
+ private static final String TRANSCODE_COMPAT_MANIFEST_VALUE =
+ "com.google.android.apps.photos,1";
+
// How long we wait to reset storage, if we failed to call onMount on the
// external storage service.
public static final int FAILED_MOUNT_RESET_TIMEOUT_SECONDS = 10;
- /**
- * If {@code 1}, enables the isolated storage feature. If {@code -1},
- * disables the isolated storage feature. If {@code 0}, uses the default
- * value from the build system.
- */
- private static final String ISOLATED_STORAGE_ENABLED = "isolated_storage_enabled";
@GuardedBy("mLock")
private final Set<Integer> mFuseMountedUser = new ArraySet<>();
@@ -898,22 +901,18 @@ class StorageManagerService extends IStorageManager.Stub
com.android.internal.R.bool.config_zramWriteback)) {
ZramWriteback.scheduleZramWriteback(mContext);
}
- // Toggle isolated-enable system property in response to settings
- mContext.getContentResolver().registerContentObserver(
- Settings.Global.getUriFor(Settings.Global.ISOLATED_STORAGE_REMOTE),
- false /*notifyForDescendants*/,
- new ContentObserver(null /* current thread */) {
- @Override
- public void onChange(boolean selfChange) {
- refreshIsolatedStorageSettings();
- }
- });
- // For now, simply clone property when it changes
- DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT,
- mContext.getMainExecutor(), (properties) -> {
- refreshIsolatedStorageSettings();
- });
- refreshIsolatedStorageSettings();
+
+ // TODO(b/169327180): Remove after setting up server-side DeviceConfig flags
+ // Set DeviceConfig values for transcoding that will be read by MediaProvider
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT,
+ PROP_TRANSCODE_ENABLED, String.valueOf(TRANSCODE_ENABLED_VALUE),
+ false /* makeDefault */);
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT,
+ PROP_TRANSCODE_DEFAULT, String.valueOf(TRANSCODE_DEFAULT_VALUE),
+ false /* makeDefault */);
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT,
+ PROP_TRANSCODE_COMPAT_MANIFEST, TRANSCODE_COMPAT_MANIFEST_VALUE,
+ false /* makeDefault */);
}
/**
@@ -945,38 +944,6 @@ class StorageManagerService extends IStorageManager.Stub
}
}
- private void refreshIsolatedStorageSettings() {
- // Always copy value from newer DeviceConfig location
- Settings.Global.putString(mResolver,
- Settings.Global.ISOLATED_STORAGE_REMOTE,
- DeviceConfig.getProperty(DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT,
- ISOLATED_STORAGE_ENABLED));
-
- final int local = Settings.Global.getInt(mContext.getContentResolver(),
- Settings.Global.ISOLATED_STORAGE_LOCAL, 0);
- final int remote = Settings.Global.getInt(mContext.getContentResolver(),
- Settings.Global.ISOLATED_STORAGE_REMOTE, 0);
-
- // Walk down precedence chain; we prefer local settings first, then
- // remote settings, before finally falling back to hard-coded default.
- final boolean res;
- if (local == -1) {
- res = false;
- } else if (local == 1) {
- res = true;
- } else if (remote == -1) {
- res = false;
- } else if (remote == 1) {
- res = true;
- } else {
- res = true;
- }
-
- Slog.d(TAG, "Isolated storage local flag " + local + " and remote flag "
- + remote + " resolved to " + res);
- SystemProperties.set(StorageManager.PROP_ISOLATED_STORAGE, Boolean.toString(res));
- }
-
/**
* MediaProvider has a ton of code that makes assumptions about storage
* paths never changing, so we outright kill them to pick up new state.
@@ -1345,12 +1312,13 @@ class StorageManagerService extends IStorageManager.Stub
final int oldState = vol.state;
final int newState = state;
vol.state = newState;
+ final VolumeInfo vInfo = new VolumeInfo(vol);
final SomeArgs args = SomeArgs.obtain();
- args.arg1 = vol;
+ args.arg1 = vInfo;
args.arg2 = oldState;
args.arg3 = newState;
mHandler.obtainMessage(H_VOLUME_STATE_CHANGED, args).sendToTarget();
- onVolumeStateChangedLocked(vol, oldState, newState);
+ onVolumeStateChangedLocked(vInfo, oldState, newState);
}
}
}
@@ -1762,11 +1730,6 @@ class StorageManagerService extends IStorageManager.Stub
*/
public StorageManagerService(Context context) {
sSelf = this;
-
- // Snapshot feature flag used for this boot
- SystemProperties.set(StorageManager.PROP_ISOLATED_STORAGE_SNAPSHOT, Boolean.toString(
- SystemProperties.getBoolean(StorageManager.PROP_ISOLATED_STORAGE, true)));
-
mVoldAppDataIsolationEnabled = SystemProperties.getBoolean(
ANDROID_VOLD_APP_DATA_ISOLATION_ENABLED_PROPERTY, false);
mContext = context;
@@ -2032,7 +1995,7 @@ class StorageManagerService extends IStorageManager.Stub
if (type == START_TAG) {
final String tag = in.getName();
if (TAG_VOLUMES.equals(tag)) {
- final int version = readIntAttribute(in, ATTR_VERSION, VERSION_INIT);
+ final int version = in.getAttributeInt(null, ATTR_VERSION, VERSION_INIT);
final boolean primaryPhysical = SystemProperties.getBoolean(
StorageManager.PROP_PRIMARY_PHYSICAL, false);
final boolean validAttr = (version >= VERSION_FIX_PRIMARY)
@@ -2067,7 +2030,7 @@ class StorageManagerService extends IStorageManager.Stub
TypedXmlSerializer out = Xml.resolveSerializer(fos);
out.startDocument(null, true);
out.startTag(null, TAG_VOLUMES);
- writeIntAttribute(out, ATTR_VERSION, VERSION_FIX_PRIMARY);
+ out.attributeInt(null, ATTR_VERSION, VERSION_FIX_PRIMARY);
writeStringAttribute(out, ATTR_PRIMARY_STORAGE_UUID, mPrimaryStorageUuid);
final int size = mRecords.size();
for (int i = 0; i < size; i++) {
@@ -2085,31 +2048,33 @@ class StorageManagerService extends IStorageManager.Stub
}
}
- public static VolumeRecord readVolumeRecord(XmlPullParser in) throws IOException {
- final int type = readIntAttribute(in, ATTR_TYPE);
+ public static VolumeRecord readVolumeRecord(TypedXmlPullParser in)
+ throws IOException, XmlPullParserException {
+ final int type = in.getAttributeInt(null, ATTR_TYPE);
final String fsUuid = readStringAttribute(in, ATTR_FS_UUID);
final VolumeRecord meta = new VolumeRecord(type, fsUuid);
meta.partGuid = readStringAttribute(in, ATTR_PART_GUID);
meta.nickname = readStringAttribute(in, ATTR_NICKNAME);
- meta.userFlags = readIntAttribute(in, ATTR_USER_FLAGS);
- meta.createdMillis = readLongAttribute(in, ATTR_CREATED_MILLIS, 0);
- meta.lastSeenMillis = readLongAttribute(in, ATTR_LAST_SEEN_MILLIS, 0);
- meta.lastTrimMillis = readLongAttribute(in, ATTR_LAST_TRIM_MILLIS, 0);
- meta.lastBenchMillis = readLongAttribute(in, ATTR_LAST_BENCH_MILLIS, 0);
+ meta.userFlags = in.getAttributeInt(null, ATTR_USER_FLAGS);
+ meta.createdMillis = in.getAttributeLong(null, ATTR_CREATED_MILLIS, 0);
+ meta.lastSeenMillis = in.getAttributeLong(null, ATTR_LAST_SEEN_MILLIS, 0);
+ meta.lastTrimMillis = in.getAttributeLong(null, ATTR_LAST_TRIM_MILLIS, 0);
+ meta.lastBenchMillis = in.getAttributeLong(null, ATTR_LAST_BENCH_MILLIS, 0);
return meta;
}
- public static void writeVolumeRecord(XmlSerializer out, VolumeRecord rec) throws IOException {
+ public static void writeVolumeRecord(TypedXmlSerializer out, VolumeRecord rec)
+ throws IOException {
out.startTag(null, TAG_VOLUME);
- writeIntAttribute(out, ATTR_TYPE, rec.type);
+ out.attributeInt(null, ATTR_TYPE, rec.type);
writeStringAttribute(out, ATTR_FS_UUID, rec.fsUuid);
writeStringAttribute(out, ATTR_PART_GUID, rec.partGuid);
writeStringAttribute(out, ATTR_NICKNAME, rec.nickname);
- writeIntAttribute(out, ATTR_USER_FLAGS, rec.userFlags);
- writeLongAttribute(out, ATTR_CREATED_MILLIS, rec.createdMillis);
- writeLongAttribute(out, ATTR_LAST_SEEN_MILLIS, rec.lastSeenMillis);
- writeLongAttribute(out, ATTR_LAST_TRIM_MILLIS, rec.lastTrimMillis);
- writeLongAttribute(out, ATTR_LAST_BENCH_MILLIS, rec.lastBenchMillis);
+ out.attributeInt(null, ATTR_USER_FLAGS, rec.userFlags);
+ out.attributeLong(null, ATTR_CREATED_MILLIS, rec.createdMillis);
+ out.attributeLong(null, ATTR_LAST_SEEN_MILLIS, rec.lastSeenMillis);
+ out.attributeLong(null, ATTR_LAST_TRIM_MILLIS, rec.lastTrimMillis);
+ out.attributeLong(null, ATTR_LAST_BENCH_MILLIS, rec.lastBenchMillis);
out.endTag(null, TAG_VOLUME);
}
@@ -2604,32 +2569,6 @@ class StorageManagerService extends IStorageManager.Stub
Binder.restoreCallingIdentity(token);
}
}
-
- if ((mask & (StorageManager.DEBUG_ISOLATED_STORAGE_FORCE_ON
- | StorageManager.DEBUG_ISOLATED_STORAGE_FORCE_OFF)) != 0) {
- final int value;
- if ((flags & StorageManager.DEBUG_ISOLATED_STORAGE_FORCE_ON) != 0) {
- value = 1;
- } else if ((flags & StorageManager.DEBUG_ISOLATED_STORAGE_FORCE_OFF) != 0) {
- value = -1;
- } else {
- value = 0;
- }
-
- final long token = Binder.clearCallingIdentity();
- try {
- Settings.Global.putInt(mContext.getContentResolver(),
- Settings.Global.ISOLATED_STORAGE_LOCAL, value);
- refreshIsolatedStorageSettings();
-
- // Perform hard reboot to kick policy into place
- mHandler.post(() -> {
- mContext.getSystemService(PowerManager.class).reboot(null);
- });
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- }
}
@Override
@@ -4149,15 +4088,6 @@ class StorageManagerService extends IStorageManager.Stub
}
}
- private int getMountMode(int uid, String packageName) {
- final int mode = getMountModeInternal(uid, packageName);
- if (LOCAL_LOGV) {
- Slog.v(TAG, "Resolved mode " + mode + " for " + packageName + "/"
- + UserHandle.formatUid(uid));
- }
- return mode;
- }
-
private int getMountModeInternal(int uid, String packageName) {
try {
// Get some easy cases out of the way first
@@ -4398,17 +4328,6 @@ class StorageManagerService extends IStorageManager.Stub
pw.println();
pw.println("Local unlocked users: " + mLocalUnlockedUsers);
pw.println("System unlocked users: " + Arrays.toString(mSystemUnlockedUsers));
-
- final ContentResolver cr = mContext.getContentResolver();
- pw.println();
- pw.println("Isolated storage, local feature flag: "
- + Settings.Global.getInt(cr, Settings.Global.ISOLATED_STORAGE_LOCAL, 0));
- pw.println("Isolated storage, remote feature flag: "
- + Settings.Global.getInt(cr, Settings.Global.ISOLATED_STORAGE_REMOTE, 0));
- pw.println("Isolated storage, resolved: " + StorageManager.hasIsolatedStorage());
- pw.println("Forced scoped storage app list: "
- + DeviceConfig.getProperty(DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT,
- PROP_FORCED_SCOPED_STORAGE_WHITELIST));
pw.println("isAutomotive:" + mIsAutomotive);
}
@@ -4460,20 +4379,10 @@ class StorageManagerService extends IStorageManager.Stub
}
private final class StorageManagerInternalImpl extends StorageManagerInternal {
- // Not guarded by a lock.
- private final CopyOnWriteArrayList<ExternalStorageMountPolicy> mPolicies =
- new CopyOnWriteArrayList<>();
-
@GuardedBy("mResetListeners")
private final List<StorageManagerInternal.ResetListener> mResetListeners =
new ArrayList<>();
- @Override
- public void addExternalStoragePolicy(ExternalStorageMountPolicy policy) {
- // No locking - CopyOnWriteArrayList
- mPolicies.add(policy);
- }
-
/**
* Check if fuse is running in target user, if it's running then setup its storage dirs.
* Return true if storage dirs are mounted.
@@ -4518,30 +4427,12 @@ class StorageManagerService extends IStorageManager.Stub
@Override
public int getExternalStorageMountMode(int uid, String packageName) {
- if (ENABLE_ISOLATED_STORAGE) {
- return getMountMode(uid, packageName);
- }
- try {
- if (packageName == null) {
- final String[] packagesForUid = mIPackageManager.getPackagesForUid(uid);
- packageName = packagesForUid[0];
- }
- } catch (RemoteException e) {
- // Should not happen - same process
- }
- // No locking - CopyOnWriteArrayList
- int mountMode = Integer.MAX_VALUE;
- for (ExternalStorageMountPolicy policy : mPolicies) {
- final int policyMode = policy.getMountMode(uid, packageName);
- if (policyMode == Zygote.MOUNT_EXTERNAL_NONE) {
- return Zygote.MOUNT_EXTERNAL_NONE;
- }
- mountMode = Math.min(mountMode, policyMode);
- }
- if (mountMode == Integer.MAX_VALUE) {
- return Zygote.MOUNT_EXTERNAL_NONE;
+ final int mode = getMountModeInternal(uid, packageName);
+ if (LOCAL_LOGV) {
+ Slog.v(TAG, "Resolved mode " + mode + " for " + packageName + "/"
+ + UserHandle.formatUid(uid));
}
- return mountMode;
+ return mode;
}
@Override
@@ -4611,17 +4502,8 @@ class StorageManagerService extends IStorageManager.Stub
if (uid == Process.SYSTEM_UID) {
return true;
}
- if (ENABLE_ISOLATED_STORAGE) {
- return getMountMode(uid, packageName) != Zygote.MOUNT_EXTERNAL_NONE;
- }
- // No locking - CopyOnWriteArrayList
- for (ExternalStorageMountPolicy policy : mPolicies) {
- final boolean policyHasStorage = policy.hasExternalStorage(uid, packageName);
- if (!policyHasStorage) {
- return false;
- }
- }
- return true;
+
+ return getExternalStorageMountMode(uid, packageName) != Zygote.MOUNT_EXTERNAL_NONE;
}
private void killAppForOpChange(int code, int uid) {
diff --git a/services/core/java/com/android/server/SystemUpdateManagerService.java b/services/core/java/com/android/server/SystemUpdateManagerService.java
index 61a7d00faeb8..fcba9b56a541 100644
--- a/services/core/java/com/android/server/SystemUpdateManagerService.java
+++ b/services/core/java/com/android/server/SystemUpdateManagerService.java
@@ -201,7 +201,7 @@ public class SystemUpdateManagerService extends ISystemUpdateManager.Stub {
// Performs I/O work only, without validating the loaded info.
@Nullable
- private PersistableBundle readInfoFileLocked(XmlPullParser parser)
+ private PersistableBundle readInfoFileLocked(TypedXmlPullParser parser)
throws XmlPullParserException, IOException {
int type;
while ((type = parser.next()) != END_DOCUMENT) {
diff --git a/services/core/java/com/android/server/TEST_MAPPING b/services/core/java/com/android/server/TEST_MAPPING
index ebeec39d6ae6..95af84293377 100644
--- a/services/core/java/com/android/server/TEST_MAPPING
+++ b/services/core/java/com/android/server/TEST_MAPPING
@@ -29,6 +29,10 @@
{
"name": "CtsScopedStorageHostTest",
"file_patterns": ["StorageManagerService\\.java"]
+ },
+ {
+ "name": "CtsScopedStorageDeviceOnlyTest",
+ "file_patterns": ["StorageManagerService\\.java"]
}
]
}
diff --git a/services/core/java/com/android/server/TestNetworkService.java b/services/core/java/com/android/server/TestNetworkService.java
index d6bd5a1d7c4c..a45466d98563 100644
--- a/services/core/java/com/android/server/TestNetworkService.java
+++ b/services/core/java/com/android/server/TestNetworkService.java
@@ -29,9 +29,9 @@ import android.net.IpPrefix;
import android.net.LinkAddress;
import android.net.LinkProperties;
import android.net.NetworkAgent;
+import android.net.NetworkAgentConfig;
import android.net.NetworkCapabilities;
-import android.net.NetworkInfo;
-import android.net.NetworkInfo.DetailedState;
+import android.net.NetworkProvider;
import android.net.RouteInfo;
import android.net.StringNetworkSpecifier;
import android.net.TestNetworkInterface;
@@ -62,7 +62,8 @@ import java.util.concurrent.atomic.AtomicInteger;
/** @hide */
class TestNetworkService extends ITestNetworkManager.Stub {
@NonNull private static final String TAG = TestNetworkService.class.getSimpleName();
- @NonNull private static final String TEST_NETWORK_TYPE = "TEST_NETWORK";
+ @NonNull private static final String TEST_NETWORK_LOGTAG = "TestNetworkAgent";
+ @NonNull private static final String TEST_NETWORK_PROVIDER_NAME = TAG;
@NonNull private static final AtomicInteger sTestTunIndex = new AtomicInteger();
@NonNull private final Context mContext;
@@ -72,6 +73,9 @@ class TestNetworkService extends ITestNetworkManager.Stub {
@NonNull private final HandlerThread mHandlerThread;
@NonNull private final Handler mHandler;
+ @NonNull private final ConnectivityManager mCm;
+ @NonNull private final NetworkProvider mNetworkProvider;
+
// Native method stubs
private static native int jniCreateTunTap(boolean isTun, @NonNull String iface);
@@ -85,6 +89,10 @@ class TestNetworkService extends ITestNetworkManager.Stub {
mContext = Objects.requireNonNull(context, "missing Context");
mNMS = Objects.requireNonNull(netManager, "missing INetworkManagementService");
mNetd = Objects.requireNonNull(NetdService.getInstance(), "could not get netd instance");
+ mCm = mContext.getSystemService(ConnectivityManager.class);
+ mNetworkProvider = new NetworkProvider(mContext, mHandler.getLooper(),
+ TEST_NETWORK_PROVIDER_NAME);
+ mCm.registerNetworkProvider(mNetworkProvider);
}
/**
@@ -150,9 +158,6 @@ class TestNetworkService extends ITestNetworkManager.Stub {
private static final int NETWORK_SCORE = 1; // Use a low, non-zero score.
private final int mUid;
- @NonNull private final NetworkInfo mNi;
- @NonNull private final NetworkCapabilities mNc;
- @NonNull private final LinkProperties mLp;
@GuardedBy("mBinderLock")
@NonNull
@@ -161,20 +166,18 @@ class TestNetworkService extends ITestNetworkManager.Stub {
@NonNull private final Object mBinderLock = new Object();
private TestNetworkAgent(
- @NonNull Looper looper,
@NonNull Context context,
- @NonNull NetworkInfo ni,
+ @NonNull Looper looper,
+ @NonNull NetworkAgentConfig config,
@NonNull NetworkCapabilities nc,
@NonNull LinkProperties lp,
int uid,
- @NonNull IBinder binder)
+ @NonNull IBinder binder,
+ @NonNull NetworkProvider np)
throws RemoteException {
- super(looper, context, TEST_NETWORK_TYPE, ni, nc, lp, NETWORK_SCORE);
+ super(context, looper, TEST_NETWORK_LOGTAG, nc, lp, NETWORK_SCORE, config, np);
mUid = uid;
- mNi = ni;
- mNc = nc;
- mLp = lp;
synchronized (mBinderLock) {
mBinder = binder; // Binder null-checks in create()
@@ -203,9 +206,7 @@ class TestNetworkService extends ITestNetworkManager.Stub {
}
private void teardown() {
- mNi.setDetailedState(DetailedState.DISCONNECTED, null, null);
- mNi.setIsAvailable(false);
- sendNetworkInfo(mNi);
+ unregister();
// Synchronize on mBinderLock to ensure that unlinkToDeath is never called more than
// once (otherwise it could throw an exception)
@@ -238,11 +239,6 @@ class TestNetworkService extends ITestNetworkManager.Stub {
Objects.requireNonNull(context, "missing Context");
// iface and binder validity checked by caller
- // Build network info with special testing type
- NetworkInfo ni = new NetworkInfo(ConnectivityManager.TYPE_TEST, 0, TEST_NETWORK_TYPE, "");
- ni.setDetailedState(DetailedState.CONNECTED, null, null);
- ni.setIsAvailable(true);
-
// Build narrow set of NetworkCapabilities, useful only for testing
NetworkCapabilities nc = new NetworkCapabilities();
nc.clearAll(); // Remove default capabilities.
@@ -290,7 +286,12 @@ class TestNetworkService extends ITestNetworkManager.Stub {
lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null, iface));
}
- return new TestNetworkAgent(looper, context, ni, nc, lp, callingUid, binder);
+ final TestNetworkAgent agent = new TestNetworkAgent(context, looper,
+ new NetworkAgentConfig.Builder().build(), nc, lp, callingUid, binder,
+ mNetworkProvider);
+ agent.register();
+ agent.markConnected();
+ return agent;
}
/**
diff --git a/services/core/java/com/android/server/accounts/AccountManagerBackupHelper.java b/services/core/java/com/android/server/accounts/AccountManagerBackupHelper.java
index 1c77a7f451b4..b379b5dc681a 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerBackupHelper.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerBackupHelper.java
@@ -23,25 +23,21 @@ import android.annotation.IntRange;
import android.annotation.NonNull;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
-import android.content.pm.Signature;
-import android.database.Cursor;
-import android.database.sqlite.SQLiteDatabase;
import android.os.UserHandle;
import android.text.TextUtils;
import android.util.Log;
import android.util.PackageUtils;
import android.util.Pair;
import android.util.Slog;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
import android.util.Xml;
+
import com.android.internal.annotations.GuardedBy;
import com.android.internal.content.PackageMonitor;
-import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.XmlUtils;
-import com.android.server.accounts.AccountsDb.DeDatabaseHelper;
-import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
@@ -163,7 +159,7 @@ public final class AccountManagerBackupHelper {
}
try {
ByteArrayOutputStream dataStream = new ByteArrayOutputStream();
- final XmlSerializer serializer = new FastXmlSerializer();
+ final TypedXmlSerializer serializer = Xml.newFastSerializer();
serializer.setOutput(dataStream, StandardCharsets.UTF_8.name());
serializer.startDocument(null, true);
serializer.startTag(null, TAG_PERMISSIONS);
@@ -216,7 +212,7 @@ public final class AccountManagerBackupHelper {
public void restoreAccountAccessPermissions(byte[] data, int userId) {
try {
ByteArrayInputStream dataStream = new ByteArrayInputStream(data);
- XmlPullParser parser = Xml.newPullParser();
+ TypedXmlPullParser parser = Xml.newFastPullParser();
parser.setInput(dataStream, StandardCharsets.UTF_8.name());
PackageManager packageManager = mAccountManagerService.mContext.getPackageManager();
diff --git a/services/core/java/com/android/server/adb/AdbDebuggingManager.java b/services/core/java/com/android/server/adb/AdbDebuggingManager.java
index f59af76ead8f..d99b195351f1 100644
--- a/services/core/java/com/android/server/adb/AdbDebuggingManager.java
+++ b/services/core/java/com/android/server/adb/AdbDebuggingManager.java
@@ -1947,8 +1947,7 @@ public class AdbDebuggingManager {
+ tagName);
return keyMap;
}
- int keystoreVersion = Integer.parseInt(
- parser.getAttributeValue(null, XML_ATTRIBUTE_VERSION));
+ int keystoreVersion = parser.getAttributeInt(null, XML_ATTRIBUTE_VERSION);
if (keystoreVersion > MAX_SUPPORTED_KEYSTORE_VERSION) {
Slog.e(TAG, "Keystore version=" + keystoreVersion
+ " not supported (max_supported="
@@ -2068,8 +2067,7 @@ public class AdbDebuggingManager {
+ tagName);
return trustedNetworks;
}
- int keystoreVersion = Integer.parseInt(
- parser.getAttributeValue(null, XML_ATTRIBUTE_VERSION));
+ int keystoreVersion = parser.getAttributeInt(null, XML_ATTRIBUTE_VERSION);
if (keystoreVersion > MAX_SUPPORTED_KEYSTORE_VERSION) {
Slog.e(TAG, "Keystore version=" + keystoreVersion
+ " not supported (max_supported="
@@ -2148,7 +2146,7 @@ public class AdbDebuggingManager {
serializer.startDocument(null, true);
serializer.startTag(null, XML_KEYSTORE_START_TAG);
- serializer.attribute(null, XML_ATTRIBUTE_VERSION, String.valueOf(KEYSTORE_VERSION));
+ serializer.attributeInt(null, XML_ATTRIBUTE_VERSION, KEYSTORE_VERSION);
for (Map.Entry<String, Long> keyEntry : mKeyMap.entrySet()) {
serializer.startTag(null, XML_TAG_ADB_KEY);
serializer.attribute(null, XML_ATTRIBUTE_KEY, keyEntry.getKey());
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 872902626fb4..c7e3b2344f54 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -91,6 +91,7 @@ import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.TransactionTooLargeException;
import android.os.UserHandle;
+import android.os.UserManager;
import android.provider.Settings;
import android.stats.devicepolicy.DevicePolicyEnums;
import android.text.TextUtils;
@@ -165,6 +166,7 @@ public final class ActiveServices {
public static final int FGS_FEATURE_ALLOWED_BY_DEVICE_IDLE_ALLOW_LIST = 15;
public static final int FGS_FEATURE_ALLOWED_BY_SYSTEM_ALERT_WINDOW_PERMISSION = 16;
public static final int FGS_FEATURE_ALLOWED_BY_FGS_BINDING = 17;
+ public static final int FGS_FEATURE_ALLOWED_BY_DEVICE_DEMO_MODE = 18;
@IntDef(flag = true, prefix = { "FGS_FEATURE_" }, value = {
FGS_FEATURE_DENIED,
@@ -183,7 +185,8 @@ public final class ActiveServices {
FGS_FEATURE_ALLOWED_BY_DEVICE_OWNER,
FGS_FEATURE_ALLOWED_BY_DEVICE_IDLE_ALLOW_LIST,
FGS_FEATURE_ALLOWED_BY_SYSTEM_ALERT_WINDOW_PERMISSION,
- FGS_FEATURE_ALLOWED_BY_FGS_BINDING
+ FGS_FEATURE_ALLOWED_BY_FGS_BINDING,
+ FGS_FEATURE_ALLOWED_BY_DEVICE_DEMO_MODE
})
@Retention(RetentionPolicy.SOURCE)
public @interface FgsFeatureRetCode {}
@@ -4987,14 +4990,16 @@ public final class ActiveServices {
* - the first arg isn't the flattened component name of an existing service:
* dump all services whose component contains the first arg as a substring
*/
- protected boolean dumpService(FileDescriptor fd, PrintWriter pw, final String name,
+ protected boolean dumpService(FileDescriptor fd, PrintWriter pw, String name, int[] users,
String[] args, int opti, boolean dumpAll) {
final ArrayList<ServiceRecord> services = new ArrayList<>();
final Predicate<ServiceRecord> filter = DumpUtils.filterRecord(name);
synchronized (mAm) {
- int[] users = mAm.mUserController.getUsers();
+ if (users == null) {
+ users = mAm.mUserController.getUsers();
+ }
for (int user : users) {
ServiceMap smap = mServiceMap.get(user);
@@ -5039,11 +5044,13 @@ public final class ActiveServices {
String innerPrefix = prefix + " ";
synchronized (mAm) {
pw.print(prefix); pw.print("SERVICE ");
- pw.print(r.shortInstanceName); pw.print(" ");
- pw.print(Integer.toHexString(System.identityHashCode(r)));
- pw.print(" pid=");
- if (r.app != null) pw.println(r.app.pid);
- else pw.println("(not running)");
+ pw.print(r.shortInstanceName); pw.print(" ");
+ pw.print(Integer.toHexString(System.identityHashCode(r)));
+ pw.print(" pid=");
+ if (r.app != null) {
+ pw.print(r.app.pid);
+ pw.print(" user="); pw.println(r.userId);
+ } else pw.println("(not running)");
if (dumpAll) {
r.dump(pw, innerPrefix);
}
@@ -5283,6 +5290,12 @@ public final class ActiveServices {
}
}
+ if (ret == FGS_FEATURE_DENIED) {
+ if (UserManager.isDeviceInDemoMode(mAm.mContext)) {
+ ret = FGS_FEATURE_ALLOWED_BY_DEVICE_DEMO_MODE;
+ }
+ }
+
final String debugInfo =
"[callingPackage: " + callingPackage
+ "; callingUid: " + callingUid
@@ -5336,6 +5349,8 @@ public final class ActiveServices {
return "ALLOWED_BY_SYSTEM_ALERT_WINDOW_PERMISSION";
case FGS_FEATURE_ALLOWED_BY_FGS_BINDING:
return "ALLOWED_BY_FGS_BINDING";
+ case FGS_FEATURE_ALLOWED_BY_DEVICE_DEMO_MODE:
+ return "ALLOWED_BY_DEVICE_DEMO_MODE";
default:
return "";
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 75e8b13ccc0d..da6e7ff84525 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -252,6 +252,7 @@ import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.ServiceManager;
+import android.os.SharedMemory;
import android.os.ShellCallback;
import android.os.StrictMode;
import android.os.SystemClock;
@@ -348,6 +349,7 @@ import com.android.server.appop.AppOpsService;
import com.android.server.compat.PlatformCompat;
import com.android.server.contentcapture.ContentCaptureManagerInternal;
import com.android.server.firewall.IntentFirewall;
+import com.android.server.graphics.fonts.FontManagerInternal;
import com.android.server.job.JobSchedulerInternal;
import com.android.server.pm.Installer;
import com.android.server.pm.permission.PermissionManagerServiceInternal;
@@ -4358,6 +4360,11 @@ public class ActivityManagerService extends IActivityManager.Stub
app.info.packageName);
}
}
+ SharedMemory serializedSystemFontMap = null;
+ final FontManagerInternal fm = LocalServices.getService(FontManagerInternal.class);
+ if (fm != null) {
+ serializedSystemFontMap = fm.getSerializedSystemFontMap();
+ }
checkTime(startTime, "attachApplicationLocked: immediately before bindApplication");
bindApplicationTimeMillis = SystemClock.elapsedRealtime();
@@ -4383,7 +4390,7 @@ public class ActivityManagerService extends IActivityManager.Stub
app.compat, getCommonServicesLocked(app.isolated),
mCoreSettingsObserver.getCoreSettingsLocked(),
buildSerial, autofillOptions, contentCaptureOptions,
- app.mDisabledCompatChanges);
+ app.mDisabledCompatChanges, serializedSystemFontMap);
} else {
thread.bindApplication(processName, appInfo, providerList, null, profilerInfo,
null, null, null, testMode,
@@ -4393,7 +4400,7 @@ public class ActivityManagerService extends IActivityManager.Stub
app.compat, getCommonServicesLocked(app.isolated),
mCoreSettingsObserver.getCoreSettingsLocked(),
buildSerial, autofillOptions, contentCaptureOptions,
- app.mDisabledCompatChanges);
+ app.mDisabledCompatChanges, serializedSystemFontMap);
}
if (profilerInfo != null) {
profilerInfo.closeFd();
@@ -5644,7 +5651,7 @@ public class ActivityManagerService extends IActivityManager.Stub
@Override
public List<RunningTaskInfo> getTasks(int maxNum) {
- return mActivityTaskManager.getTasks(maxNum);
+ return mActivityTaskManager.getTasks(maxNum, false /* filterForVisibleRecents */);
}
@Override
@@ -8664,17 +8671,30 @@ public class ActivityManagerService extends IActivityManager.Stub
} else if ("service".equals(cmd)) {
String[] newArgs;
String name;
+ int[] users = null;
if (opti >= args.length) {
name = null;
newArgs = EMPTY_STRING_ARRAY;
} else {
name = args[opti];
opti++;
+ if ("--user".equals(name) && opti < args.length) {
+ int userId = UserHandle.parseUserArg(args[opti]);
+ opti++;
+ if (userId != UserHandle.USER_ALL) {
+ if (userId == UserHandle.USER_CURRENT) {
+ userId = getCurrentUser().id;
+ }
+ users = new int[] { userId };
+ }
+ name = args[opti];
+ opti++;
+ }
newArgs = new String[args.length - opti];
if (args.length > 2) System.arraycopy(args, opti, newArgs, 0,
args.length - opti);
}
- if (!mServices.dumpService(fd, pw, name, newArgs, 0, dumpAll)) {
+ if (!mServices.dumpService(fd, pw, name, users, newArgs, 0, dumpAll)) {
pw.println("No services match: " + name);
pw.println("Use -h for help.");
}
diff --git a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
index 28afcbbb2a86..7299e814b020 100644
--- a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
+++ b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
@@ -88,6 +88,8 @@ public class SettingsToPropertiesMapper {
DeviceConfig.NAMESPACE_PROFCOLLECT_NATIVE_BOOT,
DeviceConfig.NAMESPACE_RUNTIME_NATIVE,
DeviceConfig.NAMESPACE_RUNTIME_NATIVE_BOOT,
+ DeviceConfig.NAMESPACE_STATSD_NATIVE,
+ DeviceConfig.NAMESPACE_STATSD_NATIVE_BOOT,
DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT,
DeviceConfig.NAMESPACE_WINDOW_MANAGER_NATIVE_BOOT,
};
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index da4704097ad0..d4e2d27ca7a1 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -124,7 +124,6 @@ import android.os.ShellCommand;
import android.os.SystemClock;
import android.os.UserHandle;
import android.os.UserManager;
-import android.os.storage.StorageManager;
import android.os.storage.StorageManagerInternal;
import android.provider.Settings;
import android.util.ArrayMap;
@@ -155,10 +154,8 @@ import com.android.internal.app.IAppOpsService;
import com.android.internal.app.IAppOpsStartedCallback;
import com.android.internal.app.MessageSamplingConfig;
import com.android.internal.compat.IPlatformCompat;
-import com.android.internal.os.Zygote;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.DumpUtils;
-import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.Preconditions;
import com.android.internal.util.XmlUtils;
import com.android.internal.util.function.pooled.PooledLambda;
@@ -175,7 +172,6 @@ import org.json.JSONException;
import org.json.JSONObject;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
import java.io.File;
import java.io.FileDescriptor;
@@ -185,7 +181,6 @@ import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
-import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
@@ -1057,19 +1052,20 @@ public class AppOpsService extends IAppOpsService.Stub {
}
int numInProgressEvents = mInProgressEvents.size();
+ List<IBinder> binders = new ArrayList<>(mInProgressEvents.keySet());
for (int i = 0; i < numInProgressEvents; i++) {
- InProgressStartOpEvent event = mInProgressEvents.valueAt(i);
+ InProgressStartOpEvent event = mInProgressEvents.get(binders.get(i));
- if (event.getUidState() != newState) {
+ if (event != null && event.getUidState() != newState) {
try {
// Remove all but one unfinished start count and then call finished() to
// remove start event object
int numPreviousUnfinishedStarts = event.numUnfinishedStarts;
event.numUnfinishedStarts = 1;
- finished(event.getClientId(), false);
-
OpEventProxyInfo proxy = event.getProxy();
+ finished(event.getClientId(), false);
+
// Call started() to add a new start event object and then add the
// previously removed unfinished start counts back
if (proxy != null) {
@@ -1079,7 +1075,11 @@ public class AppOpsService extends IAppOpsService.Stub {
started(event.getClientId(), Process.INVALID_UID, null, null, newState,
OP_FLAG_SELF, false);
}
- event.numUnfinishedStarts += numPreviousUnfinishedStarts - 1;
+
+ InProgressStartOpEvent newEvent = mInProgressEvents.get(binders.get(i));
+ if (newEvent != null) {
+ newEvent.numUnfinishedStarts += numPreviousUnfinishedStarts - 1;
+ }
} catch (RemoteException e) {
if (DEBUG) Slog.e(TAG, "Cannot switch to new uidState " + newState);
}
@@ -1764,26 +1764,6 @@ public class AppOpsService extends IAppOpsService.Stub {
}
});
- if (!StorageManager.hasIsolatedStorage()) {
- StorageManagerInternal storageManagerInternal = LocalServices.getService(
- StorageManagerInternal.class);
- storageManagerInternal.addExternalStoragePolicy(
- new StorageManagerInternal.ExternalStorageMountPolicy() {
- @Override
- public int getMountMode(int uid, String packageName) {
- if (Process.isIsolated(uid)) {
- return Zygote.MOUNT_EXTERNAL_NONE;
- }
- return Zygote.MOUNT_EXTERNAL_DEFAULT;
- }
-
- @Override
- public boolean hasExternalStorage(int uid, String packageName) {
- final int mountMode = getMountMode(uid, packageName);
- return mountMode != Zygote.MOUNT_EXTERNAL_NONE;
- }
- });
- }
mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
}
@@ -4285,10 +4265,7 @@ public class AppOpsService extends IAppOpsService.Stub {
throw new IllegalStateException("no start tag found");
}
- final String versionString = parser.getAttributeValue(null, "v");
- if (versionString != null) {
- oldVersion = Integer.parseInt(versionString);
- }
+ oldVersion = parser.getAttributeInt(null, "v", NO_VERSION);
int outerDepth = parser.getDepth();
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
@@ -4388,9 +4365,9 @@ public class AppOpsService extends IAppOpsService.Stub {
scheduleFastWriteLocked();
}
- private void readUidOps(XmlPullParser parser) throws NumberFormatException,
+ private void readUidOps(TypedXmlPullParser parser) throws NumberFormatException,
XmlPullParserException, IOException {
- final int uid = Integer.parseInt(parser.getAttributeValue(null, "n"));
+ final int uid = parser.getAttributeInt(null, "n");
int outerDepth = parser.getDepth();
int type;
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
@@ -4401,8 +4378,8 @@ public class AppOpsService extends IAppOpsService.Stub {
String tagName = parser.getName();
if (tagName.equals("op")) {
- final int code = Integer.parseInt(parser.getAttributeValue(null, "n"));
- final int mode = Integer.parseInt(parser.getAttributeValue(null, "m"));
+ final int code = parser.getAttributeInt(null, "n");
+ final int mode = parser.getAttributeInt(null, "m");
setUidMode(code, uid, mode);
} else {
Slog.w(TAG, "Unknown element under <uid-ops>: "
@@ -4412,7 +4389,7 @@ public class AppOpsService extends IAppOpsService.Stub {
}
}
- private void readPackage(XmlPullParser parser)
+ private void readPackage(TypedXmlPullParser parser)
throws NumberFormatException, XmlPullParserException, IOException {
String pkgName = parser.getAttributeValue(null, "n");
int outerDepth = parser.getDepth();
@@ -4434,9 +4411,9 @@ public class AppOpsService extends IAppOpsService.Stub {
}
}
- private void readUid(XmlPullParser parser, String pkgName)
+ private void readUid(TypedXmlPullParser parser, String pkgName)
throws NumberFormatException, XmlPullParserException, IOException {
- int uid = Integer.parseInt(parser.getAttributeValue(null, "n"));
+ int uid = parser.getAttributeInt(null, "n");
final UidState uidState = getUidStateLocked(uid, true);
int outerDepth = parser.getDepth();
int type;
@@ -4457,19 +4434,20 @@ public class AppOpsService extends IAppOpsService.Stub {
uidState.evalForegroundOps(mOpModeWatchers);
}
- private void readAttributionOp(XmlPullParser parser, @NonNull Op parent,
- @Nullable String attribution) throws NumberFormatException, IOException {
+ private void readAttributionOp(TypedXmlPullParser parser, @NonNull Op parent,
+ @Nullable String attribution)
+ throws NumberFormatException, IOException, XmlPullParserException {
final AttributedOp attributedOp = parent.getOrCreateAttribution(parent, attribution);
- final long key = XmlUtils.readLongAttribute(parser, "n");
+ final long key = parser.getAttributeLong(null, "n");
final int uidState = extractUidStateFromKey(key);
final int opFlags = extractFlagsFromKey(key);
- final long accessTime = XmlUtils.readLongAttribute(parser, "t", 0);
- final long rejectTime = XmlUtils.readLongAttribute(parser, "r", 0);
- final long accessDuration = XmlUtils.readLongAttribute(parser, "d", -1);
+ final long accessTime = parser.getAttributeLong(null, "t", 0);
+ final long rejectTime = parser.getAttributeLong(null, "r", 0);
+ final long accessDuration = parser.getAttributeLong(null, "d", -1);
final String proxyPkg = XmlUtils.readStringAttribute(parser, "pp");
- final int proxyUid = XmlUtils.readIntAttribute(parser, "pu", Process.INVALID_UID);
+ final int proxyUid = parser.getAttributeInt(null, "pu", Process.INVALID_UID);
final String proxyAttributionTag = XmlUtils.readStringAttribute(parser, "pc");
if (accessTime > 0) {
@@ -4481,14 +4459,13 @@ public class AppOpsService extends IAppOpsService.Stub {
}
}
- private void readOp(XmlPullParser parser, @NonNull UidState uidState, @NonNull String pkgName)
- throws NumberFormatException,
- XmlPullParserException, IOException {
- int opCode = Integer.parseInt(parser.getAttributeValue(null, "n"));
+ private void readOp(TypedXmlPullParser parser,
+ @NonNull UidState uidState, @NonNull String pkgName)
+ throws NumberFormatException, XmlPullParserException, IOException {
+ int opCode = parser.getAttributeInt(null, "n");
Op op = new Op(uidState, pkgName, opCode, uidState.uid);
- final int mode = XmlUtils.readIntAttribute(parser, "m",
- AppOpsManager.opToDefaultMode(op.op));
+ final int mode = parser.getAttributeInt(null, "m", AppOpsManager.opToDefaultMode(op.op));
op.mode = mode;
int outerDepth = parser.getDepth();
@@ -4535,7 +4512,7 @@ public class AppOpsService extends IAppOpsService.Stub {
TypedXmlSerializer out = Xml.resolveSerializer(stream);
out.startDocument(null, true);
out.startTag(null, "app-ops");
- out.attribute(null, "v", String.valueOf(CURRENT_VERSION));
+ out.attributeInt(null, "v", CURRENT_VERSION);
SparseArray<SparseIntArray> uidStatesClone;
synchronized (this) {
@@ -4565,15 +4542,14 @@ public class AppOpsService extends IAppOpsService.Stub {
SparseIntArray opModes = uidStatesClone.valueAt(uidStateNum);
if (opModes != null && opModes.size() > 0) {
out.startTag(null, "uid");
- out.attribute(null, "n",
- Integer.toString(uidStatesClone.keyAt(uidStateNum)));
+ out.attributeInt(null, "n", uidStatesClone.keyAt(uidStateNum));
final int opCount = opModes.size();
for (int opCountNum = 0; opCountNum < opCount; opCountNum++) {
final int op = opModes.keyAt(opCountNum);
final int mode = opModes.valueAt(opCountNum);
out.startTag(null, "op");
- out.attribute(null, "n", Integer.toString(op));
- out.attribute(null, "m", Integer.toString(mode));
+ out.attributeInt(null, "n", op);
+ out.attributeInt(null, "m", mode);
out.endTag(null, "op");
}
out.endTag(null, "uid");
@@ -4593,14 +4569,14 @@ public class AppOpsService extends IAppOpsService.Stub {
out.attribute(null, "n", lastPkg);
}
out.startTag(null, "uid");
- out.attribute(null, "n", Integer.toString(pkg.getUid()));
+ out.attributeInt(null, "n", pkg.getUid());
List<AppOpsManager.OpEntry> ops = pkg.getOps();
for (int j=0; j<ops.size(); j++) {
AppOpsManager.OpEntry op = ops.get(j);
out.startTag(null, "op");
- out.attribute(null, "n", Integer.toString(op.getOp()));
+ out.attributeInt(null, "n", op.getOp());
if (op.getMode() != AppOpsManager.opToDefaultMode(op.getOp())) {
- out.attribute(null, "m", Integer.toString(op.getMode()));
+ out.attributeInt(null, "m", op.getMode());
}
for (String attributionTag : op.getAttributedOpEntries().keySet()) {
@@ -4644,15 +4620,15 @@ public class AppOpsService extends IAppOpsService.Stub {
if (attributionTag != null) {
out.attribute(null, "id", attributionTag);
}
- out.attribute(null, "n", Long.toString(key));
+ out.attributeLong(null, "n", key);
if (accessTime > 0) {
- out.attribute(null, "t", Long.toString(accessTime));
+ out.attributeLong(null, "t", accessTime);
}
if (rejectTime > 0) {
- out.attribute(null, "r", Long.toString(rejectTime));
+ out.attributeLong(null, "r", rejectTime);
}
if (accessDuration > 0) {
- out.attribute(null, "d", Long.toString(accessDuration));
+ out.attributeLong(null, "d", accessDuration);
}
if (proxyPkg != null) {
out.attribute(null, "pp", proxyPkg);
@@ -4661,7 +4637,7 @@ public class AppOpsService extends IAppOpsService.Stub {
out.attribute(null, "pc", proxyAttributionTag);
}
if (proxyUid >= 0) {
- out.attribute(null, "pu", Integer.toString(proxyUid));
+ out.attributeInt(null, "pu", proxyUid);
}
out.endTag(null, "st");
}
diff --git a/services/core/java/com/android/server/appop/HistoricalRegistry.java b/services/core/java/com/android/server/appop/HistoricalRegistry.java
index f49b5dca2b08..676fcd0bdc87 100644
--- a/services/core/java/com/android/server/appop/HistoricalRegistry.java
+++ b/services/core/java/com/android/server/appop/HistoricalRegistry.java
@@ -49,6 +49,8 @@ import android.util.ArraySet;
import android.util.LongSparseArray;
import android.util.Slog;
import android.util.TimeUtils;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
import android.util.Xml;
import com.android.internal.annotations.GuardedBy;
@@ -1184,19 +1186,18 @@ final class HistoricalRegistry {
}
List<HistoricalOps> allOps = null;
try (FileInputStream stream = new FileInputStream(file)) {
- final XmlPullParser parser = Xml.newPullParser();
- parser.setInput(stream, StandardCharsets.UTF_8.name());
+ final TypedXmlPullParser parser = Xml.resolvePullParser(stream);
XmlUtils.beginDocument(parser, TAG_HISTORY);
// We haven't released version 1 and have more detailed
// accounting - just nuke the current state
- final int version = XmlUtils.readIntAttribute(parser, ATTR_VERSION);
+ final int version = parser.getAttributeInt(null, ATTR_VERSION);
if (CURRENT_VERSION == 2 && version < CURRENT_VERSION) {
throw new IllegalStateException("Dropping unsupported history "
+ "version 1 for file:" + file);
}
- final long overflowMillis = XmlUtils.readLongAttribute(parser, ATTR_OVERFLOW, 0);
+ final long overflowMillis = parser.getAttributeLong(null, ATTR_OVERFLOW, 0);
final int depth = parser.getDepth();
while (XmlUtils.nextElementWithin(parser, depth)) {
if (TAG_OPS.equals(parser.getName())) {
@@ -1235,15 +1236,16 @@ final class HistoricalRegistry {
}
private @Nullable HistoricalOps readeHistoricalOpsDLocked(
- @NonNull XmlPullParser parser, int filterUid, @Nullable String filterPackageName,
+ @NonNull TypedXmlPullParser parser, int filterUid,
+ @Nullable String filterPackageName,
@Nullable String filterAttributionTag, @Nullable String[] filterOpNames,
@HistoricalOpsRequestFilter int filter, long filterBeginTimeMillis,
long filterEndTimeMillis, @OpFlags int filterFlags,
@Nullable long[] cumulativeOverflowMillis)
throws IOException, XmlPullParserException {
- final long beginTimeMillis = XmlUtils.readLongAttribute(parser, ATTR_BEGIN_TIME, 0)
+ final long beginTimeMillis = parser.getAttributeLong(null, ATTR_BEGIN_TIME, 0)
+ (cumulativeOverflowMillis != null ? cumulativeOverflowMillis[0] : 0);
- final long endTimeMillis = XmlUtils.readLongAttribute(parser, ATTR_END_TIME, 0)
+ final long endTimeMillis = parser.getAttributeLong(null, ATTR_END_TIME, 0)
+ (cumulativeOverflowMillis != null ? cumulativeOverflowMillis[0] : 0);
// Keep reading as subsequent records may start matching
if (filterEndTimeMillis < beginTimeMillis) {
@@ -1280,12 +1282,12 @@ final class HistoricalRegistry {
}
private @Nullable HistoricalOps readHistoricalUidOpsDLocked(
- @Nullable HistoricalOps ops, @NonNull XmlPullParser parser, int filterUid,
+ @Nullable HistoricalOps ops, @NonNull TypedXmlPullParser parser, int filterUid,
@Nullable String filterPackageName, @Nullable String filterAttributionTag,
@Nullable String[] filterOpNames, @HistoricalOpsRequestFilter int filter,
@OpFlags int filterFlags, double filterScale)
throws IOException, XmlPullParserException {
- final int uid = XmlUtils.readIntAttribute(parser, ATTR_NAME);
+ final int uid = parser.getAttributeInt(null, ATTR_NAME);
if ((filter & FILTER_BY_UID) != 0 && filterUid != uid) {
XmlUtils.skipCurrentTag(parser);
return null;
@@ -1305,7 +1307,7 @@ final class HistoricalRegistry {
}
private @Nullable HistoricalOps readHistoricalPackageOpsDLocked(
- @Nullable HistoricalOps ops, int uid, @NonNull XmlPullParser parser,
+ @Nullable HistoricalOps ops, int uid, @NonNull TypedXmlPullParser parser,
@Nullable String filterPackageName, @Nullable String filterAttributionTag,
@Nullable String[] filterOpNames, @HistoricalOpsRequestFilter int filter,
@OpFlags int filterFlags, double filterScale)
@@ -1331,7 +1333,7 @@ final class HistoricalRegistry {
private @Nullable HistoricalOps readHistoricalAttributionOpsDLocked(
@Nullable HistoricalOps ops, int uid, String packageName,
- @NonNull XmlPullParser parser, @Nullable String filterAttributionTag,
+ @NonNull TypedXmlPullParser parser, @Nullable String filterAttributionTag,
@Nullable String[] filterOpNames, @HistoricalOpsRequestFilter int filter,
@OpFlags int filterFlags, double filterScale)
throws IOException, XmlPullParserException {
@@ -1357,11 +1359,11 @@ final class HistoricalRegistry {
private @Nullable HistoricalOps readHistoricalOpDLocked(@Nullable HistoricalOps ops,
int uid, @NonNull String packageName, @Nullable String attributionTag,
- @NonNull XmlPullParser parser, @Nullable String[] filterOpNames,
+ @NonNull TypedXmlPullParser parser, @Nullable String[] filterOpNames,
@HistoricalOpsRequestFilter int filter, @OpFlags int filterFlags,
double filterScale)
throws IOException, XmlPullParserException {
- final int op = XmlUtils.readIntAttribute(parser, ATTR_NAME);
+ final int op = parser.getAttributeInt(null, ATTR_NAME);
if ((filter & FILTER_BY_OP_NAMES) != 0 && !ArrayUtils.contains(filterOpNames,
AppOpsManager.opToPublicName(op))) {
XmlUtils.skipCurrentTag(parser);
@@ -1382,15 +1384,15 @@ final class HistoricalRegistry {
private @Nullable HistoricalOps readStateDLocked(@Nullable HistoricalOps ops,
int uid, @NonNull String packageName, @Nullable String attributionTag, int op,
- @NonNull XmlPullParser parser, @OpFlags int filterFlags, double filterScale)
- throws IOException {
- final long key = XmlUtils.readLongAttribute(parser, ATTR_NAME);
+ @NonNull TypedXmlPullParser parser, @OpFlags int filterFlags, double filterScale)
+ throws IOException, XmlPullParserException {
+ final long key = parser.getAttributeLong(null, ATTR_NAME);
final int flags = AppOpsManager.extractFlagsFromKey(key) & filterFlags;
if (flags == 0) {
return null;
}
final int uidState = AppOpsManager.extractUidStateFromKey(key);
- long accessCount = XmlUtils.readLongAttribute(parser, ATTR_ACCESS_COUNT, 0);
+ long accessCount = parser.getAttributeLong(null, ATTR_ACCESS_COUNT, 0);
if (accessCount > 0) {
if (!Double.isNaN(filterScale)) {
accessCount = (long) HistoricalOps.round(
@@ -1402,7 +1404,7 @@ final class HistoricalRegistry {
ops.increaseAccessCount(op, uid, packageName, attributionTag, uidState, flags,
accessCount);
}
- long rejectCount = XmlUtils.readLongAttribute(parser, ATTR_REJECT_COUNT, 0);
+ long rejectCount = parser.getAttributeLong(null, ATTR_REJECT_COUNT, 0);
if (rejectCount > 0) {
if (!Double.isNaN(filterScale)) {
rejectCount = (long) HistoricalOps.round(
@@ -1414,7 +1416,7 @@ final class HistoricalRegistry {
ops.increaseRejectCount(op, uid, packageName, attributionTag, uidState, flags,
rejectCount);
}
- long accessDuration = XmlUtils.readLongAttribute(parser, ATTR_ACCESS_DURATION, 0);
+ long accessDuration = parser.getAttributeLong(null, ATTR_ACCESS_DURATION, 0);
if (accessDuration > 0) {
if (!Double.isNaN(filterScale)) {
accessDuration = (long) HistoricalOps.round(
@@ -1433,16 +1435,14 @@ final class HistoricalRegistry {
long intervalOverflowMillis, @NonNull File file) throws IOException {
final FileOutputStream output = sHistoricalAppOpsDir.openWrite(file);
try {
- final XmlSerializer serializer = Xml.newSerializer();
- serializer.setOutput(output, StandardCharsets.UTF_8.name());
+ final TypedXmlSerializer serializer = Xml.resolveSerializer(output);
serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output",
true);
serializer.startDocument(null, true);
serializer.startTag(null, TAG_HISTORY);
- serializer.attribute(null, ATTR_VERSION, String.valueOf(CURRENT_VERSION));
+ serializer.attributeInt(null, ATTR_VERSION, CURRENT_VERSION);
if (intervalOverflowMillis != 0) {
- serializer.attribute(null, ATTR_OVERFLOW,
- Long.toString(intervalOverflowMillis));
+ serializer.attributeLong(null, ATTR_OVERFLOW, intervalOverflowMillis);
}
if (allOps != null) {
final int opsCount = allOps.size();
@@ -1461,10 +1461,10 @@ final class HistoricalRegistry {
}
private void writeHistoricalOpDLocked(@NonNull HistoricalOps ops,
- @NonNull XmlSerializer serializer) throws IOException {
+ @NonNull TypedXmlSerializer serializer) throws IOException {
serializer.startTag(null, TAG_OPS);
- serializer.attribute(null, ATTR_BEGIN_TIME, Long.toString(ops.getBeginTimeMillis()));
- serializer.attribute(null, ATTR_END_TIME, Long.toString(ops.getEndTimeMillis()));
+ serializer.attributeLong(null, ATTR_BEGIN_TIME, ops.getBeginTimeMillis());
+ serializer.attributeLong(null, ATTR_END_TIME, ops.getEndTimeMillis());
final int uidCount = ops.getUidCount();
for (int i = 0; i < uidCount; i++) {
final HistoricalUidOps uidOp = ops.getUidOpsAt(i);
@@ -1474,9 +1474,9 @@ final class HistoricalRegistry {
}
private void writeHistoricalUidOpsDLocked(@NonNull HistoricalUidOps uidOps,
- @NonNull XmlSerializer serializer) throws IOException {
+ @NonNull TypedXmlSerializer serializer) throws IOException {
serializer.startTag(null, TAG_UID);
- serializer.attribute(null, ATTR_NAME, Integer.toString(uidOps.getUid()));
+ serializer.attributeInt(null, ATTR_NAME, uidOps.getUid());
final int packageCount = uidOps.getPackageCount();
for (int i = 0; i < packageCount; i++) {
final HistoricalPackageOps packageOps = uidOps.getPackageOpsAt(i);
@@ -1486,7 +1486,7 @@ final class HistoricalRegistry {
}
private void writeHistoricalPackageOpsDLocked(@NonNull HistoricalPackageOps packageOps,
- @NonNull XmlSerializer serializer) throws IOException {
+ @NonNull TypedXmlSerializer serializer) throws IOException {
serializer.startTag(null, TAG_PACKAGE);
serializer.attribute(null, ATTR_NAME, packageOps.getPackageName());
final int numAttributions = packageOps.getAttributedOpsCount();
@@ -1499,7 +1499,7 @@ final class HistoricalRegistry {
private void writeHistoricalAttributionOpsDLocked(
@NonNull AppOpsManager.AttributedHistoricalOps attributionOps,
- @NonNull XmlSerializer serializer) throws IOException {
+ @NonNull TypedXmlSerializer serializer) throws IOException {
serializer.startTag(null, TAG_ATTRIBUTION);
XmlUtils.writeStringAttribute(serializer, ATTR_NAME, attributionOps.getTag());
final int opCount = attributionOps.getOpCount();
@@ -1511,13 +1511,13 @@ final class HistoricalRegistry {
}
private void writeHistoricalOpDLocked(@NonNull HistoricalOp op,
- @NonNull XmlSerializer serializer) throws IOException {
+ @NonNull TypedXmlSerializer serializer) throws IOException {
final LongSparseArray keys = op.collectKeys();
if (keys == null || keys.size() <= 0) {
return;
}
serializer.startTag(null, TAG_OP);
- serializer.attribute(null, ATTR_NAME, Integer.toString(op.getOpCode()));
+ serializer.attributeInt(null, ATTR_NAME, op.getOpCode());
final int keyCount = keys.size();
for (int i = 0; i < keyCount; i++) {
writeStateOnLocked(op, keys.keyAt(i), serializer);
@@ -1526,7 +1526,7 @@ final class HistoricalRegistry {
}
private void writeStateOnLocked(@NonNull HistoricalOp op, long key,
- @NonNull XmlSerializer serializer) throws IOException {
+ @NonNull TypedXmlSerializer serializer) throws IOException {
final int uidState = AppOpsManager.extractUidStateFromKey(key);
final int flags = AppOpsManager.extractFlagsFromKey(key);
@@ -1539,15 +1539,15 @@ final class HistoricalRegistry {
}
serializer.startTag(null, TAG_STATE);
- serializer.attribute(null, ATTR_NAME, Long.toString(key));
+ serializer.attributeLong(null, ATTR_NAME, key);
if (accessCount > 0) {
- serializer.attribute(null, ATTR_ACCESS_COUNT, Long.toString(accessCount));
+ serializer.attributeLong(null, ATTR_ACCESS_COUNT, accessCount);
}
if (rejectCount > 0) {
- serializer.attribute(null, ATTR_REJECT_COUNT, Long.toString(rejectCount));
+ serializer.attributeLong(null, ATTR_REJECT_COUNT, rejectCount);
}
if (accessDuration > 0) {
- serializer.attribute(null, ATTR_ACCESS_DURATION, Long.toString(accessDuration));
+ serializer.attributeLong(null, ATTR_ACCESS_DURATION, accessDuration);
}
serializer.endTag(null, TAG_STATE);
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
index ff410fcd2f66..0943c9ca17fe 100644
--- a/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
@@ -49,7 +49,7 @@ public abstract class AuthenticationClient<T> extends AcquisitionClient<T>
private final boolean mIsStrongBiometric;
private final boolean mRequireConfirmation;
- private final IActivityTaskManager mActivityTaskManager;
+ private final ActivityTaskManager mActivityTaskManager;
@Nullable private final TaskStackListener mTaskStackListener;
private final LockoutTracker mLockoutTracker;
private final boolean mIsRestricted;
@@ -71,7 +71,7 @@ public abstract class AuthenticationClient<T> extends AcquisitionClient<T>
mIsStrongBiometric = isStrongBiometric;
mOperationId = operationId;
mRequireConfirmation = requireConfirmation;
- mActivityTaskManager = ActivityTaskManager.getService();
+ mActivityTaskManager = ActivityTaskManager.getInstance();
mTaskStackListener = taskStackListener;
mLockoutTracker = lockoutTracker;
mIsRestricted = restricted;
@@ -146,29 +146,24 @@ public abstract class AuthenticationClient<T> extends AcquisitionClient<T>
// Ensure authentication only succeeds if the client activity is on top or is keyguard.
boolean isBackgroundAuth = false;
if (authenticated && !Utils.isKeyguard(getContext(), getOwnerString())) {
- try {
- final List<ActivityManager.RunningTaskInfo> tasks =
- mActivityTaskManager.getTasks(1);
- if (tasks == null || tasks.isEmpty()) {
- Slog.e(TAG, "No running tasks reported");
+ final List<ActivityManager.RunningTaskInfo> tasks =
+ mActivityTaskManager.getTasks(1);
+ if (tasks == null || tasks.isEmpty()) {
+ Slog.e(TAG, "No running tasks reported");
+ isBackgroundAuth = true;
+ } else {
+ final ComponentName topActivity = tasks.get(0).topActivity;
+ if (topActivity == null) {
+ Slog.e(TAG, "Unable to get top activity");
isBackgroundAuth = true;
} else {
- final ComponentName topActivity = tasks.get(0).topActivity;
- if (topActivity == null) {
- Slog.e(TAG, "Unable to get top activity");
+ final String topPackage = topActivity.getPackageName();
+ if (!topPackage.contentEquals(getOwnerString())) {
+ Slog.e(TAG, "Background authentication detected, top: " + topPackage
+ + ", client: " + this);
isBackgroundAuth = true;
- } else {
- final String topPackage = topActivity.getPackageName();
- if (!topPackage.contentEquals(getOwnerString())) {
- Slog.e(TAG, "Background authentication detected, top: " + topPackage
- + ", client: " + this);
- isBackgroundAuth = true;
- }
}
}
- } catch (RemoteException e) {
- Slog.e(TAG, "Unable to get running tasks", e);
- isBackgroundAuth = true;
}
}
@@ -198,11 +193,7 @@ public abstract class AuthenticationClient<T> extends AcquisitionClient<T>
}
if (mTaskStackListener != null) {
- try {
- mActivityTaskManager.unregisterTaskStackListener(mTaskStackListener);
- } catch (RemoteException e) {
- Slog.e(TAG, "Could not unregister task stack listener", e);
- }
+ mActivityTaskManager.unregisterTaskStackListener(mTaskStackListener);
}
final byte[] byteToken = new byte[hardwareAuthToken.size()];
@@ -290,11 +281,7 @@ public abstract class AuthenticationClient<T> extends AcquisitionClient<T>
}
if (mTaskStackListener != null) {
- try {
- mActivityTaskManager.registerTaskStackListener(mTaskStackListener);
- } catch (RemoteException e) {
- Slog.e(TAG, "Could not register task stack listener", e);
- }
+ mActivityTaskManager.registerTaskStackListener(mTaskStackListener);
}
if (DEBUG) Slog.w(TAG, "Requesting auth for " + getOwnerString());
@@ -309,11 +296,7 @@ public abstract class AuthenticationClient<T> extends AcquisitionClient<T>
super.cancel();
if (mTaskStackListener != null) {
- try {
- mActivityTaskManager.unregisterTaskStackListener(mTaskStackListener);
- } catch (RemoteException e) {
- Slog.e(TAG, "Could not unregister task stack listener", e);
- }
+ mActivityTaskManager.unregisterTaskStackListener(mTaskStackListener);
}
}
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/BiometricUserState.java b/services/core/java/com/android/server/biometrics/sensors/BiometricUserState.java
index a8250ac9e72d..d588b8d4aa13 100644
--- a/services/core/java/com/android/server/biometrics/sensors/BiometricUserState.java
+++ b/services/core/java/com/android/server/biometrics/sensors/BiometricUserState.java
@@ -22,6 +22,7 @@ import android.hardware.biometrics.BiometricAuthenticator;
import android.os.AsyncTask;
import android.os.Environment;
import android.util.Slog;
+import android.util.TypedXmlPullParser;
import android.util.Xml;
import com.android.internal.annotations.GuardedBy;
@@ -80,7 +81,7 @@ public abstract class BiometricUserState<T extends BiometricAuthenticator.Identi
/**
* @return
*/
- protected abstract void parseBiometricsLocked(XmlPullParser parser)
+ protected abstract void parseBiometricsLocked(TypedXmlPullParser parser)
throws IOException, XmlPullParserException;
@@ -176,8 +177,7 @@ public abstract class BiometricUserState<T extends BiometricAuthenticator.Identi
return;
}
try {
- XmlPullParser parser = Xml.newPullParser();
- parser.setInput(in, null);
+ TypedXmlPullParser parser = Xml.resolvePullParser(in);
parseStateLocked(parser);
} catch (XmlPullParserException | IOException e) {
@@ -189,7 +189,7 @@ public abstract class BiometricUserState<T extends BiometricAuthenticator.Identi
}
@GuardedBy("this")
- private void parseStateLocked(XmlPullParser parser)
+ private void parseStateLocked(TypedXmlPullParser parser)
throws IOException, XmlPullParserException {
final int outerDepth = parser.getDepth();
int type;
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceUserState.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceUserState.java
index d30c3c804362..78e875b864f4 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/FaceUserState.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceUserState.java
@@ -20,6 +20,8 @@ import android.content.Context;
import android.hardware.face.Face;
import android.util.AtomicFile;
import android.util.Slog;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
import android.util.Xml;
import com.android.internal.annotations.GuardedBy;
@@ -29,7 +31,6 @@ import libcore.io.IoUtils;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
import java.io.FileOutputStream;
import java.io.IOException;
@@ -87,8 +88,7 @@ public class FaceUserState extends BiometricUserState<Face> {
try {
out = destination.startWrite();
- XmlSerializer serializer = Xml.newSerializer();
- serializer.setOutput(out, "utf-8");
+ TypedXmlSerializer serializer = Xml.resolveSerializer(out);
serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
serializer.startDocument(null, true);
serializer.startTag(null, TAG_FACES);
@@ -97,9 +97,9 @@ public class FaceUserState extends BiometricUserState<Face> {
for (int i = 0; i < count; i++) {
Face f = faces.get(i);
serializer.startTag(null, TAG_FACE);
- serializer.attribute(null, ATTR_FACE_ID, Integer.toString(f.getBiometricId()));
+ serializer.attributeInt(null, ATTR_FACE_ID, f.getBiometricId());
serializer.attribute(null, ATTR_NAME, f.getName().toString());
- serializer.attribute(null, ATTR_DEVICE_ID, Long.toString(f.getDeviceId()));
+ serializer.attributeLong(null, ATTR_DEVICE_ID, f.getDeviceId());
serializer.endTag(null, TAG_FACE);
}
@@ -119,7 +119,7 @@ public class FaceUserState extends BiometricUserState<Face> {
@GuardedBy("this")
@Override
- protected void parseBiometricsLocked(XmlPullParser parser)
+ protected void parseBiometricsLocked(TypedXmlPullParser parser)
throws IOException, XmlPullParserException {
final int outerDepth = parser.getDepth();
int type;
@@ -132,9 +132,9 @@ public class FaceUserState extends BiometricUserState<Face> {
String tagName = parser.getName();
if (tagName.equals(TAG_FACE)) {
String name = parser.getAttributeValue(null, ATTR_NAME);
- String faceId = parser.getAttributeValue(null, ATTR_FACE_ID);
- String deviceId = parser.getAttributeValue(null, ATTR_DEVICE_ID);
- mBiometrics.add(new Face(name, Integer.parseInt(faceId), Integer.parseInt(deviceId)));
+ int faceId = parser.getAttributeInt(null, ATTR_FACE_ID);
+ int deviceId = parser.getAttributeInt(null, ATTR_DEVICE_ID);
+ mBiometrics.add(new Face(name, faceId, deviceId));
}
}
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java
index cc9298603a3e..cec1cb8654fc 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java
@@ -77,7 +77,7 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
@NonNull private final Handler mHandler;
@NonNull private final LockoutResetDispatcher mLockoutResetDispatcher;
@NonNull private final UsageStats mUsageStats;
- @NonNull private final IActivityTaskManager mActivityTaskManager;
+ @NonNull private final ActivityTaskManager mActivityTaskManager;
@NonNull private final BiometricTaskStackListener mTaskStackListener;
@Nullable private IFace mDaemon;
@@ -97,22 +97,18 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
continue; // Keyguard is always allowed
}
- try {
- final List<ActivityManager.RunningTaskInfo> runningTasks =
- mActivityTaskManager.getTasks(1);
- if (!runningTasks.isEmpty()) {
- final String topPackage =
- runningTasks.get(0).topActivity.getPackageName();
- if (!topPackage.contentEquals(client.getOwnerString())
- && !client.isAlreadyDone()) {
- Slog.e(getTag(), "Stopping background authentication, top: "
- + topPackage + " currentClient: " + client);
- mSensors.valueAt(i).getScheduler()
- .cancelAuthentication(client.getToken());
- }
+ final List<ActivityManager.RunningTaskInfo> runningTasks =
+ mActivityTaskManager.getTasks(1);
+ if (!runningTasks.isEmpty()) {
+ final String topPackage =
+ runningTasks.get(0).topActivity.getPackageName();
+ if (!topPackage.contentEquals(client.getOwnerString())
+ && !client.isAlreadyDone()) {
+ Slog.e(getTag(), "Stopping background authentication, top: "
+ + topPackage + " currentClient: " + client);
+ mSensors.valueAt(i).getScheduler()
+ .cancelAuthentication(client.getToken());
}
- } catch (RemoteException e) {
- Slog.e(getTag(), "Unable to get running tasks", e);
}
}
});
@@ -129,7 +125,7 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
mHandler = new Handler(Looper.getMainLooper());
mUsageStats = new UsageStats(context);
mLockoutResetDispatcher = lockoutResetDispatcher;
- mActivityTaskManager = ActivityTaskManager.getService();
+ mActivityTaskManager = ActivityTaskManager.getInstance();
mTaskStackListener = new BiometricTaskStackListener();
for (SensorProps prop : props) {
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintUserState.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintUserState.java
index e56c8d5b5ceb..671e08bd8c56 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintUserState.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintUserState.java
@@ -20,6 +20,8 @@ import android.content.Context;
import android.hardware.fingerprint.Fingerprint;
import android.util.AtomicFile;
import android.util.Slog;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
import android.util.Xml;
import com.android.internal.annotations.GuardedBy;
@@ -29,7 +31,6 @@ import libcore.io.IoUtils;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
import java.io.FileOutputStream;
import java.io.IOException;
@@ -88,8 +89,7 @@ public class FingerprintUserState extends BiometricUserState<Fingerprint> {
try {
out = destination.startWrite();
- XmlSerializer serializer = Xml.newSerializer();
- serializer.setOutput(out, "utf-8");
+ TypedXmlSerializer serializer = Xml.resolveSerializer(out);
serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
serializer.startDocument(null, true);
serializer.startTag(null, TAG_FINGERPRINTS);
@@ -98,10 +98,10 @@ public class FingerprintUserState extends BiometricUserState<Fingerprint> {
for (int i = 0; i < count; i++) {
Fingerprint fp = fingerprints.get(i);
serializer.startTag(null, TAG_FINGERPRINT);
- serializer.attribute(null, ATTR_FINGER_ID, Integer.toString(fp.getBiometricId()));
+ serializer.attributeInt(null, ATTR_FINGER_ID, fp.getBiometricId());
serializer.attribute(null, ATTR_NAME, fp.getName().toString());
- serializer.attribute(null, ATTR_GROUP_ID, Integer.toString(fp.getGroupId()));
- serializer.attribute(null, ATTR_DEVICE_ID, Long.toString(fp.getDeviceId()));
+ serializer.attributeInt(null, ATTR_GROUP_ID, fp.getGroupId());
+ serializer.attributeLong(null, ATTR_DEVICE_ID, fp.getDeviceId());
serializer.endTag(null, TAG_FINGERPRINT);
}
@@ -121,7 +121,7 @@ public class FingerprintUserState extends BiometricUserState<Fingerprint> {
@GuardedBy("this")
@Override
- protected void parseBiometricsLocked(XmlPullParser parser)
+ protected void parseBiometricsLocked(TypedXmlPullParser parser)
throws IOException, XmlPullParserException {
final int outerDepth = parser.getDepth();
@@ -135,11 +135,10 @@ public class FingerprintUserState extends BiometricUserState<Fingerprint> {
String tagName = parser.getName();
if (tagName.equals(TAG_FINGERPRINT)) {
String name = parser.getAttributeValue(null, ATTR_NAME);
- String groupId = parser.getAttributeValue(null, ATTR_GROUP_ID);
- String fingerId = parser.getAttributeValue(null, ATTR_FINGER_ID);
- String deviceId = parser.getAttributeValue(null, ATTR_DEVICE_ID);
- mBiometrics.add(new Fingerprint(name, Integer.parseInt(groupId),
- Integer.parseInt(fingerId), Long.parseLong(deviceId)));
+ int groupId = parser.getAttributeInt(null, ATTR_GROUP_ID);
+ int fingerId = parser.getAttributeInt(null, ATTR_FINGER_ID);
+ long deviceId = parser.getAttributeLong(null, ATTR_DEVICE_ID);
+ mBiometrics.add(new Fingerprint(name, groupId, fingerId, deviceId));
}
}
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
index 98c32cbcfc4a..99c662a57c3b 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
@@ -77,7 +77,7 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
@NonNull private final ClientMonitor.LazyDaemon<IFingerprint> mLazyDaemon;
@NonNull private final Handler mHandler;
@NonNull private final LockoutResetDispatcher mLockoutResetDispatcher;
- @NonNull private final IActivityTaskManager mActivityTaskManager;
+ @NonNull private final ActivityTaskManager mActivityTaskManager;
@NonNull private final BiometricTaskStackListener mTaskStackListener;
@Nullable private IFingerprint mDaemon;
@@ -98,22 +98,18 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
continue; // Keyguard is always allowed
}
- try {
- final List<ActivityManager.RunningTaskInfo> runningTasks =
- mActivityTaskManager.getTasks(1);
- if (!runningTasks.isEmpty()) {
- final String topPackage =
- runningTasks.get(0).topActivity.getPackageName();
- if (!topPackage.contentEquals(client.getOwnerString())
- && !client.isAlreadyDone()) {
- Slog.e(getTag(), "Stopping background authentication, top: "
- + topPackage + " currentClient: " + client);
- mSensors.valueAt(i).getScheduler()
- .cancelAuthentication(client.getToken());
- }
+ final List<ActivityManager.RunningTaskInfo> runningTasks =
+ mActivityTaskManager.getTasks(1);
+ if (!runningTasks.isEmpty()) {
+ final String topPackage =
+ runningTasks.get(0).topActivity.getPackageName();
+ if (!topPackage.contentEquals(client.getOwnerString())
+ && !client.isAlreadyDone()) {
+ Slog.e(getTag(), "Stopping background authentication, top: "
+ + topPackage + " currentClient: " + client);
+ mSensors.valueAt(i).getScheduler()
+ .cancelAuthentication(client.getToken());
}
- } catch (RemoteException e) {
- Slog.e(getTag(), "Unable to get running tasks", e);
}
}
});
@@ -129,7 +125,7 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
mLazyDaemon = this::getHalInstance;
mHandler = new Handler(Looper.getMainLooper());
mLockoutResetDispatcher = lockoutResetDispatcher;
- mActivityTaskManager = ActivityTaskManager.getService();
+ mActivityTaskManager = ActivityTaskManager.getInstance();
mTaskStackListener = new BiometricTaskStackListener();
for (SensorProps prop : props) {
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
index f38dd092007a..7c5b7c92c1c6 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
@@ -97,7 +97,7 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
private boolean mTestHalEnabled;
final Context mContext;
- private final IActivityTaskManager mActivityTaskManager;
+ private final ActivityTaskManager mActivityTaskManager;
@NonNull private final FingerprintSensorPropertiesInternal mSensorProperties;
private final BiometricScheduler mScheduler;
private final Handler mHandler;
@@ -125,20 +125,16 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
return; // Keyguard is always allowed
}
- try {
- final List<ActivityManager.RunningTaskInfo> runningTasks =
- mActivityTaskManager.getTasks(1);
- if (!runningTasks.isEmpty()) {
- final String topPackage = runningTasks.get(0).topActivity.getPackageName();
- if (!topPackage.contentEquals(client.getOwnerString())
- && !client.isAlreadyDone()) {
- Slog.e(TAG, "Stopping background authentication, top: "
- + topPackage + " currentClient: " + client);
- mScheduler.cancelAuthentication(client.getToken());
- }
+ final List<ActivityManager.RunningTaskInfo> runningTasks =
+ mActivityTaskManager.getTasks(1);
+ if (!runningTasks.isEmpty()) {
+ final String topPackage = runningTasks.get(0).topActivity.getPackageName();
+ if (!topPackage.contentEquals(client.getOwnerString())
+ && !client.isAlreadyDone()) {
+ Slog.e(TAG, "Stopping background authentication, top: "
+ + topPackage + " currentClient: " + client);
+ mScheduler.cancelAuthentication(client.getToken());
}
- } catch (RemoteException e) {
- Slog.e(TAG, "Unable to get running tasks", e);
}
});
}
@@ -313,7 +309,7 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
mContext = context;
mScheduler = scheduler;
mHandler = handler;
- mActivityTaskManager = ActivityTaskManager.getService();
+ mActivityTaskManager = ActivityTaskManager.getInstance();
mTaskStackListener = new BiometricTaskStackListener();
mAuthenticatorIds = Collections.synchronizedMap(new HashMap<>());
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index eec286a99a8f..3445275b76dd 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -18,10 +18,7 @@ package com.android.server.connectivity;
import static android.Manifest.permission.BIND_VPN_SERVICE;
import static android.net.ConnectivityManager.NETID_UNSET;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED;
import static android.net.RouteInfo.RTN_THROW;
import static android.net.RouteInfo.RTN_UNREACHABLE;
@@ -111,7 +108,6 @@ import com.android.internal.net.LegacyVpnInfo;
import com.android.internal.net.VpnConfig;
import com.android.internal.net.VpnInfo;
import com.android.internal.net.VpnProfile;
-import com.android.internal.util.ArrayUtils;
import com.android.server.DeviceIdleInternal;
import com.android.server.LocalServices;
import com.android.server.net.BaseNetworkObserver;
@@ -122,7 +118,6 @@ import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
-import java.math.BigInteger;
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
@@ -152,36 +147,13 @@ import java.util.concurrent.atomic.AtomicInteger;
public class Vpn {
private static final String NETWORKTYPE = "VPN";
private static final String TAG = "Vpn";
+ private static final String VPN_PROVIDER_NAME_BASE = "VpnNetworkProvider:";
private static final boolean LOGD = true;
// Length of time (in milliseconds) that an app hosting an always-on VPN is placed on
// the device idle allowlist during service launch and VPN bootstrap.
private static final long VPN_LAUNCH_IDLE_ALLOWLIST_DURATION_MS = 60 * 1000;
- // Settings for how much of the address space should be routed so that Vpn considers
- // "most" of the address space is routed. This is used to determine whether this Vpn
- // should be marked with the INTERNET capability.
- private static final long MOST_IPV4_ADDRESSES_COUNT;
- private static final BigInteger MOST_IPV6_ADDRESSES_COUNT;
- static {
- // 85% of the address space must be routed for Vpn to consider this VPN to provide
- // INTERNET access.
- final int howManyPercentIsMost = 85;
-
- final long twoPower32 = 1L << 32;
- MOST_IPV4_ADDRESSES_COUNT = twoPower32 * howManyPercentIsMost / 100;
- final BigInteger twoPower128 = BigInteger.ONE.shiftLeft(128);
- MOST_IPV6_ADDRESSES_COUNT = twoPower128
- .multiply(BigInteger.valueOf(howManyPercentIsMost))
- .divide(BigInteger.valueOf(100));
- }
- // How many routes to evaluate before bailing and declaring this Vpn should provide
- // the INTERNET capability. This is necessary because computing the address space is
- // O(n²) and this is running in the system service, so a limit is needed to alleviate
- // the risk of attack.
- // This is taken as a total of IPv4 + IPV6 routes for simplicity, but the algorithm
- // is actually O(n²)+O(n²).
- private static final int MAX_ROUTES_TO_EVALUATE = 150;
private static final String LOCKDOWN_ALLOWLIST_SETTING_NAME =
Settings.Secure.ALWAYS_ON_VPN_LOCKDOWN_WHITELIST;
/**
@@ -198,6 +170,7 @@ public class Vpn {
// automated reconnection
private final Context mContext;
+ private final ConnectivityManager mConnectivityManager;
// The context is for specific user which is created from mUserId
private final Context mUserIdContext;
@VisibleForTesting final Dependencies mDeps;
@@ -218,6 +191,7 @@ public class Vpn {
private final INetworkManagementService mNetd;
@VisibleForTesting
protected VpnConfig mConfig;
+ private final NetworkProvider mNetworkProvider;
@VisibleForTesting
protected NetworkAgent mNetworkAgent;
private final Looper mLooper;
@@ -401,6 +375,7 @@ public class Vpn {
int userId, @NonNull KeyStore keyStore, SystemServices systemServices,
Ikev2SessionCreator ikev2SessionCreator) {
mContext = context;
+ mConnectivityManager = mContext.getSystemService(ConnectivityManager.class);
mUserIdContext = context.createContextAsUser(UserHandle.of(userId), 0 /* flags */);
mDeps = deps;
mNetd = netService;
@@ -419,13 +394,16 @@ public class Vpn {
Log.wtf(TAG, "Problem registering observer", e);
}
+ mNetworkProvider = new NetworkProvider(context, looper, VPN_PROVIDER_NAME_BASE + mUserId);
+ // This constructor is called in onUserStart and registers the provider. The provider
+ // will be unregistered in onUserStop.
+ mConnectivityManager.registerNetworkProvider(mNetworkProvider);
mLegacyState = LegacyVpnInfo.STATE_DISCONNECTED;
mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_VPN, 0 /* subtype */, NETWORKTYPE,
"" /* subtypeName */);
mNetworkCapabilities = new NetworkCapabilities();
mNetworkCapabilities.addTransportType(NetworkCapabilities.TRANSPORT_VPN);
mNetworkCapabilities.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN);
- updateCapabilities(null /* defaultNetwork */);
loadAlwaysOnPackage(keyStore);
}
@@ -443,110 +421,44 @@ public class Vpn {
* Update current state, dispatching event to listeners.
*/
@VisibleForTesting
+ @GuardedBy("this")
protected void updateState(DetailedState detailedState, String reason) {
if (LOGD) Log.d(TAG, "setting state=" + detailedState + ", reason=" + reason);
mLegacyState = LegacyVpnInfo.stateFromNetworkInfo(detailedState);
mNetworkInfo.setDetailedState(detailedState, reason, null);
- if (mNetworkAgent != null) {
- mNetworkAgent.sendNetworkInfo(mNetworkInfo);
+ // TODO : only accept transitions when the agent is in the correct state (non-null for
+ // CONNECTED, DISCONNECTED and FAILED, null for CONNECTED).
+ // This will require a way for tests to pretend the VPN is connected that's not
+ // calling this method with CONNECTED.
+ // It will also require audit of where the code calls this method with DISCONNECTED
+ // with a null agent, which it was doing historically to make sure the agent is
+ // disconnected as this was a no-op if the agent was null.
+ switch (detailedState) {
+ case CONNECTED:
+ if (null != mNetworkAgent) {
+ mNetworkAgent.markConnected();
+ }
+ break;
+ case DISCONNECTED:
+ case FAILED:
+ if (null != mNetworkAgent) {
+ mNetworkAgent.unregister();
+ mNetworkAgent = null;
+ }
+ break;
+ case CONNECTING:
+ if (null != mNetworkAgent) {
+ throw new IllegalStateException("VPN can only go to CONNECTING state when"
+ + " the agent is null.");
+ }
+ break;
+ default:
+ throw new IllegalArgumentException("Illegal state argument " + detailedState);
}
updateAlwaysOnNotification(detailedState);
}
/**
- * Updates {@link #mNetworkCapabilities} based on current underlying networks and returns a
- * defensive copy.
- *
- * <p>Does not propagate updated capabilities to apps.
- *
- * @param defaultNetwork underlying network for VPNs following platform's default
- */
- public synchronized NetworkCapabilities updateCapabilities(@Nullable Network defaultNetwork) {
- if (mConfig == null) {
- // VPN is not running.
- return null;
- }
-
- Network[] underlyingNetworks = mConfig.underlyingNetworks;
- if (underlyingNetworks == null && defaultNetwork != null) {
- // null underlying networks means to track the default.
- underlyingNetworks = new Network[] { defaultNetwork };
- }
- // Only apps targeting Q and above can explicitly declare themselves as metered.
- final boolean isAlwaysMetered = mIsPackageTargetingAtLeastQ && mConfig.isMetered;
-
- applyUnderlyingCapabilities(
- mContext.getSystemService(ConnectivityManager.class),
- underlyingNetworks,
- mNetworkCapabilities,
- isAlwaysMetered);
-
- return new NetworkCapabilities(mNetworkCapabilities);
- }
-
- @VisibleForTesting
- public static void applyUnderlyingCapabilities(
- ConnectivityManager cm,
- Network[] underlyingNetworks,
- NetworkCapabilities caps,
- boolean isAlwaysMetered) {
- int[] transportTypes = new int[] { NetworkCapabilities.TRANSPORT_VPN };
- int downKbps = NetworkCapabilities.LINK_BANDWIDTH_UNSPECIFIED;
- int upKbps = NetworkCapabilities.LINK_BANDWIDTH_UNSPECIFIED;
- boolean metered = isAlwaysMetered; // metered if any underlying is metered, or alwaysMetered
- boolean roaming = false; // roaming if any underlying is roaming
- boolean congested = false; // congested if any underlying is congested
- boolean suspended = true; // suspended if all underlying are suspended
-
- boolean hadUnderlyingNetworks = false;
- if (null != underlyingNetworks) {
- for (Network underlying : underlyingNetworks) {
- // TODO(b/124469351): Get capabilities directly from ConnectivityService instead.
- final NetworkCapabilities underlyingCaps = cm.getNetworkCapabilities(underlying);
- if (underlyingCaps == null) continue;
- hadUnderlyingNetworks = true;
- for (int underlyingType : underlyingCaps.getTransportTypes()) {
- transportTypes = ArrayUtils.appendInt(transportTypes, underlyingType);
- }
-
- // Merge capabilities of this underlying network. For bandwidth, assume the
- // worst case.
- downKbps = NetworkCapabilities.minBandwidth(downKbps,
- underlyingCaps.getLinkDownstreamBandwidthKbps());
- upKbps = NetworkCapabilities.minBandwidth(upKbps,
- underlyingCaps.getLinkUpstreamBandwidthKbps());
- // If this underlying network is metered, the VPN is metered (it may cost money
- // to send packets on this network).
- metered |= !underlyingCaps.hasCapability(NET_CAPABILITY_NOT_METERED);
- // If this underlying network is roaming, the VPN is roaming (the billing structure
- // is different than the usual, local one).
- roaming |= !underlyingCaps.hasCapability(NET_CAPABILITY_NOT_ROAMING);
- // If this underlying network is congested, the VPN is congested (the current
- // condition of the network affects the performance of this network).
- congested |= !underlyingCaps.hasCapability(NET_CAPABILITY_NOT_CONGESTED);
- // If this network is not suspended, the VPN is not suspended (the VPN
- // is able to transfer some data).
- suspended &= !underlyingCaps.hasCapability(NET_CAPABILITY_NOT_SUSPENDED);
- }
- }
- if (!hadUnderlyingNetworks) {
- // No idea what the underlying networks are; assume the safer defaults
- metered = true;
- roaming = false;
- congested = false;
- suspended = false;
- }
-
- caps.setTransportTypes(transportTypes);
- caps.setLinkDownstreamBandwidthKbps(downKbps);
- caps.setLinkUpstreamBandwidthKbps(upKbps);
- caps.setCapability(NET_CAPABILITY_NOT_METERED, !metered);
- caps.setCapability(NET_CAPABILITY_NOT_ROAMING, !roaming);
- caps.setCapability(NET_CAPABILITY_NOT_CONGESTED, !congested);
- caps.setCapability(NET_CAPABILITY_NOT_SUSPENDED, !suspended);
- }
-
- /**
* Chooses whether to force all connections to go though VPN.
*
* Used to enable/disable legacy VPN lockdown.
@@ -1016,7 +928,7 @@ public class Vpn {
}
mConfig = null;
- updateState(DetailedState.IDLE, "prepare");
+ updateState(DetailedState.DISCONNECTED, "prepare");
setVpnForcedLocked(mLockdown);
} finally {
Binder.restoreCallingIdentity(token);
@@ -1252,7 +1164,7 @@ public class Vpn {
mNetworkCapabilities.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
mLegacyState = LegacyVpnInfo.STATE_CONNECTING;
- mNetworkInfo.setDetailedState(DetailedState.CONNECTING, null, null);
+ updateState(DetailedState.CONNECTING, "agentConnect");
NetworkAgentConfig networkAgentConfig = new NetworkAgentConfig();
networkAgentConfig.allowBypass = mConfig.allowBypass && !mLockdown;
@@ -1270,20 +1182,23 @@ public class Vpn {
mNetworkCapabilities.addCapability(NET_CAPABILITY_NOT_METERED);
}
- final long token = Binder.clearCallingIdentity();
- try {
- mNetworkAgent = new NetworkAgent(mLooper, mContext, NETWORKTYPE /* logtag */,
- mNetworkInfo, mNetworkCapabilities, lp,
- ConnectivityConstants.VPN_DEFAULT_SCORE, networkAgentConfig,
- NetworkProvider.ID_VPN) {
- @Override
- public void unwanted() {
- // We are user controlled, not driven by NetworkRequest.
- }
- };
- } finally {
- Binder.restoreCallingIdentity(token);
- }
+ mNetworkAgent = new NetworkAgent(mContext, mLooper, NETWORKTYPE /* logtag */,
+ mNetworkCapabilities, lp,
+ ConnectivityConstants.VPN_DEFAULT_SCORE, networkAgentConfig, mNetworkProvider) {
+ @Override
+ public void unwanted() {
+ // We are user controlled, not driven by NetworkRequest.
+ }
+ };
+ Binder.withCleanCallingIdentity(() -> {
+ try {
+ mNetworkAgent.register();
+ } catch (final Exception e) {
+ // If register() throws, don't keep an unregistered agent.
+ mNetworkAgent = null;
+ throw e;
+ }
+ });
mNetworkAgent.setUnderlyingNetworks((mConfig.underlyingNetworks != null)
? Arrays.asList(mConfig.underlyingNetworks) : null);
mNetworkInfo.setIsAvailable(true);
@@ -1301,19 +1216,12 @@ public class Vpn {
private void agentDisconnect(NetworkAgent networkAgent) {
if (networkAgent != null) {
- NetworkInfo networkInfo = new NetworkInfo(mNetworkInfo);
- networkInfo.setIsAvailable(false);
- networkInfo.setDetailedState(DetailedState.DISCONNECTED, null, null);
- networkAgent.sendNetworkInfo(networkInfo);
+ networkAgent.unregister();
}
}
private void agentDisconnect() {
- if (mNetworkInfo.isConnected()) {
- mNetworkInfo.setIsAvailable(false);
- updateState(DetailedState.DISCONNECTED, "agentDisconnect");
- mNetworkAgent = null;
- }
+ updateState(DetailedState.DISCONNECTED, "agentDisconnect");
}
/**
@@ -1402,6 +1310,8 @@ public class Vpn {
&& updateLinkPropertiesInPlaceIfPossible(mNetworkAgent, oldConfig)) {
// Keep mNetworkAgent unchanged
} else {
+ // Initialize the state for a new agent, while keeping the old one connected
+ // in case this new connection fails.
mNetworkAgent = null;
updateState(DetailedState.CONNECTING, "establish");
// Set up forwarding and DNS rules.
@@ -1585,12 +1495,13 @@ public class Vpn {
try {
addUserToRanges(existingRanges, userId, mConfig.allowedApplications,
mConfig.disallowedApplications);
- // ConnectivityService will call {@link #updateCapabilities} and apply
- // those for VPN network.
mNetworkCapabilities.setUids(existingRanges);
} catch (Exception e) {
Log.wtf(TAG, "Failed to add restricted user to owner", e);
}
+ if (mNetworkAgent != null) {
+ mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
+ }
}
setVpnForcedLocked(mLockdown);
}
@@ -1613,12 +1524,13 @@ public class Vpn {
final List<UidRange> removedRanges =
uidRangesForUser(userId, existingRanges);
existingRanges.removeAll(removedRanges);
- // ConnectivityService will call {@link #updateCapabilities} and
- // apply those for VPN network.
mNetworkCapabilities.setUids(existingRanges);
} catch (Exception e) {
Log.wtf(TAG, "Failed to remove restricted user to owner", e);
}
+ if (mNetworkAgent != null) {
+ mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
+ }
}
setVpnForcedLocked(mLockdown);
}
@@ -1635,6 +1547,9 @@ public class Vpn {
// Quit any active connections
agentDisconnect();
+
+ // The provider has been registered in the constructor, which is called in onUserStart.
+ mConnectivityManager.unregisterNetworkProvider(mNetworkProvider);
}
/**
@@ -2411,7 +2326,6 @@ public class Vpn {
// When restricted to test networks, select any network with TRANSPORT_TEST. Since the
// creator of the profile and the test network creator both have MANAGE_TEST_NETWORKS,
// this is considered safe.
- final ConnectivityManager cm = ConnectivityManager.from(mContext);
final NetworkRequest req;
if (mProfile.isRestrictedToTestNetworks()) {
@@ -2430,7 +2344,7 @@ public class Vpn {
.build();
}
- cm.requestNetwork(req, mNetworkCallback);
+ mConnectivityManager.requestNetwork(req, mNetworkCallback);
}
private boolean isActiveNetwork(@Nullable Network network) {
@@ -2717,8 +2631,7 @@ public class Vpn {
resetIkeState();
- final ConnectivityManager cm = ConnectivityManager.from(mContext);
- cm.unregisterNetworkCallback(mNetworkCallback);
+ mConnectivityManager.unregisterNetworkCallback(mNetworkCallback);
mExecutor.shutdown();
}
@@ -2799,13 +2712,12 @@ public class Vpn {
mProfile = profile;
if (!TextUtils.isEmpty(mOuterInterface)) {
- final ConnectivityManager cm = ConnectivityManager.from(mContext);
- for (Network network : cm.getAllNetworks()) {
- final LinkProperties lp = cm.getLinkProperties(network);
+ for (Network network : mConnectivityManager.getAllNetworks()) {
+ final LinkProperties lp = mConnectivityManager.getLinkProperties(network);
if (lp != null && lp.getAllInterfaceNames().contains(mOuterInterface)) {
- final NetworkInfo networkInfo = cm.getNetworkInfo(network);
- if (networkInfo != null) {
- mOuterConnection.set(networkInfo.getType());
+ final NetworkInfo netInfo = mConnectivityManager.getNetworkInfo(network);
+ if (netInfo != null) {
+ mOuterConnection.set(netInfo.getType());
break;
}
}
diff --git a/services/core/java/com/android/server/content/SyncStorageEngine.java b/services/core/java/com/android/server/content/SyncStorageEngine.java
index 9a1f1e522f97..d27cb16ecc51 100644
--- a/services/core/java/com/android/server/content/SyncStorageEngine.java
+++ b/services/core/java/com/android/server/content/SyncStorageEngine.java
@@ -58,12 +58,10 @@ import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
-import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.IntPair;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
import java.io.File;
import java.io.FileInputStream;
@@ -71,7 +69,6 @@ import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
-import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
@@ -1650,37 +1647,23 @@ public class SyncStorageEngine {
String tagName = parser.getName();
if ("accounts".equals(tagName)) {
- String listen = parser.getAttributeValue(null, XML_ATTR_LISTEN_FOR_TICKLES);
- String versionString = parser.getAttributeValue(null, "version");
- int version;
- try {
- version = (versionString == null) ? 0 : Integer.parseInt(versionString);
- } catch (NumberFormatException e) {
- version = 0;
- }
+ boolean listen = parser.getAttributeBoolean(
+ null, XML_ATTR_LISTEN_FOR_TICKLES, true);
+ int version = parser.getAttributeInt(null, "version", 0);
if (version < 3) {
mGrantSyncAdaptersAccountAccess = true;
}
- String nextIdString = parser.getAttributeValue(null, XML_ATTR_NEXT_AUTHORITY_ID);
- try {
- int id = (nextIdString == null) ? 0 : Integer.parseInt(nextIdString);
- mNextAuthorityId = Math.max(mNextAuthorityId, id);
- } catch (NumberFormatException e) {
- // don't care
- }
- String offsetString = parser.getAttributeValue(null, XML_ATTR_SYNC_RANDOM_OFFSET);
- try {
- mSyncRandomOffset = (offsetString == null) ? 0 : Integer.parseInt(offsetString);
- } catch (NumberFormatException e) {
- mSyncRandomOffset = 0;
- }
+ int nextId = parser.getAttributeInt(null, XML_ATTR_NEXT_AUTHORITY_ID, 0);
+ mNextAuthorityId = Math.max(mNextAuthorityId, nextId);
+
+ mSyncRandomOffset = parser.getAttributeInt(null, XML_ATTR_SYNC_RANDOM_OFFSET, 0);
if (mSyncRandomOffset == 0) {
Random random = new Random(System.currentTimeMillis());
mSyncRandomOffset = random.nextInt(86400);
}
- mMasterSyncAutomatically.put(0, listen == null || Boolean.parseBoolean(listen));
+ mMasterSyncAutomatically.put(0, listen);
eventType = parser.next();
AuthorityInfo authority = null;
PeriodicSync periodicSync = null;
@@ -1804,27 +1787,23 @@ public class SyncStorageEngine {
return writeNeeded;
}
- private void parseListenForTickles(XmlPullParser parser) {
- String user = parser.getAttributeValue(null, XML_ATTR_USER);
+ private void parseListenForTickles(TypedXmlPullParser parser) {
int userId = 0;
try {
- userId = Integer.parseInt(user);
- } catch (NumberFormatException e) {
+ parser.getAttributeInt(null, XML_ATTR_USER);
+ } catch (XmlPullParserException e) {
Slog.e(TAG, "error parsing the user for listen-for-tickles", e);
- } catch (NullPointerException e) {
- Slog.e(TAG, "the user in listen-for-tickles is null", e);
}
- String enabled = parser.getAttributeValue(null, XML_ATTR_ENABLED);
- boolean listen = enabled == null || Boolean.parseBoolean(enabled);
+ boolean listen = parser.getAttributeBoolean(null, XML_ATTR_ENABLED, true);
mMasterSyncAutomatically.put(userId, listen);
}
- private AuthorityInfo parseAuthority(XmlPullParser parser, int version,
- AccountAuthorityValidator validator) {
+ private AuthorityInfo parseAuthority(TypedXmlPullParser parser, int version,
+ AccountAuthorityValidator validator) throws XmlPullParserException {
AuthorityInfo authority = null;
int id = -1;
try {
- id = Integer.parseInt(parser.getAttributeValue(null, "id"));
+ id = parser.getAttributeInt(null, "id");
} catch (NumberFormatException e) {
Slog.e(TAG, "error parsing the id of the authority", e);
} catch (NullPointerException e) {
@@ -1832,14 +1811,13 @@ public class SyncStorageEngine {
}
if (id >= 0) {
String authorityName = parser.getAttributeValue(null, "authority");
- String enabled = parser.getAttributeValue(null, XML_ATTR_ENABLED);
+ boolean enabled = parser.getAttributeBoolean(null, XML_ATTR_ENABLED, true);
String syncable = parser.getAttributeValue(null, "syncable");
String accountName = parser.getAttributeValue(null, "account");
String accountType = parser.getAttributeValue(null, "type");
- String user = parser.getAttributeValue(null, XML_ATTR_USER);
+ int userId = parser.getAttributeInt(null, XML_ATTR_USER, 0);
String packageName = parser.getAttributeValue(null, "package");
String className = parser.getAttributeValue(null, "class");
- int userId = user == null ? 0 : Integer.parseInt(user);
if (accountType == null && packageName == null) {
accountType = "com.google";
syncable = String.valueOf(AuthorityInfo.NOT_INITIALIZED);
@@ -1884,7 +1862,7 @@ public class SyncStorageEngine {
}
}
if (authority != null) {
- authority.enabled = enabled == null || Boolean.parseBoolean(enabled);
+ authority.enabled = enabled;
try {
authority.syncable = (syncable == null) ?
AuthorityInfo.NOT_INITIALIZED : Integer.parseInt(syncable);
@@ -1912,32 +1890,22 @@ public class SyncStorageEngine {
/**
* Parse a periodic sync from accounts.xml. Sets the bundle to be empty.
*/
- private PeriodicSync parsePeriodicSync(XmlPullParser parser, AuthorityInfo authorityInfo) {
+ private PeriodicSync parsePeriodicSync(TypedXmlPullParser parser, AuthorityInfo authorityInfo) {
Bundle extras = new Bundle(); // Gets filled in later.
- String periodValue = parser.getAttributeValue(null, "period");
- String flexValue = parser.getAttributeValue(null, "flex");
- final long period;
+ long period;
long flextime;
try {
- period = Long.parseLong(periodValue);
- } catch (NumberFormatException e) {
+ period = parser.getAttributeLong(null, "period");
+ } catch (XmlPullParserException e) {
Slog.e(TAG, "error parsing the period of a periodic sync", e);
return null;
- } catch (NullPointerException e) {
- Slog.e(TAG, "the period of a periodic sync is null", e);
- return null;
}
try {
- flextime = Long.parseLong(flexValue);
- } catch (NumberFormatException e) {
- flextime = calculateDefaultFlexTime(period);
- Slog.e(TAG, "Error formatting value parsed for periodic sync flex: " + flexValue
- + ", using default: "
- + flextime);
- } catch (NullPointerException expected) {
+ flextime = parser.getAttributeLong(null, "flex");
+ } catch (XmlPullParserException e) {
flextime = calculateDefaultFlexTime(period);
- Slog.d(TAG, "No flex time specified for this sync, using a default. period: "
- + period + " flex: " + flextime);
+ Slog.e(TAG, "Error formatting value parsed for periodic sync flex, using default: "
+ + flextime, e);
}
PeriodicSync periodicSync;
periodicSync =
@@ -1949,7 +1917,7 @@ public class SyncStorageEngine {
return periodicSync;
}
- private void parseExtra(XmlPullParser parser, Bundle extras) {
+ private void parseExtra(TypedXmlPullParser parser, Bundle extras) {
String name = parser.getAttributeValue(null, "name");
String type = parser.getAttributeValue(null, "type");
String value1 = parser.getAttributeValue(null, "value1");
@@ -1994,9 +1962,9 @@ public class SyncStorageEngine {
out.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
out.startTag(null, "accounts");
- out.attribute(null, "version", Integer.toString(ACCOUNTS_VERSION));
- out.attribute(null, XML_ATTR_NEXT_AUTHORITY_ID, Integer.toString(mNextAuthorityId));
- out.attribute(null, XML_ATTR_SYNC_RANDOM_OFFSET, Integer.toString(mSyncRandomOffset));
+ out.attributeInt(null, "version", ACCOUNTS_VERSION);
+ out.attributeInt(null, XML_ATTR_NEXT_AUTHORITY_ID, mNextAuthorityId);
+ out.attributeInt(null, XML_ATTR_SYNC_RANDOM_OFFSET, mSyncRandomOffset);
// Write the Sync Automatically flags for each user
final int M = mMasterSyncAutomatically.size();
@@ -2004,8 +1972,8 @@ public class SyncStorageEngine {
int userId = mMasterSyncAutomatically.keyAt(m);
Boolean listen = mMasterSyncAutomatically.valueAt(m);
out.startTag(null, XML_TAG_LISTEN_FOR_TICKLES);
- out.attribute(null, XML_ATTR_USER, Integer.toString(userId));
- out.attribute(null, XML_ATTR_ENABLED, Boolean.toString(listen));
+ out.attributeInt(null, XML_ATTR_USER, userId);
+ out.attributeBoolean(null, XML_ATTR_ENABLED, listen);
out.endTag(null, XML_TAG_LISTEN_FOR_TICKLES);
}
@@ -2014,13 +1982,13 @@ public class SyncStorageEngine {
AuthorityInfo authority = mAuthorities.valueAt(i);
EndPoint info = authority.target;
out.startTag(null, "authority");
- out.attribute(null, "id", Integer.toString(authority.ident));
- out.attribute(null, XML_ATTR_USER, Integer.toString(info.userId));
- out.attribute(null, XML_ATTR_ENABLED, Boolean.toString(authority.enabled));
+ out.attributeInt(null, "id", authority.ident);
+ out.attributeInt(null, XML_ATTR_USER, info.userId);
+ out.attributeBoolean(null, XML_ATTR_ENABLED, authority.enabled);
out.attribute(null, "account", info.account.name);
out.attribute(null, "type", info.account.type);
out.attribute(null, "authority", info.provider);
- out.attribute(null, "syncable", Integer.toString(authority.syncable));
+ out.attributeInt(null, "syncable", authority.syncable);
out.endTag(null, "authority");
}
out.endTag(null, "accounts");
diff --git a/services/core/java/com/android/server/display/AmbientBrightnessStatsTracker.java b/services/core/java/com/android/server/display/AmbientBrightnessStatsTracker.java
index 928799b31df8..0f1e6668ceec 100644
--- a/services/core/java/com/android/server/display/AmbientBrightnessStatsTracker.java
+++ b/services/core/java/com/android/server/display/AmbientBrightnessStatsTracker.java
@@ -27,17 +27,14 @@ import android.util.TypedXmlSerializer;
import android.util.Xml;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.FastXmlSerializer;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
-import java.nio.charset.StandardCharsets;
import java.time.LocalDate;
import java.time.format.DateTimeParseException;
import java.util.ArrayDeque;
@@ -179,7 +176,7 @@ public class AmbientBrightnessStatsTracker {
entry.getKey());
if (userSerialNumber != -1 && userDayStats.getLocalDate().isAfter(cutOffDate)) {
out.startTag(null, TAG_AMBIENT_BRIGHTNESS_DAY_STATS);
- out.attribute(null, ATTR_USER, Integer.toString(userSerialNumber));
+ out.attributeInt(null, ATTR_USER, userSerialNumber);
out.attribute(null, ATTR_LOCAL_DATE,
userDayStats.getLocalDate().toString());
StringBuilder bucketBoundariesValues = new StringBuilder();
@@ -229,7 +226,7 @@ public class AmbientBrightnessStatsTracker {
}
tag = parser.getName();
if (TAG_AMBIENT_BRIGHTNESS_DAY_STATS.equals(tag)) {
- String userSerialNumber = parser.getAttributeValue(null, ATTR_USER);
+ int userSerialNumber = parser.getAttributeInt(null, ATTR_USER);
LocalDate localDate = LocalDate.parse(
parser.getAttributeValue(null, ATTR_LOCAL_DATE));
String[] bucketBoundaries = parser.getAttributeValue(null,
@@ -246,8 +243,7 @@ public class AmbientBrightnessStatsTracker {
parsedBucketBoundaries[i] = Float.parseFloat(bucketBoundaries[i]);
parsedBucketStats[i] = Float.parseFloat(bucketStats[i]);
}
- int userId = mInjector.getUserId(mUserManager,
- Integer.parseInt(userSerialNumber));
+ int userId = mInjector.getUserId(mUserManager, userSerialNumber);
if (userId != -1 && localDate.isAfter(cutOffDate)) {
Deque<AmbientBrightnessDayStats> userStats = getOrCreateUserStats(
parsedStats, userId);
diff --git a/services/core/java/com/android/server/display/BrightnessTracker.java b/services/core/java/com/android/server/display/BrightnessTracker.java
index 3ae99ef3ed5e..2a0e21919704 100644
--- a/services/core/java/com/android/server/display/BrightnessTracker.java
+++ b/services/core/java/com/android/server/display/BrightnessTracker.java
@@ -555,22 +555,22 @@ public class BrightnessTracker {
if (userSerialNo != -1 && toWrite[i].timeStamp > timeCutOff) {
mEvents.append(toWrite[i]);
out.startTag(null, TAG_EVENT);
- out.attribute(null, ATTR_NITS, Float.toString(toWrite[i].brightness));
- out.attribute(null, ATTR_TIMESTAMP, Long.toString(toWrite[i].timeStamp));
+ out.attributeFloat(null, ATTR_NITS, toWrite[i].brightness);
+ out.attributeLong(null, ATTR_TIMESTAMP, toWrite[i].timeStamp);
out.attribute(null, ATTR_PACKAGE_NAME, toWrite[i].packageName);
- out.attribute(null, ATTR_USER, Integer.toString(userSerialNo));
- out.attribute(null, ATTR_BATTERY_LEVEL, Float.toString(toWrite[i].batteryLevel));
- out.attribute(null, ATTR_NIGHT_MODE, Boolean.toString(toWrite[i].nightMode));
- out.attribute(null, ATTR_COLOR_TEMPERATURE, Integer.toString(
- toWrite[i].colorTemperature));
- out.attribute(null, ATTR_LAST_NITS,
- Float.toString(toWrite[i].lastBrightness));
- out.attribute(null, ATTR_DEFAULT_CONFIG,
- Boolean.toString(toWrite[i].isDefaultBrightnessConfig));
- out.attribute(null, ATTR_POWER_SAVE,
- Float.toString(toWrite[i].powerBrightnessFactor));
- out.attribute(null, ATTR_USER_POINT,
- Boolean.toString(toWrite[i].isUserSetBrightness));
+ out.attributeInt(null, ATTR_USER, userSerialNo);
+ out.attributeFloat(null, ATTR_BATTERY_LEVEL, toWrite[i].batteryLevel);
+ out.attributeBoolean(null, ATTR_NIGHT_MODE, toWrite[i].nightMode);
+ out.attributeInt(null, ATTR_COLOR_TEMPERATURE,
+ toWrite[i].colorTemperature);
+ out.attributeFloat(null, ATTR_LAST_NITS,
+ toWrite[i].lastBrightness);
+ out.attributeBoolean(null, ATTR_DEFAULT_CONFIG,
+ toWrite[i].isDefaultBrightnessConfig);
+ out.attributeFloat(null, ATTR_POWER_SAVE,
+ toWrite[i].powerBrightnessFactor);
+ out.attributeBoolean(null, ATTR_USER_POINT,
+ toWrite[i].isUserSetBrightness);
StringBuilder luxValues = new StringBuilder();
StringBuilder luxTimestamps = new StringBuilder();
for (int j = 0; j < toWrite[i].luxValues.length; ++j) {
@@ -585,8 +585,8 @@ public class BrightnessTracker {
out.attribute(null, ATTR_LUX_TIMESTAMPS, luxTimestamps.toString());
if (toWrite[i].colorValueBuckets != null
&& toWrite[i].colorValueBuckets.length > 0) {
- out.attribute(null, ATTR_COLOR_SAMPLE_DURATION,
- Long.toString(toWrite[i].colorSampleDuration));
+ out.attributeLong(null, ATTR_COLOR_SAMPLE_DURATION,
+ toWrite[i].colorSampleDuration);
StringBuilder buckets = new StringBuilder();
for (int j = 0; j < toWrite[i].colorValueBuckets.length; ++j) {
if (j > 0) {
@@ -633,22 +633,16 @@ public class BrightnessTracker {
if (TAG_EVENT.equals(tag)) {
BrightnessChangeEvent.Builder builder = new BrightnessChangeEvent.Builder();
- String brightness = parser.getAttributeValue(null, ATTR_NITS);
- builder.setBrightness(Float.parseFloat(brightness));
- String timestamp = parser.getAttributeValue(null, ATTR_TIMESTAMP);
- builder.setTimeStamp(Long.parseLong(timestamp));
+ builder.setBrightness(parser.getAttributeFloat(null, ATTR_NITS));
+ builder.setTimeStamp(parser.getAttributeLong(null, ATTR_TIMESTAMP));
builder.setPackageName(parser.getAttributeValue(null, ATTR_PACKAGE_NAME));
- String user = parser.getAttributeValue(null, ATTR_USER);
- builder.setUserId(mInjector.getUserId(mUserManager, Integer.parseInt(user)));
- String batteryLevel = parser.getAttributeValue(null, ATTR_BATTERY_LEVEL);
- builder.setBatteryLevel(Float.parseFloat(batteryLevel));
- String nightMode = parser.getAttributeValue(null, ATTR_NIGHT_MODE);
- builder.setNightMode(Boolean.parseBoolean(nightMode));
- String colorTemperature =
- parser.getAttributeValue(null, ATTR_COLOR_TEMPERATURE);
- builder.setColorTemperature(Integer.parseInt(colorTemperature));
- String lastBrightness = parser.getAttributeValue(null, ATTR_LAST_NITS);
- builder.setLastBrightness(Float.parseFloat(lastBrightness));
+ builder.setUserId(mInjector.getUserId(mUserManager,
+ parser.getAttributeInt(null, ATTR_USER)));
+ builder.setBatteryLevel(parser.getAttributeFloat(null, ATTR_BATTERY_LEVEL));
+ builder.setNightMode(parser.getAttributeBoolean(null, ATTR_NIGHT_MODE));
+ builder.setColorTemperature(
+ parser.getAttributeInt(null, ATTR_COLOR_TEMPERATURE));
+ builder.setLastBrightness(parser.getAttributeFloat(null, ATTR_LAST_NITS));
String luxValue = parser.getAttributeValue(null, ATTR_LUX);
String luxTimestamp = parser.getAttributeValue(null, ATTR_LUX_TIMESTAMPS);
@@ -667,20 +661,12 @@ public class BrightnessTracker {
builder.setLuxValues(luxValues);
builder.setLuxTimestamps(luxTimestamps);
- String defaultConfig = parser.getAttributeValue(null, ATTR_DEFAULT_CONFIG);
- if (defaultConfig != null) {
- builder.setIsDefaultBrightnessConfig(Boolean.parseBoolean(defaultConfig));
- }
- String powerSave = parser.getAttributeValue(null, ATTR_POWER_SAVE);
- if (powerSave != null) {
- builder.setPowerBrightnessFactor(Float.parseFloat(powerSave));
- } else {
- builder.setPowerBrightnessFactor(1.0f);
- }
- String userPoint = parser.getAttributeValue(null, ATTR_USER_POINT);
- if (userPoint != null) {
- builder.setUserBrightnessPoint(Boolean.parseBoolean(userPoint));
- }
+ builder.setIsDefaultBrightnessConfig(
+ parser.getAttributeBoolean(null, ATTR_DEFAULT_CONFIG, false));
+ builder.setPowerBrightnessFactor(
+ parser.getAttributeFloat(null, ATTR_POWER_SAVE, 1.0f));
+ builder.setUserBrightnessPoint(
+ parser.getAttributeBoolean(null, ATTR_USER_POINT, false));
String colorSampleDurationString =
parser.getAttributeValue(null, ATTR_COLOR_SAMPLE_DURATION);
diff --git a/services/core/java/com/android/server/display/DisplayModeDirector.java b/services/core/java/com/android/server/display/DisplayModeDirector.java
index 1aced07e0997..329081a8391f 100644
--- a/services/core/java/com/android/server/display/DisplayModeDirector.java
+++ b/services/core/java/com/android/server/display/DisplayModeDirector.java
@@ -38,6 +38,7 @@ import android.os.UserHandle;
import android.provider.DeviceConfig;
import android.provider.Settings;
import android.text.TextUtils;
+import android.util.IndentingPrintWriter;
import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
@@ -49,6 +50,7 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.BackgroundThread;
import com.android.server.display.utils.AmbientFilter;
import com.android.server.display.utils.AmbientFilterFactory;
+import com.android.server.utils.DeviceConfigInterface;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
@@ -68,9 +70,11 @@ public class DisplayModeDirector {
private static final boolean DEBUG = false;
private static final int MSG_REFRESH_RATE_RANGE_CHANGED = 1;
- private static final int MSG_BRIGHTNESS_THRESHOLDS_CHANGED = 2;
+ private static final int MSG_LOW_BRIGHTNESS_THRESHOLDS_CHANGED = 2;
private static final int MSG_DEFAULT_PEAK_REFRESH_RATE_CHANGED = 3;
- private static final int MSG_REFRESH_RATE_IN_ZONE_CHANGED = 4;
+ private static final int MSG_REFRESH_RATE_IN_LOW_ZONE_CHANGED = 4;
+ private static final int MSG_REFRESH_RATE_IN_HIGH_ZONE_CHANGED = 5;
+ private static final int MSG_HIGH_BRIGHTNESS_THRESHOLDS_CHANGED = 6;
// Special ID used to indicate that given vote is to be applied globally, rather than to a
// specific display.
@@ -83,6 +87,13 @@ public class DisplayModeDirector {
private final Context mContext;
private final DisplayModeDirectorHandler mHandler;
+ private final Injector mInjector;
+
+ private final AppRequestObserver mAppRequestObserver;
+ private final SettingsObserver mSettingsObserver;
+ private final DisplayObserver mDisplayObserver;
+ private final DeviceConfigInterface mDeviceConfig;
+ private final DeviceConfigDisplaySettings mDeviceConfigDisplaySettings;
// A map from the display ID to the collection of votes and their priority. The latter takes
// the form of another map from the priority to the vote itself so that each priority is
@@ -93,12 +104,8 @@ public class DisplayModeDirector {
// A map from the display ID to the default mode of that display.
private SparseArray<Display.Mode> mDefaultModeByDisplay;
- private final AppRequestObserver mAppRequestObserver;
- private final SettingsObserver mSettingsObserver;
- private final DisplayObserver mDisplayObserver;
private BrightnessObserver mBrightnessObserver;
- private final DeviceConfigDisplaySettings mDeviceConfigDisplaySettings;
private DesiredDisplayModeSpecsListener mDesiredDisplayModeSpecsListener;
private boolean mAlwaysRespectAppRequest;
@@ -127,8 +134,14 @@ public class DisplayModeDirector {
private int mModeSwitchingType = SWITCHING_TYPE_WITHIN_GROUPS;
public DisplayModeDirector(@NonNull Context context, @NonNull Handler handler) {
+ this(context, handler, new RealInjector());
+ }
+
+ public DisplayModeDirector(@NonNull Context context, @NonNull Handler handler,
+ @NonNull Injector injector) {
mContext = context;
mHandler = new DisplayModeDirectorHandler(handler.getLooper());
+ mInjector = injector;
mVotesByDisplay = new SparseArray<>();
mSupportedModesByDisplay = new SparseArray<>();
mDefaultModeByDisplay = new SparseArray<>();
@@ -137,6 +150,7 @@ public class DisplayModeDirector {
mDisplayObserver = new DisplayObserver(context, handler);
mBrightnessObserver = new BrightnessObserver(context, handler);
mDeviceConfigDisplaySettings = new DeviceConfigDisplaySettings();
+ mDeviceConfig = injector.getDeviceConfig();
mAlwaysRespectAppRequest = false;
}
@@ -455,6 +469,23 @@ public class DisplayModeDirector {
}
/**
+ * Retrieve the Vote for the given display and priority. Intended only for testing purposes.
+ *
+ * @param displayId the display to query for
+ * @param priority the priority of the vote to return
+ * @return the vote corresponding to the given {@code displayId} and {@code priority},
+ * or {@code null} if there isn't one
+ */
+ @VisibleForTesting
+ @Nullable
+ Vote getVote(int displayId, int priority) {
+ synchronized (mLock) {
+ SparseArray<Vote> votes = getVotesLocked(displayId);
+ return votes.get(priority);
+ }
+ }
+
+ /**
* Print the object's state and debug information into the given stream.
*
* @param pw The stream to dump information to.
@@ -586,6 +617,17 @@ public class DisplayModeDirector {
}
@VisibleForTesting
+ BrightnessObserver getBrightnessObserver() {
+ return mBrightnessObserver;
+ }
+
+ @VisibleForTesting
+ SettingsObserver getSettingsObserver() {
+ return mSettingsObserver;
+ }
+
+
+ @VisibleForTesting
DesiredDisplayModeSpecs getDesiredDisplayModeSpecsWithInjectedFpsSettings(
float minRefreshRate, float peakRefreshRate, float defaultRefreshRate) {
synchronized (mLock) {
@@ -613,16 +655,35 @@ public class DisplayModeDirector {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
- case MSG_BRIGHTNESS_THRESHOLDS_CHANGED:
+ case MSG_LOW_BRIGHTNESS_THRESHOLDS_CHANGED: {
+ Pair<int[], int[]> thresholds = (Pair<int[], int[]>) msg.obj;
+ mBrightnessObserver.onDeviceConfigLowBrightnessThresholdsChanged(
+ thresholds.first, thresholds.second);
+ break;
+ }
+
+ case MSG_REFRESH_RATE_IN_LOW_ZONE_CHANGED: {
+ int refreshRateInZone = msg.arg1;
+ mBrightnessObserver.onDeviceConfigRefreshRateInLowZoneChanged(
+ refreshRateInZone);
+ break;
+ }
+
+ case MSG_HIGH_BRIGHTNESS_THRESHOLDS_CHANGED: {
Pair<int[], int[]> thresholds = (Pair<int[], int[]>) msg.obj;
- if (thresholds != null) {
- mBrightnessObserver.onDeviceConfigThresholdsChanged(
- thresholds.first, thresholds.second);
- } else {
- mBrightnessObserver.onDeviceConfigThresholdsChanged(null, null);
- }
+ mBrightnessObserver.onDeviceConfigHighBrightnessThresholdsChanged(
+ thresholds.first, thresholds.second);
+
+ break;
+ }
+
+ case MSG_REFRESH_RATE_IN_HIGH_ZONE_CHANGED: {
+ int refreshRateInZone = msg.arg1;
+ mBrightnessObserver.onDeviceConfigRefreshRateInHighZoneChanged(
+ refreshRateInZone);
break;
+ }
case MSG_DEFAULT_PEAK_REFRESH_RATE_CHANGED:
Float defaultPeakRefreshRate = (Float) msg.obj;
@@ -630,12 +691,6 @@ public class DisplayModeDirector {
defaultPeakRefreshRate);
break;
- case MSG_REFRESH_RATE_IN_ZONE_CHANGED:
- int refreshRateInZone = msg.arg1;
- mBrightnessObserver.onDeviceConfigRefreshRateInZoneChanged(
- refreshRateInZone);
- break;
-
case MSG_REFRESH_RATE_RANGE_CHANGED:
DesiredDisplayModeSpecsListener desiredDisplayModeSpecsListener =
(DesiredDisplayModeSpecsListener) msg.obj;
@@ -822,10 +877,11 @@ public class DisplayModeDirector {
// by all other considerations. It acts to set a default frame rate for a device.
public static final int PRIORITY_DEFAULT_REFRESH_RATE = 0;
- // LOW_BRIGHTNESS votes for a single refresh rate like [60,60], [90,90] or null.
+ // FLICKER votes for a single refresh rate like [60,60], [90,90] or null.
// If the higher voters result is a range, it will fix the rate to a single choice.
- // It's used to avoid rate switch in certain conditions.
- public static final int PRIORITY_LOW_BRIGHTNESS = 1;
+ // It's used to avoid refresh rate switches in certain conditions which may result in the
+ // user seeing the display flickering when the switches occur.
+ public static final int PRIORITY_FLICKER = 1;
// SETTING_MIN_REFRESH_RATE is used to propose a lower bound of display refresh rate.
// It votes [MIN_REFRESH_RATE, Float.POSITIVE_INFINITY]
@@ -898,8 +954,8 @@ public class DisplayModeDirector {
switch (priority) {
case PRIORITY_DEFAULT_REFRESH_RATE:
return "PRIORITY_DEFAULT_REFRESH_RATE";
- case PRIORITY_LOW_BRIGHTNESS:
- return "PRIORITY_LOW_BRIGHTNESS";
+ case PRIORITY_FLICKER:
+ return "PRIORITY_FLICKER";
case PRIORITY_USER_SETTING_MIN_REFRESH_RATE:
return "PRIORITY_USER_SETTING_MIN_REFRESH_RATE";
case PRIORITY_APP_REQUEST_REFRESH_RATE:
@@ -924,7 +980,8 @@ public class DisplayModeDirector {
}
}
- private final class SettingsObserver extends ContentObserver {
+ @VisibleForTesting
+ final class SettingsObserver extends ContentObserver {
private final Uri mPeakRefreshRateSetting =
Settings.System.getUriFor(Settings.System.PEAK_REFRESH_RATE);
private final Uri mMinRefreshRateSetting =
@@ -949,8 +1006,7 @@ public class DisplayModeDirector {
public void observe() {
final ContentResolver cr = mContext.getContentResolver();
- cr.registerContentObserver(mPeakRefreshRateSetting, false /*notifyDescendants*/, this,
- UserHandle.USER_SYSTEM);
+ mInjector.registerPeakRefreshRateObserver(cr, this);
cr.registerContentObserver(mMinRefreshRateSetting, false /*notifyDescendants*/, this,
UserHandle.USER_SYSTEM);
cr.registerContentObserver(mLowPowerModeSetting, false /*notifyDescendants*/, this,
@@ -971,6 +1027,13 @@ public class DisplayModeDirector {
}
}
+ public void setDefaultRefreshRate(float refreshRate) {
+ synchronized (mLock) {
+ mDefaultRefreshRate = refreshRate;
+ updateRefreshRateSettingLocked();
+ }
+ }
+
public void onDeviceConfigDefaultPeakRefreshRateChanged(Float defaultPeakRefreshRate) {
if (defaultPeakRefreshRate == null) {
defaultPeakRefreshRate = (float) mContext.getResources().getInteger(
@@ -1189,6 +1252,7 @@ public class DisplayModeDirector {
@Override
public void onDisplayChanged(int displayId) {
updateDisplayModes(displayId);
+ // TODO: Break the coupling between DisplayObserver and BrightnessObserver.
mBrightnessObserver.onDisplayChanged(displayId);
}
@@ -1227,15 +1291,16 @@ public class DisplayModeDirector {
*/
@VisibleForTesting
public class BrightnessObserver extends ContentObserver {
- // TODO: brightnessfloat: change this to the float setting
- private final Uri mDisplayBrightnessSetting =
- Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS);
private final static int LIGHT_SENSOR_RATE_MS = 250;
- private int[] mDisplayBrightnessThresholds;
- private int[] mAmbientBrightnessThresholds;
+ private int[] mLowDisplayBrightnessThresholds;
+ private int[] mLowAmbientBrightnessThresholds;
+ private int[] mHighDisplayBrightnessThresholds;
+ private int[] mHighAmbientBrightnessThresholds;
// valid threshold if any item from the array >= 0
- private boolean mShouldObserveDisplayChange;
- private boolean mShouldObserveAmbientChange;
+ private boolean mShouldObserveDisplayLowChange;
+ private boolean mShouldObserveAmbientLowChange;
+ private boolean mShouldObserveDisplayHighChange;
+ private boolean mShouldObserveAmbientHighChange;
private SensorManager mSensorManager;
private Sensor mLightSensor;
@@ -1243,46 +1308,122 @@ public class DisplayModeDirector {
// Take it as low brightness before valid sensor data comes
private float mAmbientLux = -1.0f;
private AmbientFilter mAmbientFilter;
+ private int mBrightness = -1;
private final Context mContext;
- // Enable light sensor only when mShouldObserveAmbientChange is true, screen is on, peak
- // refresh rate changeable and low power mode off. After initialization, these states will
+ // Enable light sensor only when mShouldObserveAmbientLowChange is true or
+ // mShouldObserveAmbientHighChange is true, screen is on, peak refresh rate
+ // changeable and low power mode off. After initialization, these states will
// be updated from the same handler thread.
- private boolean mScreenOn = false;
+ private boolean mDefaultDisplayOn = false;
private boolean mRefreshRateChangeable = false;
private boolean mLowPowerModeEnabled = false;
- private int mRefreshRateInZone;
+ private int mRefreshRateInLowZone;
+ private int mRefreshRateInHighZone;
BrightnessObserver(Context context, Handler handler) {
super(handler);
mContext = context;
- mDisplayBrightnessThresholds = context.getResources().getIntArray(
+ mLowDisplayBrightnessThresholds = context.getResources().getIntArray(
R.array.config_brightnessThresholdsOfPeakRefreshRate);
- mAmbientBrightnessThresholds = context.getResources().getIntArray(
+ mLowAmbientBrightnessThresholds = context.getResources().getIntArray(
R.array.config_ambientThresholdsOfPeakRefreshRate);
- if (mDisplayBrightnessThresholds.length != mAmbientBrightnessThresholds.length) {
- throw new RuntimeException("display brightness threshold array and ambient "
- + "brightness threshold array have different length");
+ if (mLowDisplayBrightnessThresholds.length != mLowAmbientBrightnessThresholds.length) {
+ throw new RuntimeException("display low brightness threshold array and ambient "
+ + "brightness threshold array have different length: "
+ + "displayBrightnessThresholds="
+ + Arrays.toString(mLowDisplayBrightnessThresholds)
+ + ", ambientBrightnessThresholds="
+ + Arrays.toString(mLowAmbientBrightnessThresholds));
}
+
+ mHighDisplayBrightnessThresholds = context.getResources().getIntArray(
+ R.array.config_highDisplayBrightnessThresholdsOfFixedRefreshRate);
+ mHighAmbientBrightnessThresholds = context.getResources().getIntArray(
+ R.array.config_highAmbientBrightnessThresholdsOfFixedRefreshRate);
+ if (mHighDisplayBrightnessThresholds.length
+ != mHighAmbientBrightnessThresholds.length) {
+ throw new RuntimeException("display high brightness threshold array and ambient "
+ + "brightness threshold array have different length: "
+ + "displayBrightnessThresholds="
+ + Arrays.toString(mHighDisplayBrightnessThresholds)
+ + ", ambientBrightnessThresholds="
+ + Arrays.toString(mHighAmbientBrightnessThresholds));
+ }
+ mRefreshRateInHighZone = context.getResources().getInteger(
+ R.integer.config_fixedRefreshRateInHighZone);
+ }
+
+ /**
+ * @return the refresh to lock to when in a low brightness zone
+ */
+ @VisibleForTesting
+ int getRefreshRateInLowZone() {
+ return mRefreshRateInLowZone;
+ }
+
+ /**
+ * @return the display brightness thresholds for the low brightness zones
+ */
+ @VisibleForTesting
+ int[] getLowDisplayBrightnessThresholds() {
+ return mLowDisplayBrightnessThresholds;
+ }
+
+ /**
+ * @return the ambient brightness thresholds for the low brightness zones
+ */
+ @VisibleForTesting
+ int[] getLowAmbientBrightnessThresholds() {
+ return mLowAmbientBrightnessThresholds;
+ }
+
+ public void registerLightSensor(SensorManager sensorManager, Sensor lightSensor) {
+ mSensorManager = sensorManager;
+ mLightSensor = lightSensor;
+
+ mSensorManager.registerListener(mLightSensorListener,
+ mLightSensor, LIGHT_SENSOR_RATE_MS * 1000, mHandler);
}
public void observe(SensorManager sensorManager) {
mSensorManager = sensorManager;
+ final ContentResolver cr = mContext.getContentResolver();
+ mBrightness = Settings.System.getIntForUser(cr,
+ Settings.System.SCREEN_BRIGHTNESS, -1 /*default*/, cr.getUserId());
// DeviceConfig is accessible after system ready.
- int[] brightnessThresholds = mDeviceConfigDisplaySettings.getBrightnessThresholds();
- int[] ambientThresholds = mDeviceConfigDisplaySettings.getAmbientThresholds();
+ int[] lowDisplayBrightnessThresholds =
+ mDeviceConfigDisplaySettings.getLowDisplayBrightnessThresholds();
+ int[] lowAmbientBrightnessThresholds =
+ mDeviceConfigDisplaySettings.getLowAmbientBrightnessThresholds();
+
+ if (lowDisplayBrightnessThresholds != null && lowAmbientBrightnessThresholds != null
+ && lowDisplayBrightnessThresholds.length
+ == lowAmbientBrightnessThresholds.length) {
+ mLowDisplayBrightnessThresholds = lowDisplayBrightnessThresholds;
+ mLowAmbientBrightnessThresholds = lowAmbientBrightnessThresholds;
+ }
- if (brightnessThresholds != null && ambientThresholds != null
- && brightnessThresholds.length == ambientThresholds.length) {
- mDisplayBrightnessThresholds = brightnessThresholds;
- mAmbientBrightnessThresholds = ambientThresholds;
+
+ int[] highDisplayBrightnessThresholds =
+ mDeviceConfigDisplaySettings.getHighDisplayBrightnessThresholds();
+ int[] highAmbientBrightnessThresholds =
+ mDeviceConfigDisplaySettings.getHighAmbientBrightnessThresholds();
+
+ if (highDisplayBrightnessThresholds != null && highAmbientBrightnessThresholds != null
+ && highDisplayBrightnessThresholds.length
+ == highAmbientBrightnessThresholds.length) {
+ mHighDisplayBrightnessThresholds = highDisplayBrightnessThresholds;
+ mHighAmbientBrightnessThresholds = highAmbientBrightnessThresholds;
}
- mRefreshRateInZone = mDeviceConfigDisplaySettings.getRefreshRateInZone();
+ mRefreshRateInLowZone = mDeviceConfigDisplaySettings.getRefreshRateInLowZone();
+ mRefreshRateInHighZone = mDeviceConfigDisplaySettings.getRefreshRateInHighZone();
+
restartObserver();
mDeviceConfigDisplaySettings.startListening();
}
@@ -1294,7 +1435,7 @@ public class DisplayModeDirector {
updateSensorStatus();
if (!changeable) {
// Revoke previous vote from BrightnessObserver
- updateVoteLocked(Vote.PRIORITY_LOW_BRIGHTNESS, null);
+ updateVoteLocked(Vote.PRIORITY_FLICKER, null);
}
}
}
@@ -1306,25 +1447,48 @@ public class DisplayModeDirector {
}
}
- public void onDeviceConfigThresholdsChanged(int[] brightnessThresholds,
+ public void onDeviceConfigLowBrightnessThresholdsChanged(int[] displayThresholds,
int[] ambientThresholds) {
- if (brightnessThresholds != null && ambientThresholds != null
- && brightnessThresholds.length == ambientThresholds.length) {
- mDisplayBrightnessThresholds = brightnessThresholds;
- mAmbientBrightnessThresholds = ambientThresholds;
+ if (displayThresholds != null && ambientThresholds != null
+ && displayThresholds.length == ambientThresholds.length) {
+ mLowDisplayBrightnessThresholds = displayThresholds;
+ mLowAmbientBrightnessThresholds = ambientThresholds;
} else {
// Invalid or empty. Use device default.
- mDisplayBrightnessThresholds = mContext.getResources().getIntArray(
+ mLowDisplayBrightnessThresholds = mContext.getResources().getIntArray(
R.array.config_brightnessThresholdsOfPeakRefreshRate);
- mAmbientBrightnessThresholds = mContext.getResources().getIntArray(
+ mLowAmbientBrightnessThresholds = mContext.getResources().getIntArray(
R.array.config_ambientThresholdsOfPeakRefreshRate);
}
restartObserver();
}
- public void onDeviceConfigRefreshRateInZoneChanged(int refreshRate) {
- if (refreshRate != mRefreshRateInZone) {
- mRefreshRateInZone = refreshRate;
+ public void onDeviceConfigRefreshRateInLowZoneChanged(int refreshRate) {
+ if (refreshRate != mRefreshRateInLowZone) {
+ mRefreshRateInLowZone = refreshRate;
+ restartObserver();
+ }
+ }
+
+ public void onDeviceConfigHighBrightnessThresholdsChanged(int[] displayThresholds,
+ int[] ambientThresholds) {
+ if (displayThresholds != null && ambientThresholds != null
+ && displayThresholds.length == ambientThresholds.length) {
+ mHighDisplayBrightnessThresholds = displayThresholds;
+ mHighAmbientBrightnessThresholds = ambientThresholds;
+ } else {
+ // Invalid or empty. Use device default.
+ mHighDisplayBrightnessThresholds = mContext.getResources().getIntArray(
+ R.array.config_highDisplayBrightnessThresholdsOfFixedRefreshRate);
+ mHighAmbientBrightnessThresholds = mContext.getResources().getIntArray(
+ R.array.config_highAmbientBrightnessThresholdsOfFixedRefreshRate);
+ }
+ restartObserver();
+ }
+
+ public void onDeviceConfigRefreshRateInHighZoneChanged(int refreshRate) {
+ if (refreshRate != mRefreshRateInHighZone) {
+ mRefreshRateInHighZone = refreshRate;
restartObserver();
}
}
@@ -1332,48 +1496,95 @@ public class DisplayModeDirector {
public void dumpLocked(PrintWriter pw) {
pw.println(" BrightnessObserver");
pw.println(" mAmbientLux: " + mAmbientLux);
- pw.println(" mRefreshRateInZone: " + mRefreshRateInZone);
+ pw.println(" mBrightness: " + mBrightness);
+ pw.println(" mDefaultDisplayOn: " + mDefaultDisplayOn);
+ pw.println(" mLowPowerModeEnabled: " + mLowPowerModeEnabled);
+ pw.println(" mRefreshRateChangeable: " + mRefreshRateChangeable);
+ pw.println(" mShouldObserveDisplayLowChange: " + mShouldObserveDisplayLowChange);
+ pw.println(" mShouldObserveAmbientLowChange: " + mShouldObserveAmbientLowChange);
+ pw.println(" mRefreshRateInLowZone: " + mRefreshRateInLowZone);
- for (int d: mDisplayBrightnessThresholds) {
- pw.println(" mDisplayBrightnessThreshold: " + d);
+ for (int d : mLowDisplayBrightnessThresholds) {
+ pw.println(" mDisplayLowBrightnessThreshold: " + d);
}
- for (int d: mAmbientBrightnessThresholds) {
- pw.println(" mAmbientBrightnessThreshold: " + d);
+ for (int d : mLowAmbientBrightnessThresholds) {
+ pw.println(" mAmbientLowBrightnessThreshold: " + d);
+ }
+
+ pw.println(" mShouldObserveDisplayHighChange: " + mShouldObserveDisplayHighChange);
+ pw.println(" mShouldObserveAmbientHighChange: " + mShouldObserveAmbientHighChange);
+ pw.println(" mRefreshRateInHighZone: " + mRefreshRateInHighZone);
+
+ for (int d : mHighDisplayBrightnessThresholds) {
+ pw.println(" mDisplayHighBrightnessThresholds: " + d);
+ }
+
+ for (int d : mHighAmbientBrightnessThresholds) {
+ pw.println(" mAmbientHighBrightnessThresholds: " + d);
}
mLightSensorListener.dumpLocked(pw);
+
+ if (mAmbientFilter != null) {
+ IndentingPrintWriter ipw = new IndentingPrintWriter(pw);
+ ipw.setIndent(" ");
+ mAmbientFilter.dump(ipw);
+ }
}
public void onDisplayChanged(int displayId) {
if (displayId == Display.DEFAULT_DISPLAY) {
- onScreenOn(isDefaultDisplayOn());
+ updateDefaultDisplayState();
}
}
@Override
public void onChange(boolean selfChange, Uri uri, int userId) {
synchronized (mLock) {
- onBrightnessChangedLocked();
+ final ContentResolver cr = mContext.getContentResolver();
+ int brightness = Settings.System.getIntForUser(cr,
+ Settings.System.SCREEN_BRIGHTNESS, -1 /*default*/, cr.getUserId());
+ if (brightness != mBrightness) {
+ mBrightness = brightness;
+ onBrightnessChangedLocked();
+ }
}
}
private void restartObserver() {
- mShouldObserveDisplayChange = checkShouldObserve(mDisplayBrightnessThresholds);
- mShouldObserveAmbientChange = checkShouldObserve(mAmbientBrightnessThresholds);
-
final ContentResolver cr = mContext.getContentResolver();
- if (mShouldObserveDisplayChange) {
+
+ if (mRefreshRateInLowZone > 0) {
+ mShouldObserveDisplayLowChange = hasValidThreshold(
+ mLowDisplayBrightnessThresholds);
+ mShouldObserveAmbientLowChange = hasValidThreshold(
+ mLowAmbientBrightnessThresholds);
+ } else {
+ mShouldObserveDisplayLowChange = false;
+ mShouldObserveAmbientLowChange = false;
+ }
+
+ if (mRefreshRateInHighZone > 0) {
+ mShouldObserveDisplayHighChange = hasValidThreshold(
+ mHighDisplayBrightnessThresholds);
+ mShouldObserveAmbientHighChange = hasValidThreshold(
+ mHighAmbientBrightnessThresholds);
+ } else {
+ mShouldObserveDisplayHighChange = false;
+ mShouldObserveAmbientHighChange = false;
+ }
+
+ if (mShouldObserveDisplayLowChange || mShouldObserveDisplayHighChange) {
// Content Service does not check if an listener has already been registered.
// To ensure only one listener is registered, force an unregistration first.
- cr.unregisterContentObserver(this);
- cr.registerContentObserver(mDisplayBrightnessSetting,
- false /*notifyDescendants*/, this, UserHandle.USER_SYSTEM);
+ mInjector.unregisterBrightnessObserver(cr, this);
+ mInjector.registerBrightnessObserver(cr, this);
} else {
- cr.unregisterContentObserver(this);
+ mInjector.unregisterBrightnessObserver(cr, this);
}
- if (mShouldObserveAmbientChange) {
+ if (mShouldObserveAmbientLowChange || mShouldObserveAmbientHighChange) {
Resources resources = mContext.getResources();
String lightSensorType = resources.getString(
com.android.internal.R.string.config_displayLightSensorType);
@@ -1399,8 +1610,6 @@ public class DisplayModeDirector {
mAmbientFilter = AmbientFilterFactory.createBrightnessFilter(TAG, res);
mLightSensor = lightSensor;
-
- onScreenOn(isDefaultDisplayOn());
}
} else {
mAmbientFilter = null;
@@ -1419,11 +1628,7 @@ public class DisplayModeDirector {
* Checks to see if at least one value is positive, in which case it is necessary to listen
* to value changes.
*/
- private boolean checkShouldObserve(int[] a) {
- if (mRefreshRateInZone <= 0) {
- return false;
- }
-
+ private boolean hasValidThreshold(int[] a) {
for (int d: a) {
if (d >= 0) {
return true;
@@ -1433,13 +1638,13 @@ public class DisplayModeDirector {
return false;
}
- private boolean isInsideZone(int brightness, float lux) {
- for (int i = 0; i < mDisplayBrightnessThresholds.length; i++) {
- int disp = mDisplayBrightnessThresholds[i];
- int ambi = mAmbientBrightnessThresholds[i];
+ private boolean isInsideLowZone(int brightness, float lux) {
+ for (int i = 0; i < mLowDisplayBrightnessThresholds.length; i++) {
+ int disp = mLowDisplayBrightnessThresholds[i];
+ int ambi = mLowAmbientBrightnessThresholds[i];
if (disp >= 0 && ambi >= 0) {
- if (brightness <= disp && mAmbientLux <= ambi) {
+ if (brightness <= disp && lux <= ambi) {
return true;
}
} else if (disp >= 0) {
@@ -1447,7 +1652,7 @@ public class DisplayModeDirector {
return true;
}
} else if (ambi >= 0) {
- if (mAmbientLux <= ambi) {
+ if (lux <= ambi) {
return true;
}
}
@@ -1455,28 +1660,77 @@ public class DisplayModeDirector {
return false;
}
- // TODO: brightnessfloat: make it use float not int
- private void onBrightnessChangedLocked() {
- final ContentResolver cr = mContext.getContentResolver();
- int brightness = Settings.System.getIntForUser(cr,
- Settings.System.SCREEN_BRIGHTNESS, -1, cr.getUserId());
+ private boolean isInsideHighZone(int brightness, float lux) {
+ for (int i = 0; i < mHighDisplayBrightnessThresholds.length; i++) {
+ int disp = mHighDisplayBrightnessThresholds[i];
+ int ambi = mHighAmbientBrightnessThresholds[i];
+
+ if (disp >= 0 && ambi >= 0) {
+ if (brightness >= disp && lux >= ambi) {
+ return true;
+ }
+ } else if (disp >= 0) {
+ if (brightness >= disp) {
+ return true;
+ }
+ } else if (ambi >= 0) {
+ if (lux >= ambi) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+ private void onBrightnessChangedLocked() {
Vote vote = null;
- boolean insideZone = isInsideZone(brightness, mAmbientLux);
- if (insideZone) {
- vote = Vote.forRefreshRates(mRefreshRateInZone, mRefreshRateInZone);
+
+ if (mBrightness < 0) {
+ // Either the setting isn't available or we shouldn't be observing yet anyways.
+ // Either way, just bail out since there's nothing we can do here.
+ return;
+ }
+
+ boolean insideLowZone = hasValidLowZone() && isInsideLowZone(mBrightness, mAmbientLux);
+ if (insideLowZone) {
+ vote = Vote.forRefreshRates(mRefreshRateInLowZone, mRefreshRateInLowZone);
+ }
+
+ boolean insideHighZone = hasValidHighZone()
+ && isInsideHighZone(mBrightness, mAmbientLux);
+ if (insideHighZone) {
+ vote = Vote.forRefreshRates(mRefreshRateInHighZone, mRefreshRateInHighZone);
}
if (DEBUG) {
- Slog.d(TAG, "Display brightness " + brightness + ", ambient lux " + mAmbientLux +
- ", Vote " + vote);
+ Slog.d(TAG, "Display brightness " + mBrightness + ", ambient lux " + mAmbientLux
+ + ", Vote " + vote);
}
- updateVoteLocked(Vote.PRIORITY_LOW_BRIGHTNESS, vote);
+ updateVoteLocked(Vote.PRIORITY_FLICKER, vote);
+ }
+
+ private boolean hasValidLowZone() {
+ return mRefreshRateInLowZone > 0
+ && (mShouldObserveDisplayLowChange || mShouldObserveAmbientLowChange);
+ }
+
+ private boolean hasValidHighZone() {
+ return mRefreshRateInHighZone > 0
+ && (mShouldObserveDisplayHighChange || mShouldObserveAmbientHighChange);
+ }
+
+ private void updateDefaultDisplayState() {
+ Display display = mContext.getSystemService(DisplayManager.class)
+ .getDisplay(Display.DEFAULT_DISPLAY);
+ boolean defaultDisplayOn = display != null && display.getState() != Display.STATE_OFF;
+ setDefaultDisplayState(defaultDisplayOn);
}
- private void onScreenOn(boolean on) {
- if (mScreenOn != on) {
- mScreenOn = on;
+ @VisibleForTesting
+ public void setDefaultDisplayState(boolean on) {
+ if (mDefaultDisplayOn != on) {
+ mDefaultDisplayOn = on;
updateSensorStatus();
}
}
@@ -1486,8 +1740,8 @@ public class DisplayModeDirector {
return;
}
- if (mShouldObserveAmbientChange && mScreenOn && !mLowPowerModeEnabled
- && mRefreshRateChangeable) {
+ if ((mShouldObserveAmbientLowChange || mShouldObserveAmbientHighChange)
+ && isDeviceActive() && !mLowPowerModeEnabled && mRefreshRateChangeable) {
mSensorManager.registerListener(mLightSensorListener,
mLightSensor, LIGHT_SENSOR_RATE_MS * 1000, mHandler);
} else {
@@ -1496,11 +1750,8 @@ public class DisplayModeDirector {
}
}
- private boolean isDefaultDisplayOn() {
- final Display display = mContext.getSystemService(DisplayManager.class)
- .getDisplay(Display.DEFAULT_DISPLAY);
- return display.getState() != Display.STATE_OFF
- && mContext.getSystemService(PowerManager.class).isInteractive();
+ private boolean isDeviceActive() {
+ return mDefaultDisplayOn && mInjector.isDeviceInteractive(mContext);
}
private final class LightSensorEventListener implements SensorEventListener {
@@ -1518,23 +1769,33 @@ public class DisplayModeDirector {
Slog.d(TAG, "On sensor changed: " + mLastSensorData);
}
- boolean zoneChanged = isDifferentZone(mLastSensorData, mAmbientLux);
- if (zoneChanged && mLastSensorData < mAmbientLux) {
- // Easier to see flicker at lower brightness environment. Forget the history to
- // get immediate response.
- mAmbientFilter.clear();
+ boolean lowZoneChanged = isDifferentZone(mLastSensorData, mAmbientLux,
+ mLowAmbientBrightnessThresholds);
+ boolean highZoneChanged = isDifferentZone(mLastSensorData, mAmbientLux,
+ mHighAmbientBrightnessThresholds);
+ if ((lowZoneChanged && mLastSensorData < mAmbientLux)
+ || (highZoneChanged && mLastSensorData > mAmbientLux)) {
+ // Easier to see flicker at lower brightness environment or high brightness
+ // environment. Forget the history to get immediate response.
+ if (mAmbientFilter != null) {
+ mAmbientFilter.clear();
+ }
}
long now = SystemClock.uptimeMillis();
- mAmbientFilter.addValue(now, mLastSensorData);
+ if (mAmbientFilter != null) {
+ mAmbientFilter.addValue(now, mLastSensorData);
+ }
mHandler.removeCallbacks(mInjectSensorEventRunnable);
processSensorData(now);
- if (zoneChanged && mLastSensorData > mAmbientLux) {
+ if ((lowZoneChanged && mLastSensorData > mAmbientLux)
+ || (highZoneChanged && mLastSensorData < mAmbientLux)) {
// Sensor may not report new event if there is no brightness change.
// Need to keep querying the temporal filter for the latest estimation,
- // until enter in higher lux zone or is interrupted by a new sensor event.
+ // until sensor readout and filter estimation are in the same zone or
+ // is interrupted by a new sensor event.
mHandler.postDelayed(mInjectSensorEventRunnable, INJECT_EVENTS_INTERVAL_MS);
}
}
@@ -1549,17 +1810,19 @@ public class DisplayModeDirector {
}
private void processSensorData(long now) {
- mAmbientLux = mAmbientFilter.getEstimate(now);
+ if (mAmbientFilter != null) {
+ mAmbientLux = mAmbientFilter.getEstimate(now);
+ } else {
+ mAmbientLux = mLastSensorData;
+ }
synchronized (mLock) {
onBrightnessChangedLocked();
}
}
- private boolean isDifferentZone(float lux1, float lux2) {
- for (int z = 0; z < mAmbientBrightnessThresholds.length; z++) {
- final float boundary = mAmbientBrightnessThresholds[z];
-
+ private boolean isDifferentZone(float lux1, float lux2, int[] luxThresholds) {
+ for (final float boundary : luxThresholds) {
// Test each boundary. See if the current value and the new value are at
// different sides.
if ((lux1 <= boundary && lux2 > boundary)
@@ -1579,7 +1842,10 @@ public class DisplayModeDirector {
processSensorData(now);
// Inject next event if there is a possible zone change.
- if (isDifferentZone(mLastSensorData, mAmbientLux)) {
+ if (isDifferentZone(mLastSensorData, mAmbientLux,
+ mLowAmbientBrightnessThresholds)
+ || isDifferentZone(mLastSensorData, mAmbientLux,
+ mHighAmbientBrightnessThresholds)) {
mHandler.postDelayed(mInjectSensorEventRunnable, INJECT_EVENTS_INTERVAL_MS);
}
}
@@ -1592,72 +1858,113 @@ public class DisplayModeDirector {
}
public void startListening() {
- DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_DISPLAY_MANAGER,
+ mDeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_DISPLAY_MANAGER,
BackgroundThread.getExecutor(), this);
}
/*
* Return null if no such property or wrong format (not comma separated integers).
*/
- public int[] getBrightnessThresholds() {
+ public int[] getLowDisplayBrightnessThresholds() {
return getIntArrayProperty(
DisplayManager.DeviceConfig.
- KEY_PEAK_REFRESH_RATE_DISPLAY_BRIGHTNESS_THRESHOLDS);
+ KEY_FIXED_REFRESH_RATE_LOW_DISPLAY_BRIGHTNESS_THRESHOLDS);
}
/*
* Return null if no such property or wrong format (not comma separated integers).
*/
- public int[] getAmbientThresholds() {
+ public int[] getLowAmbientBrightnessThresholds() {
return getIntArrayProperty(
DisplayManager.DeviceConfig.
- KEY_PEAK_REFRESH_RATE_AMBIENT_BRIGHTNESS_THRESHOLDS);
+ KEY_FIXED_REFRESH_RATE_LOW_AMBIENT_BRIGHTNESS_THRESHOLDS);
+ }
+
+ public int getRefreshRateInLowZone() {
+ int defaultRefreshRateInZone = mContext.getResources().getInteger(
+ R.integer.config_defaultRefreshRateInZone);
+
+ int refreshRate = mDeviceConfig.getInt(
+ DeviceConfig.NAMESPACE_DISPLAY_MANAGER,
+ DisplayManager.DeviceConfig.KEY_REFRESH_RATE_IN_LOW_ZONE,
+ defaultRefreshRateInZone);
+
+ return refreshRate;
}
/*
- * Return null if no such property
+ * Return null if no such property or wrong format (not comma separated integers).
*/
- public Float getDefaultPeakRefreshRate() {
- float defaultPeakRefreshRate = DeviceConfig.getFloat(
- DeviceConfig.NAMESPACE_DISPLAY_MANAGER,
- DisplayManager.DeviceConfig.KEY_PEAK_REFRESH_RATE_DEFAULT, -1);
+ public int[] getHighDisplayBrightnessThresholds() {
+ return getIntArrayProperty(
+ DisplayManager.DeviceConfig
+ .KEY_FIXED_REFRESH_RATE_HIGH_DISPLAY_BRIGHTNESS_THRESHOLDS);
+ }
- if (defaultPeakRefreshRate == -1) {
- return null;
- }
- return defaultPeakRefreshRate;
+ /*
+ * Return null if no such property or wrong format (not comma separated integers).
+ */
+ public int[] getHighAmbientBrightnessThresholds() {
+ return getIntArrayProperty(
+ DisplayManager.DeviceConfig
+ .KEY_FIXED_REFRESH_RATE_HIGH_AMBIENT_BRIGHTNESS_THRESHOLDS);
}
- public int getRefreshRateInZone() {
+ public int getRefreshRateInHighZone() {
int defaultRefreshRateInZone = mContext.getResources().getInteger(
- R.integer.config_defaultRefreshRateInZone);
+ R.integer.config_fixedRefreshRateInHighZone);
- int refreshRate = DeviceConfig.getInt(
+ int refreshRate = mDeviceConfig.getInt(
DeviceConfig.NAMESPACE_DISPLAY_MANAGER,
- DisplayManager.DeviceConfig.KEY_REFRESH_RATE_IN_ZONE,
+ DisplayManager.DeviceConfig.KEY_REFRESH_RATE_IN_HIGH_ZONE,
defaultRefreshRateInZone);
return refreshRate;
}
+ /*
+ * Return null if no such property
+ */
+ public Float getDefaultPeakRefreshRate() {
+ float defaultPeakRefreshRate = mDeviceConfig.getFloat(
+ DeviceConfig.NAMESPACE_DISPLAY_MANAGER,
+ DisplayManager.DeviceConfig.KEY_PEAK_REFRESH_RATE_DEFAULT, -1);
+
+ if (defaultPeakRefreshRate == -1) {
+ return null;
+ }
+ return defaultPeakRefreshRate;
+ }
+
@Override
public void onPropertiesChanged(@NonNull DeviceConfig.Properties properties) {
- int[] brightnessThresholds = getBrightnessThresholds();
- int[] ambientThresholds = getAmbientThresholds();
Float defaultPeakRefreshRate = getDefaultPeakRefreshRate();
- int refreshRateInZone = getRefreshRateInZone();
-
- mHandler.obtainMessage(MSG_BRIGHTNESS_THRESHOLDS_CHANGED,
- new Pair<int[], int[]>(brightnessThresholds, ambientThresholds))
- .sendToTarget();
mHandler.obtainMessage(MSG_DEFAULT_PEAK_REFRESH_RATE_CHANGED,
defaultPeakRefreshRate).sendToTarget();
- mHandler.obtainMessage(MSG_REFRESH_RATE_IN_ZONE_CHANGED, refreshRateInZone,
- 0).sendToTarget();
+
+ int[] lowDisplayBrightnessThresholds = getLowDisplayBrightnessThresholds();
+ int[] lowAmbientBrightnessThresholds = getLowAmbientBrightnessThresholds();
+ int refreshRateInLowZone = getRefreshRateInLowZone();
+
+ mHandler.obtainMessage(MSG_LOW_BRIGHTNESS_THRESHOLDS_CHANGED,
+ new Pair<>(lowDisplayBrightnessThresholds, lowAmbientBrightnessThresholds))
+ .sendToTarget();
+ mHandler.obtainMessage(MSG_REFRESH_RATE_IN_LOW_ZONE_CHANGED, refreshRateInLowZone, 0)
+ .sendToTarget();
+
+ int[] highDisplayBrightnessThresholds = getHighDisplayBrightnessThresholds();
+ int[] highAmbientBrightnessThresholds = getHighAmbientBrightnessThresholds();
+ int refreshRateInHighZone = getRefreshRateInHighZone();
+
+ mHandler.obtainMessage(MSG_HIGH_BRIGHTNESS_THRESHOLDS_CHANGED,
+ new Pair<>(highDisplayBrightnessThresholds, highAmbientBrightnessThresholds))
+ .sendToTarget();
+ mHandler.obtainMessage(MSG_REFRESH_RATE_IN_HIGH_ZONE_CHANGED, refreshRateInHighZone, 0)
+ .sendToTarget();
}
private int[] getIntArrayProperty(String prop) {
- String strArray = DeviceConfig.getString(DeviceConfig.NAMESPACE_DISPLAY_MANAGER, prop,
+ String strArray = mDeviceConfig.getString(DeviceConfig.NAMESPACE_DISPLAY_MANAGER, prop,
null);
if (strArray != null) {
@@ -1684,4 +1991,59 @@ public class DisplayModeDirector {
}
}
+ interface Injector {
+ // TODO: brightnessfloat: change this to the float setting
+ Uri DISPLAY_BRIGHTNESS_URI = Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS);
+ Uri PEAK_REFRESH_RATE_URI = Settings.System.getUriFor(Settings.System.PEAK_REFRESH_RATE);
+
+ @NonNull
+ DeviceConfigInterface getDeviceConfig();
+
+ void registerBrightnessObserver(@NonNull ContentResolver cr,
+ @NonNull ContentObserver observer);
+
+ void unregisterBrightnessObserver(@NonNull ContentResolver cr,
+ @NonNull ContentObserver observer);
+
+ void registerPeakRefreshRateObserver(@NonNull ContentResolver cr,
+ @NonNull ContentObserver observer);
+
+ boolean isDeviceInteractive(@NonNull Context context);
+ }
+
+ @VisibleForTesting
+ static class RealInjector implements Injector {
+
+ @Override
+ @NonNull
+ public DeviceConfigInterface getDeviceConfig() {
+ return DeviceConfigInterface.REAL;
+ }
+
+ @Override
+ public void registerBrightnessObserver(@NonNull ContentResolver cr,
+ @NonNull ContentObserver observer) {
+ cr.registerContentObserver(DISPLAY_BRIGHTNESS_URI, false /*notifyDescendants*/,
+ observer, UserHandle.USER_SYSTEM);
+ }
+
+ @Override
+ public void unregisterBrightnessObserver(@NonNull ContentResolver cr,
+ @NonNull ContentObserver observer) {
+ cr.unregisterContentObserver(observer);
+ }
+
+ @Override
+ public void registerPeakRefreshRateObserver(@NonNull ContentResolver cr,
+ @NonNull ContentObserver observer) {
+ cr.registerContentObserver(PEAK_REFRESH_RATE_URI, false /*notifyDescendants*/,
+ observer, UserHandle.USER_SYSTEM);
+ }
+
+ @Override
+ public boolean isDeviceInteractive(@NonNull Context ctx) {
+ return ctx.getSystemService(PowerManager.class).isInteractive();
+ }
+ }
+
}
diff --git a/services/core/java/com/android/server/display/PersistentDataStore.java b/services/core/java/com/android/server/display/PersistentDataStore.java
index 494dd397b1e9..b0820e81ec09 100644
--- a/services/core/java/com/android/server/display/PersistentDataStore.java
+++ b/services/core/java/com/android/server/display/PersistentDataStore.java
@@ -25,6 +25,7 @@ import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseLongArray;
import android.util.TimeUtils;
+import android.util.TypedXmlPullParser;
import android.util.TypedXmlSerializer;
import android.util.Xml;
import android.view.Display;
@@ -322,7 +323,7 @@ final class PersistentDataStore {
return;
}
- XmlPullParser parser;
+ TypedXmlPullParser parser;
try {
parser = Xml.resolvePullParser(is);
loadFromXml(parser);
@@ -355,7 +356,7 @@ final class PersistentDataStore {
}
}
- private void loadFromXml(XmlPullParser parser)
+ private void loadFromXml(TypedXmlPullParser parser)
throws IOException, XmlPullParserException {
XmlUtils.beginDocument(parser, TAG_DISPLAY_MANAGER_STATE);
final int outerDepth = parser.getDepth();
@@ -375,7 +376,7 @@ final class PersistentDataStore {
}
}
- private void loadRememberedWifiDisplaysFromXml(XmlPullParser parser)
+ private void loadRememberedWifiDisplaysFromXml(TypedXmlPullParser parser)
throws IOException, XmlPullParserException {
final int outerDepth = parser.getDepth();
while (XmlUtils.nextElementWithin(parser, outerDepth)) {
@@ -399,7 +400,7 @@ final class PersistentDataStore {
}
}
- private void loadDisplaysFromXml(XmlPullParser parser)
+ private void loadDisplaysFromXml(TypedXmlPullParser parser)
throws IOException, XmlPullParserException {
final int outerDepth = parser.getDepth();
while (XmlUtils.nextElementWithin(parser, outerDepth)) {
@@ -420,7 +421,7 @@ final class PersistentDataStore {
}
}
- private void saveToXml(XmlSerializer serializer) throws IOException {
+ private void saveToXml(TypedXmlSerializer serializer) throws IOException {
serializer.startDocument(null, true);
serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
serializer.startTag(null, TAG_DISPLAY_MANAGER_STATE);
@@ -491,7 +492,7 @@ final class PersistentDataStore {
return mColorMode;
}
- public void loadFromXml(XmlPullParser parser)
+ public void loadFromXml(TypedXmlPullParser parser)
throws IOException, XmlPullParserException {
final int outerDepth = parser.getDepth();
@@ -503,7 +504,7 @@ final class PersistentDataStore {
}
}
- public void saveToXml(XmlSerializer serializer) throws IOException {
+ public void saveToXml(TypedXmlSerializer serializer) throws IOException {
serializer.startTag(null, TAG_COLOR_MODE);
serializer.text(Integer.toString(mColorMode));
serializer.endTag(null, TAG_COLOR_MODE);
@@ -531,7 +532,8 @@ final class PersistentDataStore {
return false;
}
- public void loadFromXml(XmlPullParser parser) throws IOException, XmlPullParserException {
+ public void loadFromXml(TypedXmlPullParser parser)
+ throws IOException, XmlPullParserException {
final int outerDepth = parser.getDepth();
while (XmlUtils.nextElementWithin(parser, outerDepth)) {
switch (parser.getName()) {
@@ -545,7 +547,7 @@ final class PersistentDataStore {
}
}
- private static int loadIntValue(XmlPullParser parser)
+ private static int loadIntValue(TypedXmlPullParser parser)
throws IOException, XmlPullParserException {
try {
String value = parser.nextText();
@@ -555,7 +557,7 @@ final class PersistentDataStore {
}
}
- public void saveToXml(XmlSerializer serializer) throws IOException {
+ public void saveToXml(TypedXmlSerializer serializer) throws IOException {
if (mWidth > 0 && mHeight > 0) {
serializer.startTag(null, TAG_STABLE_DISPLAY_WIDTH);
serializer.text(Integer.toString(mWidth));
@@ -612,14 +614,14 @@ final class PersistentDataStore {
return mConfigurations.get(userSerial);
}
- public void loadFromXml(XmlPullParser parser) throws IOException, XmlPullParserException {
+ public void loadFromXml(TypedXmlPullParser parser)
+ throws IOException, XmlPullParserException {
final int outerDepth = parser.getDepth();
while (XmlUtils.nextElementWithin(parser, outerDepth)) {
if (TAG_BRIGHTNESS_CONFIGURATION.equals(parser.getName())) {
int userSerial;
try {
- userSerial = Integer.parseInt(
- parser.getAttributeValue(null, ATTR_USER_SERIAL));
+ userSerial = parser.getAttributeInt(null, ATTR_USER_SERIAL);
} catch (NumberFormatException nfe) {
userSerial = -1;
Slog.e(TAG, "Failed to read in brightness configuration", nfe);
@@ -655,20 +657,20 @@ final class PersistentDataStore {
}
}
- public void saveToXml(XmlSerializer serializer) throws IOException {
+ public void saveToXml(TypedXmlSerializer serializer) throws IOException {
for (int i = 0; i < mConfigurations.size(); i++) {
final int userSerial = mConfigurations.keyAt(i);
final BrightnessConfiguration config = mConfigurations.valueAt(i);
serializer.startTag(null, TAG_BRIGHTNESS_CONFIGURATION);
- serializer.attribute(null, ATTR_USER_SERIAL, Integer.toString(userSerial));
+ serializer.attributeInt(null, ATTR_USER_SERIAL, userSerial);
String packageName = mPackageNames.get(userSerial);
if (packageName != null) {
serializer.attribute(null, ATTR_PACKAGE_NAME, packageName);
}
long timestamp = mTimeStamps.get(userSerial, -1);
if (timestamp != -1) {
- serializer.attribute(null, ATTR_TIME_STAMP, Long.toString(timestamp));
+ serializer.attributeLong(null, ATTR_TIME_STAMP, timestamp);
}
config.saveToXml(serializer);
serializer.endTag(null, TAG_BRIGHTNESS_CONFIGURATION);
diff --git a/services/core/java/com/android/server/graphics/fonts/FontManagerInternal.java b/services/core/java/com/android/server/graphics/fonts/FontManagerInternal.java
new file mode 100644
index 000000000000..e4b7b03a8e07
--- /dev/null
+++ b/services/core/java/com/android/server/graphics/fonts/FontManagerInternal.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.graphics.fonts;
+
+import android.annotation.Nullable;
+import android.os.SharedMemory;
+
+/** Local interface for {@link FontManagerService}. */
+public interface FontManagerInternal {
+
+ /** Returns a SharedMemory in which the system font map is serialized. */
+ @Nullable SharedMemory getSerializedSystemFontMap();
+}
diff --git a/services/core/java/com/android/server/graphics/fonts/FontManagerService.java b/services/core/java/com/android/server/graphics/fonts/FontManagerService.java
new file mode 100644
index 000000000000..22921ad1ecc2
--- /dev/null
+++ b/services/core/java/com/android/server/graphics/fonts/FontManagerService.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.graphics.fonts;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.graphics.Typeface;
+import android.os.SharedMemory;
+import android.system.ErrnoException;
+import android.util.Slog;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.server.LocalServices;
+import com.android.server.SystemService;
+
+import java.io.IOException;
+
+/** A service for managing system fonts. */
+// TODO(b/173619554): Add API to update fonts.
+public final class FontManagerService {
+
+ private static final String TAG = "FontManagerService";
+
+ /** Class to manage FontManagerService's lifecycle. */
+ public static final class Lifecycle extends SystemService {
+ private final FontManagerService mService;
+
+ public Lifecycle(@NonNull Context context) {
+ super(context);
+ mService = new FontManagerService();
+ }
+
+ @Override
+ public void onStart() {
+ LocalServices.addService(FontManagerInternal.class,
+ new FontManagerInternal() {
+ @Override
+ @Nullable
+ public SharedMemory getSerializedSystemFontMap() {
+ return mService.getSerializedSystemFontMap();
+ }
+ });
+ }
+ }
+
+ @GuardedBy("this")
+ @Nullable
+ private SharedMemory mSerializedSystemFontMap = null;
+
+ @Nullable
+ private SharedMemory getSerializedSystemFontMap() {
+ synchronized (FontManagerService.this) {
+ if (mSerializedSystemFontMap == null) {
+ mSerializedSystemFontMap = createSerializedSystemFontMapLocked();
+ }
+ return mSerializedSystemFontMap;
+ }
+ }
+
+ @Nullable
+ private SharedMemory createSerializedSystemFontMapLocked() {
+ // TODO(b/173619554): use updated fonts.
+ try {
+ return Typeface.serializeFontMap(Typeface.getSystemFontMap());
+ } catch (IOException | ErrnoException e) {
+ Slog.e(TAG, "Failed to serialize SystemServer system font map", e);
+ }
+ return null;
+ }
+}
diff --git a/services/core/java/com/android/server/hdmi/CecMessageBuffer.java b/services/core/java/com/android/server/hdmi/CecMessageBuffer.java
new file mode 100644
index 000000000000..8f971fd7db07
--- /dev/null
+++ b/services/core/java/com/android/server/hdmi/CecMessageBuffer.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.hdmi;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Buffer for processing the incoming CEC messages while allocating logical addresses.
+ */
+final class CecMessageBuffer {
+ private List<HdmiCecMessage> mBuffer = new ArrayList<>();
+ private HdmiControlService mHdmiControlService;
+
+ CecMessageBuffer(HdmiControlService hdmiControlService) {
+ mHdmiControlService = hdmiControlService;
+ }
+
+ /**
+ * Adds a message to the buffer.
+ * Only certain types of messages need to be buffered.
+ * @param message The message to add to the buffer
+ * @return Whether the message was added to the buffer
+ */
+ public boolean bufferMessage(HdmiCecMessage message) {
+ switch (message.getOpcode()) {
+ case Constants.MESSAGE_ACTIVE_SOURCE:
+ bufferActiveSource(message);
+ return true;
+ case Constants.MESSAGE_IMAGE_VIEW_ON:
+ case Constants.MESSAGE_TEXT_VIEW_ON:
+ bufferImageOrTextViewOn(message);
+ return true;
+ case Constants.MESSAGE_SYSTEM_AUDIO_MODE_REQUEST:
+ bufferSystemAudioModeRequest(message);
+ return true;
+ // Add here if new message that needs to buffer
+ default:
+ // Do not need to buffer messages other than above
+ return false;
+ }
+ }
+
+ /**
+ * Process all messages in the buffer.
+ */
+ public void processMessages() {
+ for (final HdmiCecMessage message : mBuffer) {
+ mHdmiControlService.runOnServiceThread(new Runnable() {
+ @Override
+ public void run() {
+ mHdmiControlService.handleCecCommand(message);
+ }
+ });
+ }
+ mBuffer.clear();
+ }
+
+ private void bufferActiveSource(HdmiCecMessage message) {
+ if (!replaceMessageIfBuffered(message, Constants.MESSAGE_ACTIVE_SOURCE)) {
+ mBuffer.add(message);
+ }
+ }
+
+ private void bufferImageOrTextViewOn(HdmiCecMessage message) {
+ if (!replaceMessageIfBuffered(message, Constants.MESSAGE_IMAGE_VIEW_ON)
+ && !replaceMessageIfBuffered(message, Constants.MESSAGE_TEXT_VIEW_ON)) {
+ mBuffer.add(message);
+ }
+ }
+
+ private void bufferSystemAudioModeRequest(HdmiCecMessage message) {
+ if (!replaceMessageIfBuffered(message, Constants.MESSAGE_SYSTEM_AUDIO_MODE_REQUEST)) {
+ mBuffer.add(message);
+ }
+ }
+
+ // Returns true if the message is replaced
+ private boolean replaceMessageIfBuffered(HdmiCecMessage message, int opcode) {
+ for (int i = 0; i < mBuffer.size(); i++) {
+ HdmiCecMessage bufferedMessage = mBuffer.get(i);
+ if (bufferedMessage.getOpcode() == opcode) {
+ mBuffer.set(i, message);
+ return true;
+ }
+ }
+ return false;
+ }
+}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecConfig.java b/services/core/java/com/android/server/hdmi/HdmiCecConfig.java
index 2374ece1dd65..a261fa1f2741 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecConfig.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecConfig.java
@@ -22,19 +22,12 @@ import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.StringDef;
-import android.content.ContentResolver;
import android.content.Context;
import android.content.SharedPreferences;
-import android.database.ContentObserver;
import android.hardware.hdmi.HdmiControlManager;
-import android.net.Uri;
import android.os.Environment;
-import android.os.Handler;
-import android.os.Looper;
import android.os.SystemProperties;
-import android.os.UserHandle;
import android.provider.Settings.Global;
-import android.util.ArrayMap;
import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;
@@ -95,23 +88,6 @@ public class HdmiCecConfig {
@Nullable private final CecSettings mProductConfig;
@Nullable private final CecSettings mVendorOverride;
- private final ArrayMap<Setting, Set<SettingChangeListener>>
- mSettingChangeListeners = new ArrayMap<>();
-
- private SettingsObserver mSettingsObserver;
-
- /**
- * Listener used to get notifications when value of a setting changes.
- */
- public interface SettingChangeListener {
- /**
- * Called when value of a setting changes.
- *
- * @param setting name of a CEC setting that changed
- */
- void onChange(@NonNull @CecSettingName String setting);
- }
-
/**
* Setting storage input/output helper class.
*/
@@ -183,18 +159,6 @@ public class HdmiCecConfig {
}
}
- private class SettingsObserver extends ContentObserver {
- SettingsObserver(Handler handler) {
- super(handler);
- }
-
- @Override
- public void onChange(boolean selfChange, Uri uri) {
- String setting = uri.getLastPathSegment();
- HdmiCecConfig.this.notifyGlobalSettingChanged(setting);
- }
- }
-
@VisibleForTesting
HdmiCecConfig(@NonNull Context context,
@NonNull StorageAdapter storageAdapter,
@@ -347,7 +311,6 @@ public class HdmiCecConfig {
} else if (storage == STORAGE_SHARED_PREFS) {
Slog.d(TAG, "Setting '" + storageKey + "' shared pref.");
mStorageAdapter.storeSharedPref(storageKey, value);
- notifySettingChanged(setting);
}
}
@@ -355,103 +318,6 @@ public class HdmiCecConfig {
return Integer.decode(value.getIntValue());
}
- private void notifyGlobalSettingChanged(String setting) {
- switch (setting) {
- case Global.HDMI_CONTROL_ENABLED:
- notifySettingChanged(HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED);
- break;
- case Global.HDMI_CEC_VERSION:
- notifySettingChanged(HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_VERSION);
- break;
- case Global.HDMI_CONTROL_SEND_STANDBY_ON_SLEEP:
- notifySettingChanged(HdmiControlManager.CEC_SETTING_NAME_SEND_STANDBY_ON_SLEEP);
- break;
- }
- }
-
- private void notifySettingChanged(@NonNull @CecSettingName String name) {
- Setting setting = getSetting(name);
- if (setting == null) {
- throw new IllegalArgumentException("Setting '" + name + "' does not exist.");
- }
- notifySettingChanged(setting);
- }
-
- private void notifySettingChanged(@NonNull Setting setting) {
- Set<SettingChangeListener> listeners = mSettingChangeListeners.get(setting);
- if (listeners == null) {
- return; // No listeners registered, do nothing.
- }
- for (SettingChangeListener listener: listeners) {
- listener.onChange(setting.getName());
- }
- }
-
- /**
- * This method registers Global Setting change observer.
- * Needs to be called once after initialization of HdmiCecConfig.
- */
- public void registerGlobalSettingsObserver(Looper looper) {
- Handler handler = new Handler(looper);
- mSettingsObserver = new SettingsObserver(handler);
- ContentResolver resolver = mContext.getContentResolver();
- String[] settings = new String[] {
- Global.HDMI_CONTROL_ENABLED,
- Global.HDMI_CEC_VERSION,
- Global.HDMI_CONTROL_SEND_STANDBY_ON_SLEEP,
- };
- for (String setting: settings) {
- resolver.registerContentObserver(Global.getUriFor(setting), false,
- mSettingsObserver, UserHandle.USER_ALL);
- }
- }
-
- /**
- * This method unregisters Global Setting change observer.
- */
- public void unregisterGlobalSettingsObserver() {
- ContentResolver resolver = mContext.getContentResolver();
- resolver.unregisterContentObserver(mSettingsObserver);
- }
-
- /**
- * Register change listener for a given setting name.
- */
- public void registerChangeListener(@NonNull @CecSettingName String name,
- SettingChangeListener listener) {
- Setting setting = getSetting(name);
- if (setting == null) {
- throw new IllegalArgumentException("Setting '" + name + "' does not exist.");
- }
- @Storage int storage = getStorage(setting);
- if (storage != STORAGE_GLOBAL_SETTINGS && storage != STORAGE_SHARED_PREFS) {
- throw new IllegalArgumentException("Change listeners for setting '" + name
- + "' not supported.");
- }
- if (!mSettingChangeListeners.containsKey(setting)) {
- mSettingChangeListeners.put(setting, new HashSet<>());
- }
- mSettingChangeListeners.get(setting).add(listener);
- }
-
- /**
- * Remove change listener for a given setting name.
- */
- public void removeChangeListener(@NonNull @CecSettingName String name,
- SettingChangeListener listener) {
- Setting setting = getSetting(name);
- if (setting == null) {
- throw new IllegalArgumentException("Setting '" + name + "' does not exist.");
- }
- if (mSettingChangeListeners.containsKey(setting)) {
- Set<SettingChangeListener> listeners = mSettingChangeListeners.get(setting);
- listeners.remove(listener);
- if (listeners.isEmpty()) {
- mSettingChangeListeners.remove(setting);
- }
- }
- }
-
/**
* Returns a list of all settings based on the XML metadata.
*/
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
index 11e18c54b1e4..ad3773e78b6a 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
@@ -1186,10 +1186,11 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
// When the device is not unplugged but reawaken from standby, we check if the System
// Audio Control Feature is enabled or not then decide if turning SAM on/off accordingly.
if (getAvrDeviceInfo() != null && portId == getAvrDeviceInfo().getPortId()) {
+ HdmiLogger.debug("Port ID:%d, 5v=%b", portId, connected);
if (!connected) {
setSystemAudioMode(false);
- } else if (mSystemAudioControlFeatureEnabled != mService.isSystemAudioActivated()){
- setSystemAudioMode(mSystemAudioControlFeatureEnabled);
+ } else {
+ onNewAvrAdded(getAvrDeviceInfo());
}
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index fd825d6f6288..56b73ba04d89 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -405,74 +405,7 @@ public class HdmiControlService extends SystemService {
// Use getAtomWriter() instead of accessing directly, to allow dependency injection for testing.
private HdmiCecAtomWriter mAtomWriter = new HdmiCecAtomWriter();
- // Buffer for processing the incoming cec messages while allocating logical addresses.
- private final class CecMessageBuffer {
- private List<HdmiCecMessage> mBuffer = new ArrayList<>();
-
- public boolean bufferMessage(HdmiCecMessage message) {
- switch (message.getOpcode()) {
- case Constants.MESSAGE_ACTIVE_SOURCE:
- bufferActiveSource(message);
- return true;
- case Constants.MESSAGE_IMAGE_VIEW_ON:
- case Constants.MESSAGE_TEXT_VIEW_ON:
- bufferImageOrTextViewOn(message);
- return true;
- case Constants.MESSAGE_SYSTEM_AUDIO_MODE_REQUEST:
- bufferSystemAudioModeRequest(message);
- return true;
- // Add here if new message that needs to buffer
- default:
- // Do not need to buffer messages other than above
- return false;
- }
- }
-
- public void processMessages() {
- for (final HdmiCecMessage message : mBuffer) {
- runOnServiceThread(new Runnable() {
- @Override
- public void run() {
- handleCecCommand(message);
- }
- });
- }
- mBuffer.clear();
- }
-
- private void bufferActiveSource(HdmiCecMessage message) {
- if (!replaceMessageIfBuffered(message, Constants.MESSAGE_ACTIVE_SOURCE)) {
- mBuffer.add(message);
- }
- }
-
- private void bufferImageOrTextViewOn(HdmiCecMessage message) {
- if (!replaceMessageIfBuffered(message, Constants.MESSAGE_IMAGE_VIEW_ON) &&
- !replaceMessageIfBuffered(message, Constants.MESSAGE_TEXT_VIEW_ON)) {
- mBuffer.add(message);
- }
- }
-
- private void bufferSystemAudioModeRequest(HdmiCecMessage message) {
- if (!replaceMessageIfBuffered(message, Constants.MESSAGE_SYSTEM_AUDIO_MODE_REQUEST)) {
- mBuffer.add(message);
- }
- }
-
- // Returns true if the message is replaced
- private boolean replaceMessageIfBuffered(HdmiCecMessage message, int opcode) {
- for (int i = 0; i < mBuffer.size(); i++) {
- HdmiCecMessage bufferedMessage = mBuffer.get(i);
- if (bufferedMessage.getOpcode() == opcode) {
- mBuffer.set(i, message);
- return true;
- }
- }
- return false;
- }
- }
-
- private final CecMessageBuffer mCecMessageBuffer = new CecMessageBuffer();
+ private CecMessageBuffer mCecMessageBuffer = new CecMessageBuffer(this);
private final SelectRequestBuffer mSelectRequestBuffer = new SelectRequestBuffer();
@@ -563,7 +496,6 @@ public class HdmiControlService extends SystemService {
if (mMessageValidator == null) {
mMessageValidator = new HdmiCecMessageValidator(this);
}
- mHdmiCecConfig.registerGlobalSettingsObserver(mIoLooper);
}
private void bootCompleted() {
@@ -988,6 +920,11 @@ public class HdmiControlService extends SystemService {
mMessageValidator = messageValidator;
}
+ @VisibleForTesting
+ void setCecMessageBuffer(CecMessageBuffer cecMessageBuffer) {
+ this.mCecMessageBuffer = cecMessageBuffer;
+ }
+
/**
* Returns {@link Looper} of main thread. Use this {@link Looper} instance
* for tasks that are running on main service thread.
diff --git a/services/core/java/com/android/server/hdmi/HdmiUtils.java b/services/core/java/com/android/server/hdmi/HdmiUtils.java
index e47b54472192..52a804a36750 100644
--- a/services/core/java/com/android/server/hdmi/HdmiUtils.java
+++ b/services/core/java/com/android/server/hdmi/HdmiUtils.java
@@ -25,6 +25,7 @@ import android.hardware.hdmi.HdmiControlManager;
import android.hardware.hdmi.HdmiDeviceInfo;
import android.util.Slog;
import android.util.SparseArray;
+import android.util.TypedXmlPullParser;
import android.util.Xml;
import com.android.internal.util.HexDump;
@@ -571,14 +572,13 @@ final class HdmiUtils {
// return a list of devices config
public static List<DeviceConfig> parse(InputStream in)
throws XmlPullParserException, IOException {
- XmlPullParser parser = Xml.newPullParser();
- parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false);
- parser.setInput(in, null);
+ TypedXmlPullParser parser = Xml.resolvePullParser(in);
parser.nextTag();
return readDevices(parser);
}
- private static void skip(XmlPullParser parser) throws XmlPullParserException, IOException {
+ private static void skip(TypedXmlPullParser parser)
+ throws XmlPullParserException, IOException {
if (parser.getEventType() != XmlPullParser.START_TAG) {
throw new IllegalStateException();
}
@@ -595,7 +595,7 @@ final class HdmiUtils {
}
}
- private static List<DeviceConfig> readDevices(XmlPullParser parser)
+ private static List<DeviceConfig> readDevices(TypedXmlPullParser parser)
throws XmlPullParserException, IOException {
List<DeviceConfig> devices = new ArrayList<>();
@@ -624,7 +624,7 @@ final class HdmiUtils {
// Processes device tags in the config.
@Nullable
- private static DeviceConfig readDeviceConfig(XmlPullParser parser, String deviceType)
+ private static DeviceConfig readDeviceConfig(TypedXmlPullParser parser, String deviceType)
throws XmlPullParserException, IOException {
List<CodecSad> codecSads = new ArrayList<>();
int format;
diff --git a/services/core/java/com/android/server/hdmi/SetArcTransmissionStateAction.java b/services/core/java/com/android/server/hdmi/SetArcTransmissionStateAction.java
index 6633789ffc06..db93ad0617ff 100644
--- a/services/core/java/com/android/server/hdmi/SetArcTransmissionStateAction.java
+++ b/services/core/java/com/android/server/hdmi/SetArcTransmissionStateAction.java
@@ -102,12 +102,12 @@ final class SetArcTransmissionStateAction extends HdmiCecFeatureAction {
}
private void setArcStatus(boolean enabled) {
- boolean wasEnabled = tv().setArcStatus(enabled);
- Slog.i(TAG, "Change arc status [old:" + wasEnabled + ", new:" + enabled + "]");
+ tv().setArcStatus(enabled);
+ Slog.i(TAG, "Change arc status to " + enabled);
// If enabled before and set to "disabled" and send <Report Arc Terminated> to
// av reciever.
- if (!enabled && wasEnabled) {
+ if (!enabled) {
sendCommand(HdmiCecMessageBuilder.buildReportArcTerminated(getSourceAddress(),
mAvrAddress));
}
diff --git a/services/core/java/com/android/server/input/ConfigurationProcessor.java b/services/core/java/com/android/server/input/ConfigurationProcessor.java
index 3888b1b71096..0563806895a0 100644
--- a/services/core/java/com/android/server/input/ConfigurationProcessor.java
+++ b/services/core/java/com/android/server/input/ConfigurationProcessor.java
@@ -18,15 +18,13 @@ package com.android.server.input;
import android.text.TextUtils;
import android.util.Slog;
+import android.util.TypedXmlPullParser;
import android.util.Xml;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.XmlUtils;
-import org.xmlpull.v1.XmlPullParser;
-
import java.io.InputStream;
-import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@@ -38,9 +36,8 @@ class ConfigurationProcessor {
static List<String> processExcludedDeviceNames(InputStream xml) throws Exception {
List<String> names = new ArrayList<>();
- try (InputStreamReader confReader = new InputStreamReader(xml)) {
- XmlPullParser parser = Xml.newPullParser();
- parser.setInput(confReader);
+ {
+ TypedXmlPullParser parser = Xml.resolvePullParser(xml);
XmlUtils.beginDocument(parser, "devices");
while (true) {
XmlUtils.nextElement(parser);
@@ -90,9 +87,8 @@ class ConfigurationProcessor {
static Map<String, Integer> processInputPortAssociations(InputStream xml)
throws Exception {
Map<String, Integer> associations = new HashMap<String, Integer>();
- try (InputStreamReader confReader = new InputStreamReader(xml)) {
- XmlPullParser parser = Xml.newPullParser();
- parser.setInput(confReader);
+ {
+ TypedXmlPullParser parser = Xml.resolvePullParser(xml);
XmlUtils.beginDocument(parser, "ports");
while (true) {
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index f2eb5af51616..42aad7d7ad5c 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -95,6 +95,7 @@ import com.android.internal.annotations.GuardedBy;
import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
import com.android.internal.notification.SystemNotificationChannels;
import com.android.internal.os.SomeArgs;
+import com.android.internal.util.ArrayUtils;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.XmlUtils;
import com.android.server.DisplayThread;
@@ -146,6 +147,16 @@ public class InputManagerService extends IInputManager.Stub
private static final int DEFAULT_VIBRATION_MAGNITUDE = 192;
+ /**
+ * We know the issue and are working to fix it, so suppressing the toast to not annoy
+ * dogfooders.
+ *
+ * TODO(b/169067926): Remove this
+ */
+ private static final String[] PACKAGE_BLOCKLIST_FOR_UNTRUSTED_TOUCHES_TOAST = {
+ "com.snapchat.android" // b/173297887
+ };
+
// Pointer to native input manager service object.
private final long mPtr;
@@ -2091,6 +2102,10 @@ public class InputManagerService extends IInputManager.Stub
// Native callback
private void notifyUntrustedTouch(String packageName) {
// TODO(b/169067926): Remove toast after gathering feedback on dogfood.
+ if (ArrayUtils.contains(PACKAGE_BLOCKLIST_FOR_UNTRUSTED_TOUCHES_TOAST, packageName)) {
+ Log.i(TAG, "Suppressing untrusted touch toast for " + packageName);
+ return;
+ }
DisplayThread.getHandler().post(() ->
Toast.makeText(mContext,
"Touch obscured by " + packageName
diff --git a/services/core/java/com/android/server/input/PersistentDataStore.java b/services/core/java/com/android/server/input/PersistentDataStore.java
index f61662d34e75..a735a8f9d305 100644
--- a/services/core/java/com/android/server/input/PersistentDataStore.java
+++ b/services/core/java/com/android/server/input/PersistentDataStore.java
@@ -253,7 +253,7 @@ final class PersistentDataStore {
}
}
- private void loadFromXml(XmlPullParser parser)
+ private void loadFromXml(TypedXmlPullParser parser)
throws IOException, XmlPullParserException {
XmlUtils.beginDocument(parser, "input-manager-state");
final int outerDepth = parser.getDepth();
@@ -264,7 +264,7 @@ final class PersistentDataStore {
}
}
- private void loadInputDevicesFromXml(XmlPullParser parser)
+ private void loadInputDevicesFromXml(TypedXmlPullParser parser)
throws IOException, XmlPullParserException {
final int outerDepth = parser.getDepth();
while (XmlUtils.nextElementWithin(parser, outerDepth)) {
@@ -285,7 +285,7 @@ final class PersistentDataStore {
}
}
- private void saveToXml(XmlSerializer serializer) throws IOException {
+ private void saveToXml(TypedXmlSerializer serializer) throws IOException {
serializer.startDocument(null, true);
serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
serializer.startTag(null, "input-manager-state");
@@ -422,7 +422,7 @@ final class PersistentDataStore {
return changed;
}
- public void loadFromXml(XmlPullParser parser)
+ public void loadFromXml(TypedXmlPullParser parser)
throws IOException, XmlPullParserException {
final int outerDepth = parser.getDepth();
while (XmlUtils.nextElementWithin(parser, outerDepth)) {
@@ -505,7 +505,7 @@ final class PersistentDataStore {
}
}
- public void saveToXml(XmlSerializer serializer) throws IOException {
+ public void saveToXml(TypedXmlSerializer serializer) throws IOException {
for (String layout : mKeyboardLayouts) {
serializer.startTag(null, "keyboard-layout");
serializer.attribute(null, "descriptor", layout);
diff --git a/services/core/java/com/android/server/inputmethod/AdditionalSubtypeUtils.java b/services/core/java/com/android/server/inputmethod/AdditionalSubtypeUtils.java
index a077b049b014..24b8e340dee9 100644
--- a/services/core/java/com/android/server/inputmethod/AdditionalSubtypeUtils.java
+++ b/services/core/java/com/android/server/inputmethod/AdditionalSubtypeUtils.java
@@ -31,17 +31,13 @@ import android.util.Xml;
import android.view.inputmethod.InputMethodInfo;
import android.view.inputmethod.InputMethodSubtype;
-import com.android.internal.util.FastXmlSerializer;
-
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
-import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
@@ -158,20 +154,17 @@ final class AdditionalSubtypeUtils {
final InputMethodSubtype subtype = subtypesList.get(i);
out.startTag(null, NODE_SUBTYPE);
if (subtype.hasSubtypeId()) {
- out.attribute(null, ATTR_IME_SUBTYPE_ID,
- String.valueOf(subtype.getSubtypeId()));
+ out.attributeInt(null, ATTR_IME_SUBTYPE_ID, subtype.getSubtypeId());
}
- out.attribute(null, ATTR_ICON, String.valueOf(subtype.getIconResId()));
- out.attribute(null, ATTR_LABEL, String.valueOf(subtype.getNameResId()));
+ out.attributeInt(null, ATTR_ICON, subtype.getIconResId());
+ out.attributeInt(null, ATTR_LABEL, subtype.getNameResId());
out.attribute(null, ATTR_IME_SUBTYPE_LOCALE, subtype.getLocale());
out.attribute(null, ATTR_IME_SUBTYPE_LANGUAGE_TAG,
subtype.getLanguageTag());
out.attribute(null, ATTR_IME_SUBTYPE_MODE, subtype.getMode());
out.attribute(null, ATTR_IME_SUBTYPE_EXTRA_VALUE, subtype.getExtraValue());
- out.attribute(null, ATTR_IS_AUXILIARY,
- String.valueOf(subtype.isAuxiliary() ? 1 : 0));
- out.attribute(null, ATTR_IS_ASCII_CAPABLE,
- String.valueOf(subtype.isAsciiCapable() ? 1 : 0));
+ out.attributeInt(null, ATTR_IS_AUXILIARY, subtype.isAuxiliary() ? 1 : 0);
+ out.attributeInt(null, ATTR_IS_ASCII_CAPABLE, subtype.isAsciiCapable() ? 1 : 0);
out.endTag(null, NODE_SUBTYPE);
}
out.endTag(null, NODE_IMI);
@@ -243,10 +236,8 @@ final class AdditionalSubtypeUtils {
Slog.w(TAG, "IME uninstalled or not valid.: " + currentImiId);
continue;
}
- final int icon = Integer.parseInt(
- parser.getAttributeValue(null, ATTR_ICON));
- final int label = Integer.parseInt(
- parser.getAttributeValue(null, ATTR_LABEL));
+ final int icon = parser.getAttributeInt(null, ATTR_ICON);
+ final int label = parser.getAttributeInt(null, ATTR_LABEL);
final String imeSubtypeLocale =
parser.getAttributeValue(null, ATTR_IME_SUBTYPE_LOCALE);
final String languageTag =
@@ -269,10 +260,10 @@ final class AdditionalSubtypeUtils {
.setSubtypeExtraValue(imeSubtypeExtraValue)
.setIsAuxiliary(isAuxiliary)
.setIsAsciiCapable(isAsciiCapable);
- final String subtypeIdString =
- parser.getAttributeValue(null, ATTR_IME_SUBTYPE_ID);
- if (subtypeIdString != null) {
- builder.setSubtypeId(Integer.parseInt(subtypeIdString));
+ final int subtypeId = parser.getAttributeInt(null, ATTR_IME_SUBTYPE_ID,
+ InputMethodSubtype.SUBTYPE_ID_NONE);
+ if (subtypeId != InputMethodSubtype.SUBTYPE_ID_NONE) {
+ builder.setSubtypeId(subtypeId);
}
tempSubtypesArray.add(builder.build());
}
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 0ceaf7748eba..6395094038c7 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -158,6 +158,8 @@ import android.view.inputmethod.InputMethodSubtype;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.compat.IPlatformCompat;
import com.android.internal.content.PackageMonitor;
+import com.android.internal.inputmethod.CallbackUtils;
+import com.android.internal.inputmethod.IInputBindResultResultCallback;
import com.android.internal.inputmethod.IInputContentUriToken;
import com.android.internal.inputmethod.IInputMethodPrivilegedOperations;
import com.android.internal.inputmethod.InputMethodDebug;
@@ -208,6 +210,7 @@ import java.util.Objects;
import java.util.WeakHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.Supplier;
/**
* This class provides a system service that manages input methods.
@@ -1534,12 +1537,14 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
@Override
public void sessionCreated(IInputMethodSession session) {
+ Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMMS.sessionCreated");
final long ident = Binder.clearCallingIdentity();
try {
mParentIMMS.onSessionCreated(mMethod, session, mChannel);
} finally {
Binder.restoreCallingIdentity(ident);
}
+ Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
}
@@ -2284,6 +2289,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
}
if (mCurClient == cs) {
+ hideCurrentInputLocked(
+ mCurFocusedWindow, 0, null, SoftInputShowHideReason.HIDE_REMOVE_CLIENT);
if (mBoundToMethod) {
mBoundToMethod = false;
if (mCurMethod != null) {
@@ -2610,6 +2617,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
+ Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMMS.onServiceConnected");
synchronized (mMethodMap) {
if (mCurIntent != null && name.equals(mCurIntent.getComponent())) {
mCurMethod = IInputMethod.Stub.asInterface(service);
@@ -2625,6 +2633,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
if (mCurToken == null) {
Slog.w(TAG, "Service connected without a token!");
unbindCurrentMethodLocked();
+ Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
return;
}
if (DEBUG) Slog.v(TAG, "Initiating attach with token: " + mCurToken);
@@ -2638,6 +2647,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
}
}
}
+ Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
void onSessionCreated(IInputMethod method, IInputMethodSession session,
@@ -3345,63 +3355,68 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
@NonNull
@Override
- public InputBindResult startInputOrWindowGainedFocus(
+ public void startInputOrWindowGainedFocus(
@StartInputReason int startInputReason, IInputMethodClient client, IBinder windowToken,
@StartInputFlags int startInputFlags, @SoftInputModeFlags int softInputMode,
int windowFlags, @Nullable EditorInfo attribute, IInputContext inputContext,
- @MissingMethodFlags int missingMethods, int unverifiedTargetSdkVersion) {
- if (windowToken == null) {
- Slog.e(TAG, "windowToken cannot be null.");
- return InputBindResult.NULL;
- }
- try {
- Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER,
- "IMMS.startInputOrWindowGainedFocus");
- ImeTracing.getInstance().triggerManagerServiceDump(
- "InputMethodManagerService#startInputOrWindowGainedFocus");
- final int callingUserId = UserHandle.getCallingUserId();
- final int userId;
- if (attribute != null && attribute.targetInputMethodUser != null
- && attribute.targetInputMethodUser.getIdentifier() != callingUserId) {
- mContext.enforceCallingPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL,
- "Using EditorInfo.targetInputMethodUser requires"
- + " INTERACT_ACROSS_USERS_FULL.");
- userId = attribute.targetInputMethodUser.getIdentifier();
- if (!mUserManagerInternal.isUserRunning(userId)) {
- // There is a chance that we hit here because of race condition. Let's just
- // return an error code instead of crashing the caller process, which at least
- // has INTERACT_ACROSS_USERS_FULL permission thus is likely to be an important
- // process.
- Slog.e(TAG, "User #" + userId + " is not running.");
- return InputBindResult.INVALID_USER;
- }
- } else {
- userId = callingUserId;
- }
- final InputBindResult result;
- synchronized (mMethodMap) {
- final long ident = Binder.clearCallingIdentity();
- try {
- result = startInputOrWindowGainedFocusInternalLocked(startInputReason, client,
- windowToken, startInputFlags, softInputMode, windowFlags, attribute,
- inputContext, missingMethods, unverifiedTargetSdkVersion, userId);
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- }
- if (result == null) {
- // This must never happen, but just in case.
- Slog.wtf(TAG, "InputBindResult is @NonNull. startInputReason="
- + InputMethodDebug.startInputReasonToString(startInputReason)
- + " windowFlags=#" + Integer.toHexString(windowFlags)
- + " editorInfo=" + attribute);
+ @MissingMethodFlags int missingMethods, int unverifiedTargetSdkVersion,
+ IInputBindResultResultCallback resultCallback) {
+ CallbackUtils.onResult(resultCallback, (Supplier<InputBindResult>) () -> {
+ if (windowToken == null) {
+ Slog.e(TAG, "windowToken cannot be null.");
return InputBindResult.NULL;
}
+ try {
+ Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER,
+ "IMMS.startInputOrWindowGainedFocus");
+ ImeTracing.getInstance().triggerManagerServiceDump(
+ "InputMethodManagerService#startInputOrWindowGainedFocus");
+ final int callingUserId = UserHandle.getCallingUserId();
+ final int userId;
+ if (attribute != null && attribute.targetInputMethodUser != null
+ && attribute.targetInputMethodUser.getIdentifier() != callingUserId) {
+ mContext.enforceCallingPermission(
+ Manifest.permission.INTERACT_ACROSS_USERS_FULL,
+ "Using EditorInfo.targetInputMethodUser requires"
+ + " INTERACT_ACROSS_USERS_FULL.");
+ userId = attribute.targetInputMethodUser.getIdentifier();
+ if (!mUserManagerInternal.isUserRunning(userId)) {
+ // There is a chance that we hit here because of race condition. Let's just
+ // return an error code instead of crashing the caller process, which at
+ // least has INTERACT_ACROSS_USERS_FULL permission thus is likely to be an
+ // important process.
+ Slog.e(TAG, "User #" + userId + " is not running.");
+ return InputBindResult.INVALID_USER;
+ }
+ } else {
+ userId = callingUserId;
+ }
+ final InputBindResult result;
+ synchronized (mMethodMap) {
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ result = startInputOrWindowGainedFocusInternalLocked(startInputReason,
+ client, windowToken, startInputFlags, softInputMode, windowFlags,
+ attribute, inputContext, missingMethods, unverifiedTargetSdkVersion,
+ userId);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+ if (result == null) {
+ // This must never happen, but just in case.
+ Slog.wtf(TAG, "InputBindResult is @NonNull. startInputReason="
+ + InputMethodDebug.startInputReasonToString(startInputReason)
+ + " windowFlags=#" + Integer.toHexString(windowFlags)
+ + " editorInfo=" + attribute);
+ return InputBindResult.NULL;
+ }
- return result;
- } finally {
- Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
- }
+ return result;
+ } finally {
+ Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
+ }
+ });
}
@NonNull
diff --git a/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
index 62d817c22ae6..6bdae63461b2 100644
--- a/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
@@ -72,6 +72,8 @@ import android.view.inputmethod.InputMethodSubtype;
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.inputmethod.CallbackUtils;
+import com.android.internal.inputmethod.IInputBindResultResultCallback;
import com.android.internal.inputmethod.IMultiClientInputMethod;
import com.android.internal.inputmethod.IMultiClientInputMethodPrivilegedOperations;
import com.android.internal.inputmethod.IMultiClientInputMethodSession;
@@ -104,6 +106,7 @@ import java.lang.annotation.Retention;
import java.util.Collections;
import java.util.List;
import java.util.WeakHashMap;
+import java.util.function.Supplier;
/**
* Actual implementation of multi-client InputMethodManagerService.
@@ -1588,7 +1591,26 @@ public final class MultiClientInputMethodManagerService {
@BinderThread
@Override
- public InputBindResult startInputOrWindowGainedFocus(
+ public void startInputOrWindowGainedFocus(
+ @StartInputReason int startInputReason,
+ @Nullable IInputMethodClient client,
+ @Nullable IBinder windowToken,
+ @StartInputFlags int startInputFlags,
+ @SoftInputModeFlags int softInputMode,
+ int windowFlags,
+ @Nullable EditorInfo editorInfo,
+ @Nullable IInputContext inputContext,
+ @MissingMethodFlags int missingMethods,
+ int unverifiedTargetSdkVersion,
+ IInputBindResultResultCallback resultCallback) {
+ CallbackUtils.onResult(resultCallback, (Supplier<InputBindResult>) () ->
+ startInputOrWindowGainedFocusInternal(startInputReason, client, windowToken,
+ startInputFlags, softInputMode, windowFlags, editorInfo, inputContext,
+ missingMethods, unverifiedTargetSdkVersion));
+ }
+
+ @BinderThread
+ private InputBindResult startInputOrWindowGainedFocusInternal(
@StartInputReason int startInputReason,
@Nullable IInputMethodClient client,
@Nullable IBinder windowToken,
@@ -1676,8 +1698,7 @@ public final class MultiClientInputMethodManagerService {
clientInfo.mMSInputMethodSession.startInputOrWindowGainedFocus(
inputContext, missingMethods, editorInfo, startInputFlags,
softInputMode, windowHandle);
- } catch (RemoteException e) {
- }
+ } catch (RemoteException ignored) { }
break;
}
return InputBindResult.NULL_EDITOR_INFO;
@@ -1708,8 +1729,7 @@ public final class MultiClientInputMethodManagerService {
clientInfo.mMSInputMethodSession.startInputOrWindowGainedFocus(
inputContext, missingMethods, editorInfo, startInputFlags,
softInputMode, windowHandle);
- } catch (RemoteException e) {
- }
+ } catch (RemoteException ignored) { }
clientInfo.mState = InputMethodClientState.ALREADY_SENT_BIND_RESULT;
return new InputBindResult(
InputBindResult.ResultCode.SUCCESS_WITH_IME_SESSION,
diff --git a/services/core/java/com/android/server/integrity/parser/RuleMetadataParser.java b/services/core/java/com/android/server/integrity/parser/RuleMetadataParser.java
index 28d2e6914103..ab912906617b 100644
--- a/services/core/java/com/android/server/integrity/parser/RuleMetadataParser.java
+++ b/services/core/java/com/android/server/integrity/parser/RuleMetadataParser.java
@@ -17,6 +17,7 @@
package com.android.server.integrity.parser;
import android.annotation.Nullable;
+import android.util.TypedXmlPullParser;
import android.util.Xml;
import com.android.server.integrity.model.RuleMetadata;
@@ -26,7 +27,6 @@ import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
import java.io.InputStream;
-import java.nio.charset.StandardCharsets;
/** Helper class for parsing rule metadata. */
public class RuleMetadataParser {
@@ -42,8 +42,7 @@ public class RuleMetadataParser {
String ruleProvider = "";
String version = "";
- XmlPullParser xmlPullParser = Xml.newPullParser();
- xmlPullParser.setInput(inputStream, StandardCharsets.UTF_8.name());
+ TypedXmlPullParser xmlPullParser = Xml.resolvePullParser(inputStream);
int eventType;
while ((eventType = xmlPullParser.next()) != XmlPullParser.END_DOCUMENT) {
diff --git a/services/core/java/com/android/server/integrity/serializer/RuleMetadataSerializer.java b/services/core/java/com/android/server/integrity/serializer/RuleMetadataSerializer.java
index 5c51f31ba8cc..7aed35252816 100644
--- a/services/core/java/com/android/server/integrity/serializer/RuleMetadataSerializer.java
+++ b/services/core/java/com/android/server/integrity/serializer/RuleMetadataSerializer.java
@@ -19,6 +19,7 @@ package com.android.server.integrity.serializer;
import static com.android.server.integrity.parser.RuleMetadataParser.RULE_PROVIDER_TAG;
import static com.android.server.integrity.parser.RuleMetadataParser.VERSION_TAG;
+import android.util.TypedXmlSerializer;
import android.util.Xml;
import com.android.server.integrity.model.RuleMetadata;
@@ -34,8 +35,7 @@ public class RuleMetadataSerializer {
/** Serialize the rule metadata to an output stream. */
public static void serialize(RuleMetadata ruleMetadata, OutputStream outputStream)
throws IOException {
- XmlSerializer xmlSerializer = Xml.newSerializer();
- xmlSerializer.setOutput(outputStream, StandardCharsets.UTF_8.name());
+ TypedXmlSerializer xmlSerializer = Xml.resolveSerializer(outputStream);
serializeTaggedValue(xmlSerializer, RULE_PROVIDER_TAG, ruleMetadata.getRuleProvider());
serializeTaggedValue(xmlSerializer, VERSION_TAG, ruleMetadata.getVersion());
@@ -43,8 +43,8 @@ public class RuleMetadataSerializer {
xmlSerializer.endDocument();
}
- private static void serializeTaggedValue(XmlSerializer xmlSerializer, String tag, String value)
- throws IOException {
+ private static void serializeTaggedValue(TypedXmlSerializer xmlSerializer, String tag,
+ String value) throws IOException {
xmlSerializer.startTag(/* namespace= */ null, tag);
xmlSerializer.text(value);
xmlSerializer.endTag(/* namespace= */ null, tag);
diff --git a/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java b/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java
index a8889fd6b454..9e126673637f 100644
--- a/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java
@@ -987,21 +987,17 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
// update client uids
updateClientUids(mProviderRequest.getWorkSource());
- mFixInterval = (int) mProviderRequest.getIntervalMillis();
- // check for overflow
- if (mFixInterval != mProviderRequest.getIntervalMillis()) {
+ if (mProviderRequest.getIntervalMillis() <= Integer.MAX_VALUE) {
+ mFixInterval = (int) mProviderRequest.getIntervalMillis();
+ } else {
Log.w(TAG, "interval overflow: " + mProviderRequest.getIntervalMillis());
mFixInterval = Integer.MAX_VALUE;
}
- // requested batch size, or zero to disable batching
- int batchSize;
- try {
- batchSize = mBatchingEnabled ? Math.toIntExact(
- mProviderRequest.getMaxUpdateDelayMillis() / mFixInterval) : 0;
- } catch (ArithmeticException e) {
- batchSize = Integer.MAX_VALUE;
- }
+ // requested batch size, or zero to disable batching
+ long batchSize =
+ mBatchingEnabled ? mProviderRequest.getMaxUpdateDelayMillis() / Math.max(
+ mFixInterval, 1) : 0;
if (batchSize < getBatchSize()) {
batchSize = 0;
}
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotDeserializer.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotDeserializer.java
index 8a19d62de0b9..0c209c5b48dc 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotDeserializer.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotDeserializer.java
@@ -18,7 +18,6 @@ package com.android.server.locksettings.recoverablekeystore.serialization;
import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.CERTIFICATE_FACTORY_TYPE;
import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.NAMESPACE;
-import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.OUTPUT_ENCODING;
import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_ALGORITHM;
import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_ALIAS;
import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_APPLICATION_KEY;
@@ -46,6 +45,7 @@ import android.security.keystore.recovery.KeyChainSnapshot;
import android.security.keystore.recovery.KeyDerivationParams;
import android.security.keystore.recovery.WrappedApplicationKey;
import android.util.Base64;
+import android.util.TypedXmlPullParser;
import android.util.Xml;
import org.xmlpull.v1.XmlPullParser;
@@ -84,8 +84,7 @@ public class KeyChainSnapshotDeserializer {
private static KeyChainSnapshot deserializeInternal(InputStream inputStream) throws IOException,
XmlPullParserException, KeyChainSnapshotParserException {
- XmlPullParser parser = Xml.newPullParser();
- parser.setInput(inputStream, OUTPUT_ENCODING);
+ TypedXmlPullParser parser = Xml.resolvePullParser(inputStream);
parser.nextTag();
parser.require(XmlPullParser.START_TAG, NAMESPACE, TAG_KEY_CHAIN_SNAPSHOT);
@@ -156,7 +155,7 @@ public class KeyChainSnapshotDeserializer {
}
}
- private static List<WrappedApplicationKey> readWrappedApplicationKeys(XmlPullParser parser)
+ private static List<WrappedApplicationKey> readWrappedApplicationKeys(TypedXmlPullParser parser)
throws IOException, XmlPullParserException, KeyChainSnapshotParserException {
parser.require(XmlPullParser.START_TAG, NAMESPACE, TAG_APPLICATION_KEYS);
ArrayList<WrappedApplicationKey> keys = new ArrayList<>();
@@ -170,7 +169,7 @@ public class KeyChainSnapshotDeserializer {
return keys;
}
- private static WrappedApplicationKey readWrappedApplicationKey(XmlPullParser parser)
+ private static WrappedApplicationKey readWrappedApplicationKey(TypedXmlPullParser parser)
throws IOException, XmlPullParserException, KeyChainSnapshotParserException {
parser.require(XmlPullParser.START_TAG, NAMESPACE, TAG_APPLICATION_KEY);
WrappedApplicationKey.Builder builder = new WrappedApplicationKey.Builder();
@@ -209,7 +208,7 @@ public class KeyChainSnapshotDeserializer {
}
private static List<KeyChainProtectionParams> readKeyChainProtectionParamsList(
- XmlPullParser parser) throws IOException, XmlPullParserException,
+ TypedXmlPullParser parser) throws IOException, XmlPullParserException,
KeyChainSnapshotParserException {
parser.require(XmlPullParser.START_TAG, NAMESPACE, TAG_KEY_CHAIN_PROTECTION_PARAMS_LIST);
@@ -225,7 +224,7 @@ public class KeyChainSnapshotDeserializer {
return keyChainProtectionParamsList;
}
- private static KeyChainProtectionParams readKeyChainProtectionParams(XmlPullParser parser)
+ private static KeyChainProtectionParams readKeyChainProtectionParams(TypedXmlPullParser parser)
throws IOException, XmlPullParserException, KeyChainSnapshotParserException {
parser.require(XmlPullParser.START_TAG, NAMESPACE, TAG_KEY_CHAIN_PROTECTION_PARAMS);
@@ -269,7 +268,7 @@ public class KeyChainSnapshotDeserializer {
}
}
- private static KeyDerivationParams readKeyDerivationParams(XmlPullParser parser)
+ private static KeyDerivationParams readKeyDerivationParams(TypedXmlPullParser parser)
throws XmlPullParserException, IOException, KeyChainSnapshotParserException {
parser.require(XmlPullParser.START_TAG, NAMESPACE, TAG_KEY_DERIVATION_PARAMS);
@@ -331,7 +330,7 @@ public class KeyChainSnapshotDeserializer {
return keyDerivationParams;
}
- private static int readIntTag(XmlPullParser parser, String tagName)
+ private static int readIntTag(TypedXmlPullParser parser, String tagName)
throws IOException, XmlPullParserException, KeyChainSnapshotParserException {
parser.require(XmlPullParser.START_TAG, NAMESPACE, tagName);
String text = readText(parser);
@@ -345,7 +344,7 @@ public class KeyChainSnapshotDeserializer {
}
}
- private static long readLongTag(XmlPullParser parser, String tagName)
+ private static long readLongTag(TypedXmlPullParser parser, String tagName)
throws IOException, XmlPullParserException, KeyChainSnapshotParserException {
parser.require(XmlPullParser.START_TAG, NAMESPACE, tagName);
String text = readText(parser);
@@ -359,7 +358,7 @@ public class KeyChainSnapshotDeserializer {
}
}
- private static String readStringTag(XmlPullParser parser, String tagName)
+ private static String readStringTag(TypedXmlPullParser parser, String tagName)
throws IOException, XmlPullParserException {
parser.require(XmlPullParser.START_TAG, NAMESPACE, tagName);
String text = readText(parser);
@@ -367,7 +366,7 @@ public class KeyChainSnapshotDeserializer {
return text;
}
- private static byte[] readBlobTag(XmlPullParser parser, String tagName)
+ private static byte[] readBlobTag(TypedXmlPullParser parser, String tagName)
throws IOException, XmlPullParserException, KeyChainSnapshotParserException {
parser.require(XmlPullParser.START_TAG, NAMESPACE, tagName);
String text = readText(parser);
@@ -384,7 +383,7 @@ public class KeyChainSnapshotDeserializer {
}
}
- private static CertPath readCertPathTag(XmlPullParser parser, String tagName)
+ private static CertPath readCertPathTag(TypedXmlPullParser parser, String tagName)
throws IOException, XmlPullParserException, KeyChainSnapshotParserException {
byte[] bytes = readBlobTag(parser, tagName);
try {
@@ -396,7 +395,7 @@ public class KeyChainSnapshotDeserializer {
}
}
- private static String readText(XmlPullParser parser)
+ private static String readText(TypedXmlPullParser parser)
throws IOException, XmlPullParserException {
String result = "";
if (parser.next() == XmlPullParser.TEXT) {
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotSchema.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotSchema.java
index 8f85a27d4690..6475d9e530f8 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotSchema.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotSchema.java
@@ -22,8 +22,6 @@ package com.android.server.locksettings.recoverablekeystore.serialization;
class KeyChainSnapshotSchema {
static final String NAMESPACE = null;
- static final String OUTPUT_ENCODING = "UTF-8";
-
static final String CERTIFICATE_FACTORY_TYPE = "X.509";
static final String CERT_PATH_ENCODING = "PkiPath";
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotSerializer.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotSerializer.java
index 527e879a198b..eb34e981723d 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotSerializer.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotSerializer.java
@@ -19,7 +19,6 @@ package com.android.server.locksettings.recoverablekeystore.serialization;
import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.CERT_PATH_ENCODING;
import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.NAMESPACE;
-import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.OUTPUT_ENCODING;
import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_ALGORITHM;
import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_ALIAS;
import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_APPLICATION_KEY;
@@ -47,10 +46,9 @@ import android.security.keystore.recovery.KeyChainSnapshot;
import android.security.keystore.recovery.KeyDerivationParams;
import android.security.keystore.recovery.WrappedApplicationKey;
import android.util.Base64;
+import android.util.TypedXmlSerializer;
import android.util.Xml;
-import org.xmlpull.v1.XmlSerializer;
-
import java.io.IOException;
import java.io.OutputStream;
import java.security.cert.CertPath;
@@ -71,8 +69,7 @@ public class KeyChainSnapshotSerializer {
*/
public static void serialize(KeyChainSnapshot keyChainSnapshot, OutputStream outputStream)
throws IOException, CertificateEncodingException {
- XmlSerializer xmlSerializer = Xml.newSerializer();
- xmlSerializer.setOutput(outputStream, OUTPUT_ENCODING);
+ TypedXmlSerializer xmlSerializer = Xml.resolveSerializer(outputStream);
xmlSerializer.startDocument(
/*encoding=*/ null,
/*standalone=*/ null);
@@ -87,7 +84,7 @@ public class KeyChainSnapshotSerializer {
}
private static void writeApplicationKeys(
- XmlSerializer xmlSerializer, List<WrappedApplicationKey> wrappedApplicationKeys)
+ TypedXmlSerializer xmlSerializer, List<WrappedApplicationKey> wrappedApplicationKeys)
throws IOException {
xmlSerializer.startTag(NAMESPACE, TAG_APPLICATION_KEYS);
for (WrappedApplicationKey key : wrappedApplicationKeys) {
@@ -98,15 +95,15 @@ public class KeyChainSnapshotSerializer {
xmlSerializer.endTag(NAMESPACE, TAG_APPLICATION_KEYS);
}
- private static void writeApplicationKeyProperties(
- XmlSerializer xmlSerializer, WrappedApplicationKey applicationKey) throws IOException {
+ private static void writeApplicationKeyProperties(TypedXmlSerializer xmlSerializer,
+ WrappedApplicationKey applicationKey) throws IOException {
writePropertyTag(xmlSerializer, TAG_ALIAS, applicationKey.getAlias());
writePropertyTag(xmlSerializer, TAG_KEY_MATERIAL, applicationKey.getEncryptedKeyMaterial());
writePropertyTag(xmlSerializer, TAG_KEY_METADATA, applicationKey.getMetadata());
}
private static void writeKeyChainProtectionParams(
- XmlSerializer xmlSerializer,
+ TypedXmlSerializer xmlSerializer,
List<KeyChainProtectionParams> keyChainProtectionParamsList) throws IOException {
xmlSerializer.startTag(NAMESPACE, TAG_KEY_CHAIN_PROTECTION_PARAMS_LIST);
for (KeyChainProtectionParams keyChainProtectionParams : keyChainProtectionParamsList) {
@@ -118,7 +115,7 @@ public class KeyChainSnapshotSerializer {
}
private static void writeKeyChainProtectionParamsProperties(
- XmlSerializer xmlSerializer, KeyChainProtectionParams keyChainProtectionParams)
+ TypedXmlSerializer xmlSerializer, KeyChainProtectionParams keyChainProtectionParams)
throws IOException {
writePropertyTag(xmlSerializer, TAG_USER_SECRET_TYPE,
keyChainProtectionParams.getUserSecretType());
@@ -132,7 +129,7 @@ public class KeyChainSnapshotSerializer {
}
private static void writeKeyDerivationParams(
- XmlSerializer xmlSerializer, KeyDerivationParams keyDerivationParams)
+ TypedXmlSerializer xmlSerializer, KeyDerivationParams keyDerivationParams)
throws IOException {
xmlSerializer.startTag(NAMESPACE, TAG_KEY_DERIVATION_PARAMS);
writeKeyDerivationParamsProperties(
@@ -141,7 +138,7 @@ public class KeyChainSnapshotSerializer {
}
private static void writeKeyDerivationParamsProperties(
- XmlSerializer xmlSerializer, KeyDerivationParams keyDerivationParams)
+ TypedXmlSerializer xmlSerializer, KeyDerivationParams keyDerivationParams)
throws IOException {
writePropertyTag(xmlSerializer, TAG_ALGORITHM, keyDerivationParams.getAlgorithm());
writePropertyTag(xmlSerializer, TAG_SALT, keyDerivationParams.getSalt());
@@ -150,7 +147,7 @@ public class KeyChainSnapshotSerializer {
}
private static void writeKeyChainSnapshotProperties(
- XmlSerializer xmlSerializer, KeyChainSnapshot keyChainSnapshot)
+ TypedXmlSerializer xmlSerializer, KeyChainSnapshot keyChainSnapshot)
throws IOException, CertificateEncodingException {
writePropertyTag(xmlSerializer, TAG_SNAPSHOT_VERSION,
@@ -165,7 +162,7 @@ public class KeyChainSnapshotSerializer {
}
private static void writePropertyTag(
- XmlSerializer xmlSerializer, String propertyName, long propertyValue)
+ TypedXmlSerializer xmlSerializer, String propertyName, long propertyValue)
throws IOException {
xmlSerializer.startTag(NAMESPACE, propertyName);
xmlSerializer.text(Long.toString(propertyValue));
@@ -173,7 +170,7 @@ public class KeyChainSnapshotSerializer {
}
private static void writePropertyTag(
- XmlSerializer xmlSerializer, String propertyName, String propertyValue)
+ TypedXmlSerializer xmlSerializer, String propertyName, String propertyValue)
throws IOException {
xmlSerializer.startTag(NAMESPACE, propertyName);
xmlSerializer.text(propertyValue);
@@ -181,7 +178,7 @@ public class KeyChainSnapshotSerializer {
}
private static void writePropertyTag(
- XmlSerializer xmlSerializer, String propertyName, @Nullable byte[] propertyValue)
+ TypedXmlSerializer xmlSerializer, String propertyName, @Nullable byte[] propertyValue)
throws IOException {
if (propertyValue == null) {
return;
@@ -192,7 +189,7 @@ public class KeyChainSnapshotSerializer {
}
private static void writePropertyTag(
- XmlSerializer xmlSerializer, String propertyName, CertPath certPath)
+ TypedXmlSerializer xmlSerializer, String propertyName, CertPath certPath)
throws IOException, CertificateEncodingException {
writePropertyTag(xmlSerializer, propertyName, certPath.getEncoded(CERT_PATH_ENCODING));
}
diff --git a/services/core/java/com/android/server/media/MediaKeyDispatcher.java b/services/core/java/com/android/server/media/MediaKeyDispatcher.java
index 0dbc8392b610..63618eef250a 100644
--- a/services/core/java/com/android/server/media/MediaKeyDispatcher.java
+++ b/services/core/java/com/android/server/media/MediaKeyDispatcher.java
@@ -20,6 +20,7 @@ import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.PendingIntent;
+import android.content.Context;
import android.media.session.ISessionManager;
import android.media.session.MediaSession;
import android.os.Binder;
@@ -60,7 +61,7 @@ public abstract class MediaKeyDispatcher {
private Map<Integer, Integer> mOverriddenKeyEvents;
- public MediaKeyDispatcher() {
+ public MediaKeyDispatcher(Context context) {
// Constructor used for reflection
mOverriddenKeyEvents = new HashMap<>();
mOverriddenKeyEvents.put(KeyEvent.KEYCODE_MEDIA_PLAY, 0);
diff --git a/services/core/java/com/android/server/media/MediaServerUtils.java b/services/core/java/com/android/server/media/MediaServerUtils.java
index 5fa2b1ceaae9..a4f11b2470f1 100644
--- a/services/core/java/com/android/server/media/MediaServerUtils.java
+++ b/services/core/java/com/android/server/media/MediaServerUtils.java
@@ -18,6 +18,9 @@ package com.android.server.media;
import android.content.Context;
import android.content.pm.PackageManager;
+import android.media.AudioAttributes;
+import android.media.AudioManager;
+import android.media.AudioPlaybackConfiguration;
import android.os.Binder;
import java.io.PrintWriter;
@@ -29,7 +32,7 @@ class MediaServerUtils {
/**
* Verify that caller holds {@link android.Manifest.permission#DUMP}.
*/
- public static boolean checkDumpPermission(Context context, String tag, PrintWriter pw) {
+ static boolean checkDumpPermission(Context context, String tag, PrintWriter pw) {
if (context.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
!= PackageManager.PERMISSION_GRANTED) {
pw.println("Permission Denial: can't dump " + tag + " from from pid="
@@ -40,4 +43,18 @@ class MediaServerUtils {
return true;
}
}
+
+ /**
+ * Whether the given stream is currently active or not.
+ */
+ static boolean isStreamActive(AudioManager audioManager, int stream) {
+ for (AudioPlaybackConfiguration configuration
+ : audioManager.getActivePlaybackConfigurations()) {
+ AudioAttributes attributes = configuration.getAudioAttributes();
+ if (attributes != null && attributes.getVolumeControlStream() == stream) {
+ return configuration.isActive();
+ }
+ }
+ return false;
+ }
}
diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java
index f9973529a120..ea6e7d7d0bf6 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecord.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecord.java
@@ -23,7 +23,6 @@ import android.content.Intent;
import android.content.pm.ParceledListSlice;
import android.media.AudioAttributes;
import android.media.AudioManager;
-import android.media.AudioSystem;
import android.media.MediaMetadata;
import android.media.Rating;
import android.media.VolumeProvider;
@@ -513,7 +512,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR
public void run() {
try {
if (useSuggested) {
- if (AudioSystem.isStreamActive(stream, 0)) {
+ if (MediaServerUtils.isStreamActive(mAudioManager, stream)) {
mAudioManager.adjustSuggestedStreamVolumeForUid(stream,
direction, flags, opPackageName, uid, pid,
mContext.getApplicationInfo().targetSdkVersion);
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index c23bfc442bd9..11dbef21b34f 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -43,7 +43,6 @@ import android.content.pm.ParceledListSlice;
import android.content.pm.UserInfo;
import android.media.AudioManager;
import android.media.AudioPlaybackConfiguration;
-import android.media.AudioSystem;
import android.media.IRemoteVolumeControllerCallback;
import android.media.Session2Token;
import android.media.session.IActiveSessionsListener;
@@ -94,7 +93,6 @@ import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
-import java.util.Map;
/**
* System implementation of MediaSessionManager
@@ -149,7 +147,6 @@ public class MediaSessionService extends SystemService implements Monitor {
private SessionPolicyProvider mCustomSessionPolicyProvider;
private MediaKeyDispatcher mCustomMediaKeyDispatcher;
- private Map<Integer, Integer> mOverriddenKeyEventsMap;
public MediaSessionService(Context context) {
super(context);
@@ -780,7 +777,6 @@ public class MediaSessionService extends SystemService implements Monitor {
private void instantiateCustomDispatcher(String nameFromTesting) {
synchronized (mLock) {
mCustomMediaKeyDispatcher = null;
- mOverriddenKeyEventsMap = null;
String customDispatcherClassName = (nameFromTesting == null)
? mContext.getResources().getString(R.string.config_customMediaKeyDispatcher)
@@ -788,9 +784,10 @@ public class MediaSessionService extends SystemService implements Monitor {
try {
if (!TextUtils.isEmpty(customDispatcherClassName)) {
Class customDispatcherClass = Class.forName(customDispatcherClassName);
- Constructor constructor = customDispatcherClass.getDeclaredConstructor();
- mCustomMediaKeyDispatcher = (MediaKeyDispatcher) constructor.newInstance();
- mOverriddenKeyEventsMap = mCustomMediaKeyDispatcher.getOverriddenKeyEvents();
+ Constructor constructor =
+ customDispatcherClass.getDeclaredConstructor(Context.class);
+ mCustomMediaKeyDispatcher =
+ (MediaKeyDispatcher) constructor.newInstance(mContext);
}
} catch (ClassNotFoundException | InstantiationException | InvocationTargetException
| IllegalAccessException | NoSuchMethodException e) {
@@ -810,9 +807,10 @@ public class MediaSessionService extends SystemService implements Monitor {
try {
if (!TextUtils.isEmpty(customProviderClassName)) {
Class customProviderClass = Class.forName(customProviderClassName);
- Constructor constructor = customProviderClass.getDeclaredConstructor();
+ Constructor constructor =
+ customProviderClass.getDeclaredConstructor(Context.class);
mCustomSessionPolicyProvider =
- (SessionPolicyProvider) constructor.newInstance();
+ (SessionPolicyProvider) constructor.newInstance(mContext);
}
} catch (ClassNotFoundException | InstantiationException | InvocationTargetException
| IllegalAccessException | NoSuchMethodException e) {
@@ -2019,7 +2017,7 @@ public class MediaSessionService extends SystemService implements Monitor {
boolean preferSuggestedStream = false;
if (isValidLocalStreamType(suggestedStream)
- && AudioSystem.isStreamActive(suggestedStream, 0)) {
+ && MediaServerUtils.isStreamActive(mAudioManager, suggestedStream)) {
preferSuggestedStream = true;
}
if (session == null || preferSuggestedStream) {
@@ -2028,7 +2026,8 @@ public class MediaSessionService extends SystemService implements Monitor {
+ ". flags=" + flags + ", preferSuggestedStream="
+ preferSuggestedStream + ", session=" + session);
}
- if (musicOnly && !AudioSystem.isStreamActive(AudioManager.STREAM_MUSIC, 0)) {
+ if (musicOnly && !MediaServerUtils.isStreamActive(mAudioManager,
+ AudioManager.STREAM_MUSIC)) {
if (DEBUG_KEY_EVENT) {
Log.d(TAG, "Nothing is playing on the music stream. Skipping volume event,"
+ " flags=" + flags);
@@ -2382,9 +2381,12 @@ public class MediaSessionService extends SystemService implements Monitor {
return;
}
- int overriddenKeyEvents = (mCustomMediaKeyDispatcher == null) ? 0
- : mCustomMediaKeyDispatcher.getOverriddenKeyEvents()
- .get(keyEvent.getKeyCode());
+ int overriddenKeyEvents = 0;
+ if (mCustomMediaKeyDispatcher != null
+ && mCustomMediaKeyDispatcher.getOverriddenKeyEvents() != null) {
+ overriddenKeyEvents = mCustomMediaKeyDispatcher.getOverriddenKeyEvents()
+ .get(keyEvent.getKeyCode());
+ }
cancelTrackingIfNeeded(packageName, pid, uid, asSystemService, keyEvent,
needWakeLock, opPackageName, stream, musicOnly, overriddenKeyEvents);
if (!needTracking(keyEvent, overriddenKeyEvents)) {
diff --git a/services/core/java/com/android/server/media/SessionPolicyProvider.java b/services/core/java/com/android/server/media/SessionPolicyProvider.java
index 5f02a075344e..332c85adec01 100644
--- a/services/core/java/com/android/server/media/SessionPolicyProvider.java
+++ b/services/core/java/com/android/server/media/SessionPolicyProvider.java
@@ -18,6 +18,7 @@ package com.android.server.media;
import android.annotation.IntDef;
import android.annotation.NonNull;
+import android.content.Context;
import android.media.session.MediaSession;
import java.lang.annotation.Retention;
@@ -54,7 +55,7 @@ public abstract class SessionPolicyProvider {
*/
static final int SESSION_POLICY_IGNORE_BUTTON_SESSION = 1 << 1;
- public SessionPolicyProvider() {
+ public SessionPolicyProvider(Context context) {
// Constructor used for reflection
}
diff --git a/services/core/java/com/android/server/media/metrics/PlaybackMetricsManagerService.java b/services/core/java/com/android/server/media/metrics/PlaybackMetricsManagerService.java
index adb98695161a..9c68349af7d5 100644
--- a/services/core/java/com/android/server/media/metrics/PlaybackMetricsManagerService.java
+++ b/services/core/java/com/android/server/media/metrics/PlaybackMetricsManagerService.java
@@ -19,13 +19,17 @@ package com.android.server.media.metrics;
import android.content.Context;
import android.media.metrics.IPlaybackMetricsManager;
import android.media.metrics.PlaybackMetrics;
+import android.util.Base64;
import com.android.server.SystemService;
+import java.security.SecureRandom;
+
/**
* System service manages playback metrics.
*/
public final class PlaybackMetricsManagerService extends SystemService {
+ private final SecureRandom mSecureRandom;
/**
* Initializes the playback metrics manager service.
@@ -34,6 +38,7 @@ public final class PlaybackMetricsManagerService extends SystemService {
*/
public PlaybackMetricsManagerService(Context context) {
super(context);
+ mSecureRandom = new SecureRandom();
}
@Override
@@ -44,8 +49,16 @@ public final class PlaybackMetricsManagerService extends SystemService {
private final class BinderService extends IPlaybackMetricsManager.Stub {
@Override
- public void reportPlaybackMetrics(PlaybackMetrics metrics, int userId) {
+ public void reportPlaybackMetrics(String sessionId, PlaybackMetrics metrics, int userId) {
// TODO: log it to statsd
}
+
+ @Override
+ public String getSessionId(int userId) {
+ byte[] byteId = new byte[16]; // 128 bits
+ mSecureRandom.nextBytes(byteId);
+ String id = Base64.encodeToString(byteId, Base64.DEFAULT);
+ return id;
+ }
}
}
diff --git a/services/core/java/com/android/server/notification/ConditionProviders.java b/services/core/java/com/android/server/notification/ConditionProviders.java
index bdf0fb9cee59..8200ca0523be 100644
--- a/services/core/java/com/android/server/notification/ConditionProviders.java
+++ b/services/core/java/com/android/server/notification/ConditionProviders.java
@@ -34,6 +34,7 @@ import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Slog;
+import android.util.TypedXmlSerializer;
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
@@ -110,7 +111,7 @@ public class ConditionProviders extends ManagedServices {
}
@Override
- void writeDefaults(XmlSerializer out) throws IOException {
+ void writeDefaults(TypedXmlSerializer out) throws IOException {
synchronized (mDefaultsLock) {
String defaults = String.join(ENABLED_SERVICES_SEPARATOR, mDefaultPackages);
out.attribute(null, ATT_DEFAULTS, defaults);
diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java
index f2e3708051c4..a7ee27286a24 100644
--- a/services/core/java/com/android/server/notification/ManagedServices.java
+++ b/services/core/java/com/android/server/notification/ManagedServices.java
@@ -60,6 +60,8 @@ import android.util.Log;
import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.GuardedBy;
@@ -443,7 +445,7 @@ abstract public class ManagedServices {
}
}
- void writeDefaults(XmlSerializer out) throws IOException {
+ void writeDefaults(TypedXmlSerializer out) throws IOException {
synchronized (mDefaultsLock) {
List<String> componentStrings = new ArrayList<>(mDefaultComponents.size());
for (int i = 0; i < mDefaultComponents.size(); i++) {
@@ -454,10 +456,10 @@ abstract public class ManagedServices {
}
}
- public void writeXml(XmlSerializer out, boolean forBackup, int userId) throws IOException {
+ public void writeXml(TypedXmlSerializer out, boolean forBackup, int userId) throws IOException {
out.startTag(null, getConfig().xmlTag);
- out.attribute(null, ATT_VERSION, String.valueOf(DB_VERSION));
+ out.attributeInt(null, ATT_VERSION, DB_VERSION);
writeDefaults(out);
@@ -485,8 +487,8 @@ abstract public class ManagedServices {
: String.join(ENABLED_SERVICES_SEPARATOR, approved);
out.startTag(null, TAG_MANAGED_SERVICES);
out.attribute(null, ATT_APPROVED_LIST, allowedItems);
- out.attribute(null, ATT_USER_ID, Integer.toString(approvedUserId));
- out.attribute(null, ATT_IS_PRIMARY, Boolean.toString(isPrimary));
+ out.attributeInt(null, ATT_USER_ID, approvedUserId);
+ out.attributeBoolean(null, ATT_IS_PRIMARY, isPrimary);
if (userSet != null) {
String userSetItems =
String.join(ENABLED_SERVICES_SEPARATOR, userSet);
@@ -516,23 +518,23 @@ abstract public class ManagedServices {
/**
* Writes extra xml attributes to {@link #TAG_MANAGED_SERVICES} tag.
*/
- protected void writeExtraAttributes(XmlSerializer out, int userId) throws IOException {}
+ protected void writeExtraAttributes(TypedXmlSerializer out, int userId) throws IOException {}
/**
* Writes extra xml tags within the parent tag specified in {@link Config#xmlTag}.
*/
- protected void writeExtraXmlTags(XmlSerializer out) throws IOException {}
+ protected void writeExtraXmlTags(TypedXmlSerializer out) throws IOException {}
/**
* This is called to process tags other than {@link #TAG_MANAGED_SERVICES}.
*/
- protected void readExtraTag(String tag, XmlPullParser parser) throws IOException {}
+ protected void readExtraTag(String tag, TypedXmlPullParser parser) throws IOException {}
protected void migrateToXml() {
loadAllowedComponentsFromSettings();
}
- void readDefaults(XmlPullParser parser) {
+ void readDefaults(TypedXmlPullParser parser) {
String defaultComponents = XmlUtils.readStringAttribute(parser, ATT_DEFAULTS);
if (!TextUtils.isEmpty(defaultComponents)) {
@@ -554,7 +556,7 @@ abstract public class ManagedServices {
}
public void readXml(
- XmlPullParser parser,
+ TypedXmlPullParser parser,
TriPredicate<String, Integer, String> allowedManagedServicePackages,
boolean forRestore,
int userId)
@@ -577,9 +579,9 @@ abstract public class ManagedServices {
final String approved = XmlUtils.readStringAttribute(parser, ATT_APPROVED_LIST);
// Ignore parser's user id for restore.
final int resolvedUserId = forRestore
- ? userId : XmlUtils.readIntAttribute(parser, ATT_USER_ID, 0);
+ ? userId : parser.getAttributeInt(null, ATT_USER_ID, 0);
final boolean isPrimary =
- XmlUtils.readBooleanAttribute(parser, ATT_IS_PRIMARY, true);
+ parser.getAttributeBoolean(null, ATT_IS_PRIMARY, true);
final String userSet = XmlUtils.readStringAttribute(parser, ATT_USER_SET);
readExtraAttributes(tag, parser, resolvedUserId);
if (allowedManagedServicePackages == null || allowedManagedServicePackages.test(
@@ -631,7 +633,7 @@ abstract public class ManagedServices {
/**
* Read extra attributes in the {@link #TAG_MANAGED_SERVICES} tag.
*/
- protected void readExtraAttributes(String tag, XmlPullParser parser, int userId)
+ protected void readExtraAttributes(String tag, TypedXmlPullParser parser, int userId)
throws IOException {}
protected abstract String getRequiredPermission();
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index b1289dd0e39f..ee860e3ac6d7 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -230,6 +230,8 @@ import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
import android.util.StatsEvent;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
import android.util.Xml;
import android.util.proto.ProtoOutputStream;
import android.view.accessibility.AccessibilityEvent;
@@ -255,7 +257,6 @@ import com.android.internal.util.ArrayUtils;
import com.android.internal.util.CollectionUtils;
import com.android.internal.util.ConcurrentUtils;
import com.android.internal.util.DumpUtils;
-import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.Preconditions;
import com.android.internal.util.XmlUtils;
import com.android.internal.util.function.TriPredicate;
@@ -284,9 +285,7 @@ import libcore.io.IoUtils;
import org.json.JSONException;
import org.json.JSONObject;
-import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
@@ -735,7 +734,7 @@ public class NotificationManagerService extends SystemService {
null,
MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE, userId);
if (candidate != null && validAssistants.contains(candidate)) {
- setNotificationAssistantAccessGrantedForUserInternal(candidate, userId, true);
+ setNotificationAssistantAccessGrantedForUserInternal(candidate, userId, true, false);
return true;
}
return false;
@@ -743,8 +742,13 @@ public class NotificationManagerService extends SystemService {
void readPolicyXml(InputStream stream, boolean forRestore, int userId)
throws XmlPullParserException, NumberFormatException, IOException {
- final XmlPullParser parser = Xml.newPullParser();
- parser.setInput(stream, StandardCharsets.UTF_8.name());
+ final TypedXmlPullParser parser;
+ if (forRestore) {
+ parser = Xml.newFastPullParser();
+ parser.setInput(stream, StandardCharsets.UTF_8.name());
+ } else {
+ parser = Xml.resolvePullParser(stream);
+ }
XmlUtils.beginDocument(parser, TAG_NOTIFICATION_POLICY);
boolean migratedManagedServices = false;
boolean ineligibleForManagedServices = forRestore && mUm.isManagedProfile(userId);
@@ -781,9 +785,8 @@ public class NotificationManagerService extends SystemService {
if (forRestore && userId != UserHandle.USER_SYSTEM) {
continue;
}
- mLockScreenAllowSecureNotifications =
- safeBoolean(parser.getAttributeValue(null,
- LOCKSCREEN_ALLOW_SECURE_NOTIFICATIONS_VALUE), true);
+ mLockScreenAllowSecureNotifications = parser.getAttributeBoolean(null,
+ LOCKSCREEN_ALLOW_SECURE_NOTIFICATIONS_VALUE, true);
}
}
@@ -856,11 +859,16 @@ public class NotificationManagerService extends SystemService {
private void writePolicyXml(OutputStream stream, boolean forBackup, int userId)
throws IOException {
- final XmlSerializer out = new FastXmlSerializer();
- out.setOutput(stream, StandardCharsets.UTF_8.name());
+ final TypedXmlSerializer out;
+ if (forBackup) {
+ out = Xml.newFastSerializer();
+ out.setOutput(stream, StandardCharsets.UTF_8.name());
+ } else {
+ out = Xml.resolveSerializer(stream);
+ }
out.startDocument(null, true);
out.startTag(null, TAG_NOTIFICATION_POLICY);
- out.attribute(null, ATTR_VERSION, Integer.toString(DB_VERSION));
+ out.attributeInt(null, ATTR_VERSION, DB_VERSION);
mZenModeHelper.writeXml(out, forBackup, null, userId);
mPreferencesHelper.writeXml(out, forBackup, userId);
mListeners.writeXml(out, forBackup, userId);
@@ -4902,7 +4910,8 @@ public class NotificationManagerService extends SystemService {
}
final long identity = Binder.clearCallingIdentity();
try {
- setNotificationAssistantAccessGrantedForUserInternal(assistant, userId, granted);
+ setNotificationAssistantAccessGrantedForUserInternal(assistant, userId, granted,
+ true);
} finally {
Binder.restoreCallingIdentity(identity);
}
@@ -5153,7 +5162,7 @@ public class NotificationManagerService extends SystemService {
@VisibleForTesting
protected void setNotificationAssistantAccessGrantedForUserInternal(
- ComponentName assistant, int baseUserId, boolean granted) {
+ ComponentName assistant, int baseUserId, boolean granted, boolean userSet) {
List<UserInfo> users = mUm.getEnabledProfiles(baseUserId);
if (users != null) {
for (UserInfo user : users) {
@@ -5163,7 +5172,7 @@ public class NotificationManagerService extends SystemService {
mAssistants.getAllowedComponents(userId));
if (allowedAssistant != null) {
setNotificationAssistantAccessGrantedForUserInternal(
- allowedAssistant, userId, false);
+ allowedAssistant, userId, false, userSet);
}
continue;
}
@@ -5172,7 +5181,7 @@ public class NotificationManagerService extends SystemService {
mConditionProviders.setPackageOrComponentEnabled(assistant.flattenToString(),
userId, false, granted);
mAssistants.setPackageOrComponentEnabled(assistant.flattenToString(),
- userId, true, granted);
+ userId, true, granted, userSet);
getContext().sendBroadcastAsUser(
new Intent(ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED)
@@ -8975,7 +8984,7 @@ public class NotificationManagerService extends SystemService {
}
@Override
- protected void writeExtraXmlTags(XmlSerializer out) throws IOException {
+ protected void writeExtraXmlTags(TypedXmlSerializer out) throws IOException {
synchronized (mLock) {
out.startTag(null, TAG_ALLOWED_ADJUSTMENT_TYPES);
out.attribute(null, ATT_TYPES, TextUtils.join(",", mAllowedAdjustments));
@@ -8984,7 +8993,7 @@ public class NotificationManagerService extends SystemService {
}
@Override
- protected void readExtraTag(String tag, XmlPullParser parser) throws IOException {
+ protected void readExtraTag(String tag, TypedXmlPullParser parser) throws IOException {
if (TAG_ALLOWED_ADJUSTMENT_TYPES.equals(tag)) {
final String types = XmlUtils.readStringAttribute(parser, ATT_TYPES);
synchronized (mLock) {
@@ -9104,9 +9113,9 @@ public class NotificationManagerService extends SystemService {
}
@Override
- protected void readExtraAttributes(String tag, XmlPullParser parser, int userId)
+ protected void readExtraAttributes(String tag, TypedXmlPullParser parser, int userId)
throws IOException {
- boolean userSet = XmlUtils.readBooleanAttribute(parser, ATT_USER_SET, false);
+ boolean userSet = parser.getAttributeBoolean(null, ATT_USER_SET, false);
setUserSet(userId, userSet);
}
@@ -9327,7 +9336,7 @@ public class NotificationManagerService extends SystemService {
@Override
protected void setPackageOrComponentEnabled(String pkgOrComponent, int userId,
- boolean isPrimary, boolean enabled) {
+ boolean isPrimary, boolean enabled, boolean userSet) {
// Ensures that only one component is enabled at a time
if (enabled) {
List<ComponentName> allowedComponents = getAllowedComponents(userId);
@@ -9335,10 +9344,10 @@ public class NotificationManagerService extends SystemService {
ComponentName currentComponent = CollectionUtils.firstOrNull(allowedComponents);
if (currentComponent.flattenToString().equals(pkgOrComponent)) return;
setNotificationAssistantAccessGrantedForUserInternal(
- currentComponent, userId, false);
+ currentComponent, userId, false, userSet);
}
}
- super.setPackageOrComponentEnabled(pkgOrComponent, userId, isPrimary, enabled);
+ super.setPackageOrComponentEnabled(pkgOrComponent, userId, isPrimary, enabled, userSet);
}
private boolean isVerboseLogEnabled() {
@@ -10106,18 +10115,13 @@ public class NotificationManagerService extends SystemService {
}
}
- private void writeSecureNotificationsPolicy(XmlSerializer out) throws IOException {
+ private void writeSecureNotificationsPolicy(TypedXmlSerializer out) throws IOException {
out.startTag(null, LOCKSCREEN_ALLOW_SECURE_NOTIFICATIONS_TAG);
- out.attribute(null, LOCKSCREEN_ALLOW_SECURE_NOTIFICATIONS_VALUE,
- Boolean.toString(mLockScreenAllowSecureNotifications));
+ out.attributeBoolean(null, LOCKSCREEN_ALLOW_SECURE_NOTIFICATIONS_VALUE,
+ mLockScreenAllowSecureNotifications);
out.endTag(null, LOCKSCREEN_ALLOW_SECURE_NOTIFICATIONS_TAG);
}
- private static boolean safeBoolean(String val, boolean defValue) {
- if (TextUtils.isEmpty(val)) return defValue;
- return Boolean.parseBoolean(val);
- }
-
/**
* Shows a warning on logcat. Shows the toast only once per package. This is to avoid being too
* aggressive and annoying the user.
diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java
index 2f990c62305f..1c0349d1b51f 100644
--- a/services/core/java/com/android/server/notification/PreferencesHelper.java
+++ b/services/core/java/com/android/server/notification/PreferencesHelper.java
@@ -56,6 +56,8 @@ import android.util.Pair;
import android.util.Slog;
import android.util.SparseBooleanArray;
import android.util.StatsEvent;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
import android.util.proto.ProtoOutputStream;
import com.android.internal.R;
@@ -195,21 +197,15 @@ public class PreferencesHelper implements RankingConfig {
syncChannelsBypassingDnd(mContext.getUserId());
}
- public void readXml(XmlPullParser parser, boolean forRestore, int userId)
+ public void readXml(TypedXmlPullParser parser, boolean forRestore, int userId)
throws XmlPullParserException, IOException {
int type = parser.getEventType();
if (type != XmlPullParser.START_TAG) return;
String tag = parser.getName();
if (!TAG_RANKING.equals(tag)) return;
- boolean upgradeForBubbles = false;
- if (parser.getAttributeCount() > 0) {
- String attribute = parser.getAttributeName(0);
- if (ATT_VERSION.equals(attribute)) {
- int xmlVersion = Integer.parseInt(parser.getAttributeValue(0));
- upgradeForBubbles = xmlVersion == XML_VERSION_BUBBLES_UPGRADE;
- }
- }
+ final int xmlVersion = parser.getAttributeInt(null, ATT_VERSION, -1);
+ boolean upgradeForBubbles = xmlVersion == XML_VERSION_BUBBLES_UPGRADE;
synchronized (mPackagePreferences) {
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
tag = parser.getName();
@@ -221,10 +217,10 @@ public class PreferencesHelper implements RankingConfig {
if (forRestore && userId != UserHandle.USER_SYSTEM) {
continue;
}
- mHideSilentStatusBarIcons = XmlUtils.readBooleanAttribute(
- parser, ATT_HIDE_SILENT, DEFAULT_HIDE_SILENT_STATUS_BAR_ICONS);
+ mHideSilentStatusBarIcons = parser.getAttributeBoolean(null,
+ ATT_HIDE_SILENT, DEFAULT_HIDE_SILENT_STATUS_BAR_ICONS);
} else if (TAG_PACKAGE.equals(tag)) {
- int uid = XmlUtils.readIntAttribute(parser, ATT_UID, UNKNOWN_UID);
+ int uid = parser.getAttributeInt(null, ATT_UID, UNKNOWN_UID);
String name = parser.getAttributeValue(null, ATT_NAME);
if (!TextUtils.isEmpty(name)) {
if (forRestore) {
@@ -243,36 +239,36 @@ public class PreferencesHelper implements RankingConfig {
}
int bubblePref = hasSAWPermission
? BUBBLE_PREFERENCE_ALL
- : XmlUtils.readIntAttribute(parser, ATT_ALLOW_BUBBLE,
- DEFAULT_BUBBLE_PREFERENCE);
+ : parser.getAttributeInt(
+ null, ATT_ALLOW_BUBBLE, DEFAULT_BUBBLE_PREFERENCE);
PackagePreferences r = getOrCreatePackagePreferencesLocked(
name, userId, uid,
- XmlUtils.readIntAttribute(
- parser, ATT_IMPORTANCE, DEFAULT_IMPORTANCE),
- XmlUtils.readIntAttribute(parser, ATT_PRIORITY,
- DEFAULT_PRIORITY),
- XmlUtils.readIntAttribute(
- parser, ATT_VISIBILITY, DEFAULT_VISIBILITY),
- XmlUtils.readBooleanAttribute(
- parser, ATT_SHOW_BADGE, DEFAULT_SHOW_BADGE),
+ parser.getAttributeInt(
+ null, ATT_IMPORTANCE, DEFAULT_IMPORTANCE),
+ parser.getAttributeInt(
+ null, ATT_PRIORITY, DEFAULT_PRIORITY),
+ parser.getAttributeInt(
+ null, ATT_VISIBILITY, DEFAULT_VISIBILITY),
+ parser.getAttributeBoolean(
+ null, ATT_SHOW_BADGE, DEFAULT_SHOW_BADGE),
bubblePref);
- r.importance = XmlUtils.readIntAttribute(
- parser, ATT_IMPORTANCE, DEFAULT_IMPORTANCE);
- r.priority = XmlUtils.readIntAttribute(
- parser, ATT_PRIORITY, DEFAULT_PRIORITY);
- r.visibility = XmlUtils.readIntAttribute(
- parser, ATT_VISIBILITY, DEFAULT_VISIBILITY);
- r.showBadge = XmlUtils.readBooleanAttribute(
- parser, ATT_SHOW_BADGE, DEFAULT_SHOW_BADGE);
- r.lockedAppFields = XmlUtils.readIntAttribute(parser,
- ATT_APP_USER_LOCKED_FIELDS, DEFAULT_LOCKED_APP_FIELDS);
- r.hasSentInvalidMessage = XmlUtils.readBooleanAttribute(
- parser, ATT_SENT_INVALID_MESSAGE, false);
- r.hasSentValidMessage = XmlUtils.readBooleanAttribute(
- parser, ATT_SENT_VALID_MESSAGE, false);
- r.userDemotedMsgApp = XmlUtils.readBooleanAttribute(
- parser, ATT_USER_DEMOTED_INVALID_MSG_APP, false);
+ r.importance = parser.getAttributeInt(
+ null, ATT_IMPORTANCE, DEFAULT_IMPORTANCE);
+ r.priority = parser.getAttributeInt(
+ null, ATT_PRIORITY, DEFAULT_PRIORITY);
+ r.visibility = parser.getAttributeInt(
+ null, ATT_VISIBILITY, DEFAULT_VISIBILITY);
+ r.showBadge = parser.getAttributeBoolean(
+ null, ATT_SHOW_BADGE, DEFAULT_SHOW_BADGE);
+ r.lockedAppFields = parser.getAttributeInt(
+ null, ATT_APP_USER_LOCKED_FIELDS, DEFAULT_LOCKED_APP_FIELDS);
+ r.hasSentInvalidMessage = parser.getAttributeBoolean(
+ null, ATT_SENT_INVALID_MESSAGE, false);
+ r.hasSentValidMessage = parser.getAttributeBoolean(
+ null, ATT_SENT_VALID_MESSAGE, false);
+ r.userDemotedMsgApp = parser.getAttributeBoolean(
+ null, ATT_USER_DEMOTED_INVALID_MSG_APP, false);
final int innerDepth = parser.getDepth();
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
@@ -307,8 +303,8 @@ public class PreferencesHelper implements RankingConfig {
}
String id = parser.getAttributeValue(null, ATT_ID);
String channelName = parser.getAttributeValue(null, ATT_NAME);
- int channelImportance = XmlUtils.readIntAttribute(
- parser, ATT_IMPORTANCE, DEFAULT_IMPORTANCE);
+ int channelImportance = parser.getAttributeInt(
+ null, ATT_IMPORTANCE, DEFAULT_IMPORTANCE);
if (!TextUtils.isEmpty(id) && !TextUtils.isEmpty(channelName)) {
NotificationChannel channel = new NotificationChannel(id,
channelName, channelImportance);
@@ -338,14 +334,13 @@ public class PreferencesHelper implements RankingConfig {
// Delegate
if (TAG_DELEGATE.equals(tagName)) {
int delegateId =
- XmlUtils.readIntAttribute(parser, ATT_UID, UNKNOWN_UID);
+ parser.getAttributeInt(null, ATT_UID, UNKNOWN_UID);
String delegateName =
XmlUtils.readStringAttribute(parser, ATT_NAME);
- boolean delegateEnabled = XmlUtils.readBooleanAttribute(
- parser, ATT_ENABLED, Delegate.DEFAULT_ENABLED);
- boolean userAllowed = XmlUtils.readBooleanAttribute(
- parser, ATT_USER_ALLOWED,
- Delegate.DEFAULT_USER_ALLOWED);
+ boolean delegateEnabled = parser.getAttributeBoolean(
+ null, ATT_ENABLED, Delegate.DEFAULT_ENABLED);
+ boolean userAllowed = parser.getAttributeBoolean(
+ null, ATT_USER_ALLOWED, Delegate.DEFAULT_USER_ALLOWED);
Delegate d = null;
if (delegateId != UNKNOWN_UID && !TextUtils.isEmpty(
delegateName)) {
@@ -502,13 +497,13 @@ public class PreferencesHelper implements RankingConfig {
return true;
}
- public void writeXml(XmlSerializer out, boolean forBackup, int userId) throws IOException {
+ public void writeXml(TypedXmlSerializer out, boolean forBackup, int userId) throws IOException {
out.startTag(null, TAG_RANKING);
- out.attribute(null, ATT_VERSION, Integer.toString(XML_VERSION));
+ out.attributeInt(null, ATT_VERSION, XML_VERSION);
if (mHideSilentStatusBarIcons != DEFAULT_HIDE_SILENT_STATUS_BAR_ICONS
&& (!forBackup || userId == UserHandle.USER_SYSTEM)) {
out.startTag(null, TAG_STATUS_ICONS);
- out.attribute(null, ATT_HIDE_SILENT, String.valueOf(mHideSilentStatusBarIcons));
+ out.attributeBoolean(null, ATT_HIDE_SILENT, mHideSilentStatusBarIcons);
out.endTag(null, TAG_STATUS_ICONS);
}
@@ -536,42 +531,41 @@ public class PreferencesHelper implements RankingConfig {
out.startTag(null, TAG_PACKAGE);
out.attribute(null, ATT_NAME, r.pkg);
if (r.importance != DEFAULT_IMPORTANCE) {
- out.attribute(null, ATT_IMPORTANCE, Integer.toString(r.importance));
+ out.attributeInt(null, ATT_IMPORTANCE, r.importance);
}
if (r.priority != DEFAULT_PRIORITY) {
- out.attribute(null, ATT_PRIORITY, Integer.toString(r.priority));
+ out.attributeInt(null, ATT_PRIORITY, r.priority);
}
if (r.visibility != DEFAULT_VISIBILITY) {
- out.attribute(null, ATT_VISIBILITY, Integer.toString(r.visibility));
+ out.attributeInt(null, ATT_VISIBILITY, r.visibility);
}
if (r.bubblePreference != DEFAULT_BUBBLE_PREFERENCE) {
- out.attribute(null, ATT_ALLOW_BUBBLE, Integer.toString(r.bubblePreference));
+ out.attributeInt(null, ATT_ALLOW_BUBBLE, r.bubblePreference);
}
- out.attribute(null, ATT_SHOW_BADGE, Boolean.toString(r.showBadge));
- out.attribute(null, ATT_APP_USER_LOCKED_FIELDS,
- Integer.toString(r.lockedAppFields));
- out.attribute(null, ATT_SENT_INVALID_MESSAGE,
- Boolean.toString(r.hasSentInvalidMessage));
- out.attribute(null, ATT_SENT_VALID_MESSAGE,
- Boolean.toString(r.hasSentValidMessage));
- out.attribute(null, ATT_USER_DEMOTED_INVALID_MSG_APP,
- Boolean.toString(r.userDemotedMsgApp));
+ out.attributeBoolean(null, ATT_SHOW_BADGE, r.showBadge);
+ out.attributeInt(null, ATT_APP_USER_LOCKED_FIELDS,
+ r.lockedAppFields);
+ out.attributeBoolean(null, ATT_SENT_INVALID_MESSAGE,
+ r.hasSentInvalidMessage);
+ out.attributeBoolean(null, ATT_SENT_VALID_MESSAGE,
+ r.hasSentValidMessage);
+ out.attributeBoolean(null, ATT_USER_DEMOTED_INVALID_MSG_APP,
+ r.userDemotedMsgApp);
if (!forBackup) {
- out.attribute(null, ATT_UID, Integer.toString(r.uid));
+ out.attributeInt(null, ATT_UID, r.uid);
}
if (r.delegate != null) {
out.startTag(null, TAG_DELEGATE);
out.attribute(null, ATT_NAME, r.delegate.mPkg);
- out.attribute(null, ATT_UID, Integer.toString(r.delegate.mUid));
+ out.attributeInt(null, ATT_UID, r.delegate.mUid);
if (r.delegate.mEnabled != Delegate.DEFAULT_ENABLED) {
- out.attribute(null, ATT_ENABLED, Boolean.toString(r.delegate.mEnabled));
+ out.attributeBoolean(null, ATT_ENABLED, r.delegate.mEnabled);
}
if (r.delegate.mUserAllowed != Delegate.DEFAULT_USER_ALLOWED) {
- out.attribute(null, ATT_USER_ALLOWED,
- Boolean.toString(r.delegate.mUserAllowed));
+ out.attributeBoolean(null, ATT_USER_ALLOWED, r.delegate.mUserAllowed);
}
out.endTag(null, TAG_DELEGATE);
}
diff --git a/services/core/java/com/android/server/notification/SnoozeHelper.java b/services/core/java/com/android/server/notification/SnoozeHelper.java
index f7d69fdc09d2..b5ca2abf8afe 100644
--- a/services/core/java/com/android/server/notification/SnoozeHelper.java
+++ b/services/core/java/com/android/server/notification/SnoozeHelper.java
@@ -32,6 +32,8 @@ import android.util.ArrayMap;
import android.util.IntArray;
import android.util.Log;
import android.util.Slog;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.MetricsLogger;
@@ -57,7 +59,7 @@ import java.util.Set;
* NotificationManagerService helper for handling snoozed notifications.
*/
public class SnoozeHelper {
- public static final String XML_SNOOZED_NOTIFICATION_VERSION = "1";
+ public static final int XML_SNOOZED_NOTIFICATION_VERSION = 1;
protected static final String XML_TAG_NAME = "snoozed-notifications";
@@ -547,7 +549,7 @@ public class SnoozeHelper {
}
}
- protected void writeXml(XmlSerializer out) throws IOException {
+ protected void writeXml(TypedXmlSerializer out) throws IOException {
synchronized (mLock) {
final long currentTime = System.currentTimeMillis();
out.startTag(null, XML_TAG_NAME);
@@ -573,7 +575,7 @@ public class SnoozeHelper {
void insert(T t) throws IOException;
}
- private <T> void writeXml(XmlSerializer out,
+ private <T> void writeXml(TypedXmlSerializer out,
ArrayMap<String, ArrayMap<String, T>> targets, String tag,
Inserter<T> attributeInserter)
throws IOException {
@@ -596,21 +598,18 @@ public class SnoozeHelper {
attributeInserter.insert(value);
- out.attribute(null, XML_SNOOZED_NOTIFICATION_VERSION_LABEL,
+ out.attributeInt(null, XML_SNOOZED_NOTIFICATION_VERSION_LABEL,
XML_SNOOZED_NOTIFICATION_VERSION);
out.attribute(null, XML_SNOOZED_NOTIFICATION_KEY, key);
-
-
out.attribute(null, XML_SNOOZED_NOTIFICATION_PKG, pkg);
- out.attribute(null, XML_SNOOZED_NOTIFICATION_USER_ID,
- String.valueOf(userId));
+ out.attributeInt(null, XML_SNOOZED_NOTIFICATION_USER_ID, userId);
out.endTag(null, tag);
}
}
}
- protected void readXml(XmlPullParser parser, long currentTime)
+ protected void readXml(TypedXmlPullParser parser, long currentTime)
throws XmlPullParserException, IOException {
int type;
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
@@ -622,16 +621,16 @@ public class SnoozeHelper {
if (type == XmlPullParser.START_TAG
&& (XML_SNOOZED_NOTIFICATION.equals(tag)
|| tag.equals(XML_SNOOZED_NOTIFICATION_CONTEXT))
- && parser.getAttributeValue(null, XML_SNOOZED_NOTIFICATION_VERSION_LABEL)
- .equals(XML_SNOOZED_NOTIFICATION_VERSION)) {
+ && parser.getAttributeInt(null, XML_SNOOZED_NOTIFICATION_VERSION_LABEL, -1)
+ == XML_SNOOZED_NOTIFICATION_VERSION) {
try {
final String key = parser.getAttributeValue(null, XML_SNOOZED_NOTIFICATION_KEY);
final String pkg = parser.getAttributeValue(null, XML_SNOOZED_NOTIFICATION_PKG);
- final int userId = XmlUtils.readIntAttribute(
- parser, XML_SNOOZED_NOTIFICATION_USER_ID, UserHandle.USER_ALL);
+ final int userId = parser.getAttributeInt(
+ null, XML_SNOOZED_NOTIFICATION_USER_ID, UserHandle.USER_ALL);
if (tag.equals(XML_SNOOZED_NOTIFICATION)) {
- final Long time = XmlUtils.readLongAttribute(
- parser, XML_SNOOZED_NOTIFICATION_TIME, 0);
+ final Long time = parser.getAttributeLong(
+ null, XML_SNOOZED_NOTIFICATION_TIME, 0);
if (time > currentTime) { //only read new stuff
synchronized (mLock) {
storeRecordLocked(
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index 13cd6e547629..94f46ba6bc60 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -72,6 +72,8 @@ import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
import android.util.StatsEvent;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
import android.util.proto.ProtoOutputStream;
import com.android.internal.R;
@@ -702,7 +704,7 @@ public class ZenModeHelper {
}
}
- public void readXml(XmlPullParser parser, boolean forRestore, int userId)
+ public void readXml(TypedXmlPullParser parser, boolean forRestore, int userId)
throws XmlPullParserException, IOException {
ZenModeConfig config = ZenModeConfig.readXml(parser);
String reason = "readXml";
@@ -761,7 +763,7 @@ public class ZenModeHelper {
}
}
- public void writeXml(XmlSerializer out, boolean forBackup, Integer version, int userId)
+ public void writeXml(TypedXmlSerializer out, boolean forBackup, Integer version, int userId)
throws IOException {
synchronized (mConfigs) {
final int n = mConfigs.size();
diff --git a/services/core/java/com/android/server/om/OverlayManagerSettings.java b/services/core/java/com/android/server/om/OverlayManagerSettings.java
index 8a2d823cf7e9..0613dff31da5 100644
--- a/services/core/java/com/android/server/om/OverlayManagerSettings.java
+++ b/services/core/java/com/android/server/om/OverlayManagerSettings.java
@@ -411,7 +411,7 @@ final class OverlayManagerSettings {
table.clear();
final TypedXmlPullParser parser = Xml.resolvePullParser(is);
XmlUtils.beginDocument(parser, TAG_OVERLAYS);
- int version = XmlUtils.readIntAttribute(parser, ATTR_VERSION);
+ int version = parser.getAttributeInt(null, ATTR_VERSION);
if (version != CURRENT_VERSION) {
upgrade(version);
}
@@ -445,19 +445,19 @@ final class OverlayManagerSettings {
}
}
- private static SettingsItem restoreRow(@NonNull final XmlPullParser parser, final int depth)
- throws IOException {
+ private static SettingsItem restoreRow(@NonNull final TypedXmlPullParser parser,
+ final int depth) throws IOException, XmlPullParserException {
final String packageName = XmlUtils.readStringAttribute(parser, ATTR_PACKAGE_NAME);
- final int userId = XmlUtils.readIntAttribute(parser, ATTR_USER_ID);
+ final int userId = parser.getAttributeInt(null, ATTR_USER_ID);
final String targetPackageName = XmlUtils.readStringAttribute(parser,
ATTR_TARGET_PACKAGE_NAME);
final String targetOverlayableName = XmlUtils.readStringAttribute(parser,
ATTR_TARGET_OVERLAYABLE_NAME);
final String baseCodePath = XmlUtils.readStringAttribute(parser, ATTR_BASE_CODE_PATH);
- final int state = XmlUtils.readIntAttribute(parser, ATTR_STATE);
- final boolean isEnabled = XmlUtils.readBooleanAttribute(parser, ATTR_IS_ENABLED);
- final boolean isStatic = XmlUtils.readBooleanAttribute(parser, ATTR_IS_STATIC);
- final int priority = XmlUtils.readIntAttribute(parser, ATTR_PRIORITY);
+ final int state = parser.getAttributeInt(null, ATTR_STATE);
+ final boolean isEnabled = parser.getAttributeBoolean(null, ATTR_IS_ENABLED, false);
+ final boolean isStatic = parser.getAttributeBoolean(null, ATTR_IS_STATIC, false);
+ final int priority = parser.getAttributeInt(null, ATTR_PRIORITY);
final String category = XmlUtils.readStringAttribute(parser, ATTR_CATEGORY);
return new SettingsItem(packageName, userId, targetPackageName, targetOverlayableName,
@@ -470,7 +470,7 @@ final class OverlayManagerSettings {
xml.startDocument(null, true);
xml.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
xml.startTag(null, TAG_OVERLAYS);
- XmlUtils.writeIntAttribute(xml, ATTR_VERSION, CURRENT_VERSION);
+ xml.attributeInt(null, ATTR_VERSION, CURRENT_VERSION);
final int n = table.size();
for (int i = 0; i < n; i++) {
@@ -485,15 +485,15 @@ final class OverlayManagerSettings {
@NonNull final SettingsItem item) throws IOException {
xml.startTag(null, TAG_ITEM);
XmlUtils.writeStringAttribute(xml, ATTR_PACKAGE_NAME, item.mPackageName);
- XmlUtils.writeIntAttribute(xml, ATTR_USER_ID, item.mUserId);
+ xml.attributeInt(null, ATTR_USER_ID, item.mUserId);
XmlUtils.writeStringAttribute(xml, ATTR_TARGET_PACKAGE_NAME, item.mTargetPackageName);
XmlUtils.writeStringAttribute(xml, ATTR_TARGET_OVERLAYABLE_NAME,
item.mTargetOverlayableName);
XmlUtils.writeStringAttribute(xml, ATTR_BASE_CODE_PATH, item.mBaseCodePath);
- XmlUtils.writeIntAttribute(xml, ATTR_STATE, item.mState);
+ xml.attributeInt(null, ATTR_STATE, item.mState);
XmlUtils.writeBooleanAttribute(xml, ATTR_IS_ENABLED, item.mIsEnabled);
XmlUtils.writeBooleanAttribute(xml, ATTR_IS_STATIC, !item.mIsMutable);
- XmlUtils.writeIntAttribute(xml, ATTR_PRIORITY, item.mPriority);
+ xml.attributeInt(null, ATTR_PRIORITY, item.mPriority);
XmlUtils.writeStringAttribute(xml, ATTR_CATEGORY, item.mCategory);
xml.endTag(null, TAG_ITEM);
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index db5eb844f1b4..85659edd1321 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -21,7 +21,6 @@ import static android.Manifest.permission.MANAGE_DEVICE_ADMINS;
import static android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS;
import static android.Manifest.permission.REQUEST_DELETE_PACKAGES;
import static android.Manifest.permission.SET_HARMFUL_APP_WARNINGS;
-import static android.app.AppOpsManager.MODE_ALLOWED;
import static android.app.AppOpsManager.MODE_DEFAULT;
import static android.app.AppOpsManager.MODE_IGNORED;
import static android.content.Intent.ACTION_MAIN;
@@ -44,7 +43,6 @@ import static android.content.pm.PackageManager.FLAG_PERMISSION_REVOKED_COMPAT;
import static android.content.pm.PackageManager.FLAG_PERMISSION_SYSTEM_FIXED;
import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_FIXED;
import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_SET;
-import static android.content.pm.PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER;
import static android.content.pm.PackageManager.INSTALL_FAILED_ALREADY_EXISTS;
import static android.content.pm.PackageManager.INSTALL_FAILED_BAD_PERMISSION_GROUP;
import static android.content.pm.PackageManager.INSTALL_FAILED_DUPLICATE_PACKAGE;
@@ -343,7 +341,6 @@ import com.android.internal.content.PackageHelper;
import com.android.internal.content.om.OverlayConfig;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.os.SomeArgs;
-import com.android.internal.os.Zygote;
import com.android.internal.telephony.CarrierAppUtils;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.ConcurrentUtils;
@@ -1744,6 +1741,14 @@ public class PackageManagerService extends IPackageManager.Stub
private final PackageUsage mPackageUsage = new PackageUsage();
private final CompilerStats mCompilerStats = new CompilerStats();
+ /**
+ * Invalidate the package info cache, which includes updating the cached computer.
+ * @hide
+ */
+ public static void invalidatePackageInfoCache() {
+ PackageManager.invalidatePackageInfoCache();
+ }
+
class PackageHandler extends Handler {
PackageHandler(Looper looper) {
@@ -2172,7 +2177,7 @@ public class PackageManagerService extends IPackageManager.Stub
private void handlePackagePostInstall(PackageInstalledInfo res, boolean grantPermissions,
boolean killApp, boolean virtualPreload,
- String[] grantedPermissions, List<String> whitelistedRestrictedPermissions,
+ String[] grantedPermissions, List<String> allowlistedRestrictedPermissions,
int autoRevokePermissionsMode,
boolean launchedForRestore, String installerPackage,
IPackageInstallObserver2 installObserver, int dataLoaderType) {
@@ -2205,31 +2210,22 @@ public class PackageManagerService extends IPackageManager.Stub
res.removedInfo.sendPackageRemovedBroadcasts(killApp, false /*removedBySystem*/);
}
- // Allowlist any restricted permissions first as some may be runtime
- // that the installer requested to be granted at install time.
- if (whitelistedRestrictedPermissions != null
- && !whitelistedRestrictedPermissions.isEmpty()) {
- mPermissionManager.setAllowlistedRestrictedPermissions(res.pkg,
- whitelistedRestrictedPermissions, FLAG_PERMISSION_WHITELIST_INSTALLER,
- res.newUsers);
+ final List<String> grantedPermissionsList;
+ if (grantPermissions) {
+ if (grantedPermissions != null) {
+ grantedPermissionsList = Arrays.asList(grantedPermissions);
+ } else {
+ grantedPermissionsList = res.pkg.getRequestedPermissions();
+ }
+ } else {
+ grantedPermissionsList = Collections.emptyList();
}
-
- if (autoRevokePermissionsMode == MODE_ALLOWED
- || autoRevokePermissionsMode == MODE_IGNORED) {
- mPermissionManager.setAutoRevokeExempted(res.pkg,
- autoRevokePermissionsMode == MODE_IGNORED, res.newUsers);
+ if (allowlistedRestrictedPermissions == null) {
+ allowlistedRestrictedPermissions = Collections.emptyList();
}
-
- // Now that we successfully installed the package, grant runtime
- // permissions if requested before broadcasting the install. Also
- // for legacy apps in permission review mode we clear the permission
- // review flag which is used to emulate runtime permissions for
- // legacy apps.
- if (grantPermissions) {
- final int callingUid = Binder.getCallingUid();
- mPermissionManager.grantRequestedRuntimePermissions(res.pkg,
- grantedPermissions != null ? Arrays.asList(grantedPermissions) : null,
- res.newUsers);
+ for (final int userId : res.newUsers) {
+ mPermissionManager.onPackageInstalled(res.pkg, grantedPermissionsList,
+ allowlistedRestrictedPermissions, autoRevokePermissionsMode, userId);
}
final String installerPackageName =
@@ -2695,14 +2691,14 @@ public class PackageManagerService extends IPackageManager.Stub
// We normally invalidate when we write settings, but in cases where we delay and
// coalesce settings writes, this strategy would have us invalidate the cache too late.
// Invalidating on schedule addresses this problem.
- PackageManager.invalidatePackageInfoCache();
+ invalidatePackageInfoCache();
if (!mHandler.hasMessages(WRITE_SETTINGS)) {
mHandler.sendEmptyMessageDelayed(WRITE_SETTINGS, WRITE_SETTINGS_DELAY);
}
}
void scheduleWritePackageListLocked(int userId) {
- PackageManager.invalidatePackageInfoCache();
+ invalidatePackageInfoCache();
if (!mHandler.hasMessages(WRITE_PACKAGE_LIST)) {
Message msg = mHandler.obtainMessage(WRITE_PACKAGE_LIST);
msg.arg1 = userId;
@@ -2716,7 +2712,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
void scheduleWritePackageRestrictionsLocked(int userId) {
- PackageManager.invalidatePackageInfoCache();
+ invalidatePackageInfoCache();
final int[] userIds = (userId == UserHandle.USER_ALL)
? mUserManager.getUserIds() : new int[]{userId};
for (int nextUserId : userIds) {
@@ -4105,10 +4101,7 @@ public class PackageManagerService extends IPackageManager.Stub
// feature flags should cause us to invalidate any caches.
final String cacheName = FORCE_PACKAGE_PARSED_CACHE_ENABLED ? "debug"
: injector.getSystemWrapper().digestOfProperties(
- "ro.build.fingerprint",
- StorageManager.PROP_ISOLATED_STORAGE,
- StorageManager.PROP_ISOLATED_STORAGE_SNAPSHOT
- );
+ "ro.build.fingerprint");
// Reconcile cache directories, keeping only what we'd actually use.
for (File cacheDir : FileUtils.listFilesOrEmpty(cacheBaseDir)) {
@@ -6954,8 +6947,7 @@ public class PackageManagerService extends IPackageManager.Stub
private boolean isPersistentPreferredActivitySetByDpm(Intent intent, int userId,
String resolvedType, int flags) {
- PersistentPreferredIntentResolver ppir = mSettings.mPersistentPreferredActivities
- .get(userId);
+ PersistentPreferredIntentResolver ppir = mSettings.getPersistentPreferredActivities(userId);
//TODO(b/158003772): Remove double query
List<PersistentPreferredActivity> pprefs = ppir != null
? ppir.queryIntent(intent, resolvedType,
@@ -6974,8 +6966,7 @@ public class PackageManagerService extends IPackageManager.Stub
private ResolveInfo findPersistentPreferredActivityLP(Intent intent, String resolvedType,
int flags, List<ResolveInfo> query, boolean debug, int userId) {
final int N = query.size();
- PersistentPreferredIntentResolver ppir = mSettings.mPersistentPreferredActivities
- .get(userId);
+ PersistentPreferredIntentResolver ppir = mSettings.getPersistentPreferredActivities(userId);
// Get the list of persistent preferred activities that handle the intent
if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Looking for presistent preferred activities...");
List<PersistentPreferredActivity> pprefs = ppir != null
@@ -7075,7 +7066,7 @@ public class PackageManagerService extends IPackageManager.Stub
return pri;
}
- PreferredIntentResolver pir = mSettings.mPreferredActivities.get(userId);
+ PreferredIntentResolver pir = mSettings.getPreferredActivities(userId);
// Get the list of preferred activities that handle the intent
if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Looking for preferred activities...");
List<PreferredActivity> prefs = pir != null
@@ -7302,7 +7293,7 @@ public class PackageManagerService extends IPackageManager.Stub
private List<CrossProfileIntentFilter> getMatchingCrossProfileIntentFilters(Intent intent,
String resolvedType, int userId) {
- CrossProfileIntentResolver resolver = mSettings.mCrossProfileIntentResolvers.get(userId);
+ CrossProfileIntentResolver resolver = mSettings.getCrossProfileIntentResolvers(userId);
if (resolver != null) {
return resolver.queryIntent(intent, resolvedType, false /*defaultOnly*/, userId);
}
@@ -9904,7 +9895,7 @@ public class PackageManagerService extends IPackageManager.Stub
android.Manifest.permission.INTERACT_ACROSS_PROFILES,
PermissionChecker.PID_UNKNOWN,
callingUid,
- mPmInternal.getPackage(callingUid).getPackageName())
+ getPackage(callingUid).getPackageName())
== PermissionChecker.PERMISSION_GRANTED) {
return;
}
@@ -13611,11 +13602,12 @@ public class PackageManagerService extends IPackageManager.Stub
int installExistingPackageAsUser(@Nullable String packageName, @UserIdInt int userId,
@PackageManager.InstallFlags int installFlags,
@PackageManager.InstallReason int installReason,
- @Nullable List<String> whiteListedPermissions, @Nullable IntentSender intentSender) {
+ @Nullable List<String> allowlistedRestrictedPermissions,
+ @Nullable IntentSender intentSender) {
if (DEBUG_INSTALL) {
Log.v(TAG, "installExistingPackageAsUser package=" + packageName + " userId=" + userId
+ " installFlags=" + installFlags + " installReason=" + installReason
- + " whiteListedPermissions=" + whiteListedPermissions);
+ + " allowlistedRestrictedPermissions=" + allowlistedRestrictedPermissions);
}
final int callingUid = Binder.getCallingUid();
@@ -13681,11 +13673,12 @@ public class PackageManagerService extends IPackageManager.Stub
if (pkgSetting.pkg != null) {
if ((installFlags & PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS)
!= 0) {
- whiteListedPermissions = pkgSetting.pkg.getRequestedPermissions();
+ allowlistedRestrictedPermissions = pkgSetting.pkg.getRequestedPermissions();
+ } else if (allowlistedRestrictedPermissions == null) {
+ allowlistedRestrictedPermissions = Collections.emptyList();
}
- mPermissionManager.setAllowlistedRestrictedPermissions(pkgSetting.pkg,
- whiteListedPermissions, FLAG_PERMISSION_WHITELIST_INSTALLER,
- new int[] { userId });
+ mPermissionManager.onPackageInstalled(pkgSetting.pkg, Collections.emptyList(),
+ allowlistedRestrictedPermissions, MODE_DEFAULT, userId);
}
if (pkgSetting.pkg != null) {
@@ -20460,7 +20453,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
synchronized (mLock) {
- final PreferredIntentResolver pir = mSettings.mPreferredActivities.get(userId);
+ final PreferredIntentResolver pir = mSettings.getPreferredActivities(userId);
if (pir != null) {
// Get all of the existing entries that exactly match this filter.
final ArrayList<PreferredActivity> existing = pir.findFilters(filter);
@@ -20557,35 +20550,7 @@ public class PackageManagerService extends IPackageManager.Stub
@GuardedBy("mLock")
private void clearPackagePreferredActivitiesLPw(String packageName,
@NonNull SparseBooleanArray outUserChanged, int userId) {
- ArrayList<PreferredActivity> removed = null;
- for (int i=0; i<mSettings.mPreferredActivities.size(); i++) {
- final int thisUserId = mSettings.mPreferredActivities.keyAt(i);
- PreferredIntentResolver pir = mSettings.mPreferredActivities.valueAt(i);
- if (userId != UserHandle.USER_ALL && userId != thisUserId) {
- continue;
- }
- Iterator<PreferredActivity> it = pir.filterIterator();
- while (it.hasNext()) {
- PreferredActivity pa = it.next();
- // Mark entry for removal only if it matches the package name
- // and the entry is of type "always".
- if (packageName == null ||
- (pa.mPref.mComponent.getPackageName().equals(packageName)
- && pa.mPref.mAlways)) {
- if (removed == null) {
- removed = new ArrayList<>();
- }
- removed.add(pa);
- }
- }
- if (removed != null) {
- for (int j=0; j<removed.size(); j++) {
- PreferredActivity pa = removed.get(j);
- pir.removeFilter(pa);
- }
- outUserChanged.put(thisUserId, true);
- }
- }
+ mSettings.clearPackagePreferredActivities(packageName, outUserChanged, userId);
}
/** This method takes a specific user id as well as UserHandle.USER_ALL. */
@@ -20702,7 +20667,7 @@ public class PackageManagerService extends IPackageManager.Stub
final int userId = UserHandle.getCallingUserId();
// reader
synchronized (mLock) {
- PreferredIntentResolver pir = mSettings.mPreferredActivities.get(userId);
+ PreferredIntentResolver pir = mSettings.getPreferredActivities(userId);
if (pir != null) {
final Iterator<PreferredActivity> it = pir.filterIterator();
while (it.hasNext()) {
@@ -20757,35 +20722,9 @@ public class PackageManagerService extends IPackageManager.Stub
throw new SecurityException(
"clearPackagePersistentPreferredActivities can only be run by the system");
}
- ArrayList<PersistentPreferredActivity> removed = null;
boolean changed = false;
synchronized (mLock) {
- for (int i=0; i<mSettings.mPersistentPreferredActivities.size(); i++) {
- final int thisUserId = mSettings.mPersistentPreferredActivities.keyAt(i);
- PersistentPreferredIntentResolver ppir = mSettings.mPersistentPreferredActivities
- .valueAt(i);
- if (userId != thisUserId) {
- continue;
- }
- Iterator<PersistentPreferredActivity> it = ppir.filterIterator();
- while (it.hasNext()) {
- PersistentPreferredActivity ppa = it.next();
- // Mark entry for removal only if it matches the package name.
- if (ppa.mComponent.getPackageName().equals(packageName)) {
- if (removed == null) {
- removed = new ArrayList<>();
- }
- removed.add(ppa);
- }
- }
- if (removed != null) {
- for (int j=0; j<removed.size(); j++) {
- PersistentPreferredActivity ppa = removed.get(j);
- ppir.removeFilter(ppa);
- }
- changed = true;
- }
- }
+ changed = mSettings.clearPackagePersistentPreferredActivities(packageName, userId);
}
if (changed) {
updateDefaultHomeNotLocked(userId);
@@ -22165,33 +22104,9 @@ public class PackageManagerService extends IPackageManager.Stub
}
synchronized (mLock) {
- // Verify that all of the preferred activity components actually
- // exist. It is possible for applications to be updated and at
- // that point remove a previously declared activity component that
- // had been set as a preferred activity. We try to clean this up
- // the next time we encounter that preferred activity, but it is
- // possible for the user flow to never be able to return to that
- // situation so here we do a validity check to make sure we haven't
- // left any junk around.
- ArrayList<PreferredActivity> removed = new ArrayList<>();
- for (int i=0; i<mSettings.mPreferredActivities.size(); i++) {
- PreferredIntentResolver pir = mSettings.mPreferredActivities.valueAt(i);
- removed.clear();
- for (PreferredActivity pa : pir.filterSet()) {
- if (!mComponentResolver.isActivityDefined(pa.mPref.mComponent)) {
- removed.add(pa);
- }
- }
- if (removed.size() > 0) {
- for (int r=0; r<removed.size(); r++) {
- PreferredActivity pa = removed.get(r);
- Slog.w(TAG, "Removing dangling preferred activity: "
- + pa.mPref.mComponent);
- pir.removeFilter(pa);
- }
- mSettings.writePackageRestrictionsLPr(
- mSettings.mPreferredActivities.keyAt(i));
- }
+ ArrayList<Integer> changed = mSettings.systemReady(mComponentResolver);
+ for (int i = 0; i < changed.size(); i++) {
+ mSettings.writePackageRestrictionsLPr(changed.get(i));
}
}
@@ -22221,22 +22136,6 @@ public class PackageManagerService extends IPackageManager.Stub
mInstallerService.systemReady();
mPackageDexOptimizer.systemReady();
- mInjector.getLocalService(StorageManagerInternal.class).addExternalStoragePolicy(
- new StorageManagerInternal.ExternalStorageMountPolicy() {
- @Override
- public int getMountMode(int uid, String packageName) {
- if (Process.isIsolated(uid)) {
- return Zygote.MOUNT_EXTERNAL_NONE;
- }
- return Zygote.MOUNT_EXTERNAL_DEFAULT;
- }
-
- @Override
- public boolean hasExternalStorage(int uid, String packageName) {
- return true;
- }
- });
-
// Now that we're mostly running, clean up stale users and apps
mUserManager.reconcileUsers(StorageManager.UUID_PRIVATE_INTERNAL);
reconcileApps(StorageManager.UUID_PRIVATE_INTERNAL);
@@ -22718,17 +22617,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
if (!checkin && dumpState.isDumping(DumpState.DUMP_PREFERRED)) {
- for (int i=0; i<mSettings.mPreferredActivities.size(); i++) {
- PreferredIntentResolver pir = mSettings.mPreferredActivities.valueAt(i);
- int user = mSettings.mPreferredActivities.keyAt(i);
- if (pir.dump(pw,
- dumpState.getTitlePrinted()
- ? "\nPreferred Activities User " + user + ":"
- : "Preferred Activities User " + user + ":", " ",
- packageName, true, false)) {
- dumpState.setTitlePrinted(true);
- }
- }
+ mSettings.dumpPreferred(pw, dumpState, packageName);
}
if (!checkin && dumpState.isDumping(DumpState.DUMP_PREFERRED_XML)) {
@@ -24827,6 +24716,26 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
+ private AndroidPackage getPackage(String packageName) {
+ synchronized (mLock) {
+ packageName = resolveInternalPackageNameLPr(
+ packageName, PackageManager.VERSION_CODE_HIGHEST);
+ return mPackages.get(packageName);
+ }
+ }
+
+ private AndroidPackage getPackage(int uid) {
+ synchronized (mLock) {
+ final String[] packageNames = getPackagesForUidInternal(uid, Process.SYSTEM_UID);
+ AndroidPackage pkg = null;
+ final int numPackages = packageNames == null ? 0 : packageNames.length;
+ for (int i = 0; pkg == null && i < numPackages; i++) {
+ pkg = mPackages.get(packageNames[i]);
+ }
+ return pkg;
+ }
+ }
+
private class PackageManagerInternalImpl extends PackageManagerInternal {
@Override
public List<ApplicationInfo> getInstalledApplications(int flags, int userId,
@@ -24937,24 +24846,12 @@ public class PackageManagerService extends IPackageManager.Stub
@Override
public AndroidPackage getPackage(String packageName) {
- synchronized (mLock) {
- packageName = resolveInternalPackageNameLPr(
- packageName, PackageManager.VERSION_CODE_HIGHEST);
- return mPackages.get(packageName);
- }
+ return PackageManagerService.this.getPackage(packageName);
}
@Override
public AndroidPackage getPackage(int uid) {
- synchronized (mLock) {
- final String[] packageNames = getPackagesForUidInternal(uid, Process.SYSTEM_UID);
- AndroidPackage pkg = null;
- final int numPackages = packageNames == null ? 0 : packageNames.length;
- for (int i = 0; pkg == null && i < numPackages; i++) {
- pkg = mPackages.get(packageNames[i]);
- }
- return pkg;
- }
+ return PackageManagerService.this.getPackage(uid);
}
@Nullable
@@ -25561,7 +25458,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
- PackageManager.invalidatePackageInfoCache();
+ invalidatePackageInfoCache();
return true;
}
diff --git a/services/core/java/com/android/server/pm/PackageProperty.java b/services/core/java/com/android/server/pm/PackageProperty.java
index d18a02d9f315..ee9ed3b90599 100644
--- a/services/core/java/com/android/server/pm/PackageProperty.java
+++ b/services/core/java/com/android/server/pm/PackageProperty.java
@@ -274,7 +274,7 @@ public class PackageProperty {
private Property getApplicationProperty(String propertyName, String packageName) {
final ArrayMap<String, ArrayList<Property>> packagePropertyMap =
- mApplicationProperties.get(propertyName);
+ mApplicationProperties != null ? mApplicationProperties.get(propertyName) : null;
if (packagePropertyMap == null) {
return null;
}
diff --git a/services/core/java/com/android/server/pm/PreferredComponent.java b/services/core/java/com/android/server/pm/PreferredComponent.java
index 804faa1b7f0f..ff6b73b36f62 100644
--- a/services/core/java/com/android/server/pm/PreferredComponent.java
+++ b/services/core/java/com/android/server/pm/PreferredComponent.java
@@ -252,6 +252,37 @@ public class PreferredComponent {
return numMatch == NS;
}
+ public boolean sameSet(PreferredComponent pc) {
+ if (mSetPackages == null || pc == null || pc.mSetPackages == null
+ || !sameComponent(pc.mComponent)) {
+ return false;
+ }
+ final int otherPackageCount = pc.mSetPackages.length;
+ final int packageCount = mSetPackages.length;
+ if (otherPackageCount != packageCount) {
+ return false;
+ }
+ for (int i = 0; i < packageCount; i++) {
+ if (!mSetPackages[i].equals(pc.mSetPackages[i])
+ || !mSetClasses[i].equals(pc.mSetClasses[i])) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /** Returns true if the preferred component represents the provided ComponentName. */
+ private boolean sameComponent(ComponentName comp) {
+ if (mComponent == null || comp == null) {
+ return false;
+ }
+ if (mComponent.getPackageName().equals(comp.getPackageName())
+ && mComponent.getClassName().equals(comp.getClassName())) {
+ return true;
+ }
+ return false;
+ }
+
public boolean isSuperset(List<ResolveInfo> query, boolean excludeSetupWizardPackage) {
if (mSetPackages == null) {
return query == null;
diff --git a/services/core/java/com/android/server/pm/PreferredIntentResolver.java b/services/core/java/com/android/server/pm/PreferredIntentResolver.java
index a261e29b05a7..ff3df130a3cc 100644
--- a/services/core/java/com/android/server/pm/PreferredIntentResolver.java
+++ b/services/core/java/com/android/server/pm/PreferredIntentResolver.java
@@ -22,6 +22,7 @@ import android.content.IntentFilter;
import java.io.PrintWriter;
import com.android.server.IntentResolver;
+import java.util.ArrayList;
public class PreferredIntentResolver
extends IntentResolver<PreferredActivity, PreferredActivity> {
@@ -45,4 +46,24 @@ public class PreferredIntentResolver
protected IntentFilter getIntentFilter(@NonNull PreferredActivity input) {
return input;
}
+
+ public boolean shouldAddPreferredActivity(PreferredActivity pa) {
+ ArrayList<PreferredActivity> pal = findFilters(pa);
+ if (pal == null || pal.isEmpty()) {
+ return true;
+ }
+ if (!pa.mPref.mAlways) {
+ return false;
+ }
+ final int activityCount = pal.size();
+ for (int i = 0; i < activityCount; i++) {
+ PreferredActivity cur = pal.get(i);
+ if (cur.mPref.mAlways
+ && cur.mPref.mMatch == (pa.mPref.mMatch & IntentFilter.MATCH_CATEGORY_MASK)
+ && cur.mPref.sameSet(pa.mPref)) {
+ return false;
+ }
+ }
+ return true;
+ }
}
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 966090cb96a7..f47b4b46fdd4 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -369,16 +369,16 @@ public final class Settings {
// The user's preferred activities associated with particular intent
// filters.
- final SparseArray<PreferredIntentResolver> mPreferredActivities =
+ private final SparseArray<PreferredIntentResolver> mPreferredActivities =
new SparseArray<PreferredIntentResolver>();
// The persistent preferred activities of the user's profile/device owner
// associated with particular intent filters.
- final SparseArray<PersistentPreferredIntentResolver> mPersistentPreferredActivities =
+ private final SparseArray<PersistentPreferredIntentResolver> mPersistentPreferredActivities =
new SparseArray<PersistentPreferredIntentResolver>();
// For every user, it is used to find to which other users the intent can be forwarded.
- final SparseArray<CrossProfileIntentResolver> mCrossProfileIntentResolvers =
+ private final SparseArray<CrossProfileIntentResolver> mCrossProfileIntentResolvers =
new SparseArray<CrossProfileIntentResolver>();
final ArrayMap<String, SharedUserSetting> mSharedUsers = new ArrayMap<>();
@@ -467,7 +467,7 @@ public final class Settings {
}
private static void invalidatePackageCache() {
- PackageManager.invalidatePackageInfoCache();
+ PackageManagerService.invalidatePackageInfoCache();
ChangeIdStateCache.invalidate();
}
@@ -1312,8 +1312,7 @@ public final class Settings {
PreferredActivity pa = new PreferredActivity(parser);
if (pa.mPref.getParseError() == null) {
final PreferredIntentResolver resolver = editPreferredActivitiesLPw(userId);
- ArrayList<PreferredActivity> pal = resolver.findFilters(pa);
- if (pal == null || pal.size() == 0 || pa.mPref.mAlways) {
+ if (resolver.shouldAddPreferredActivity(pa)) {
resolver.addFilter(pa);
}
} else {
@@ -5543,4 +5542,130 @@ public final class Settings {
}
}
}
+
+ /**
+ * Accessor for preferred activities
+ */
+ PersistentPreferredIntentResolver getPersistentPreferredActivities(int userId) {
+ return mPersistentPreferredActivities.get(userId);
+ }
+
+ PreferredIntentResolver getPreferredActivities(int userId) {
+ return mPreferredActivities.get(userId);
+ }
+
+ CrossProfileIntentResolver getCrossProfileIntentResolvers(int userId) {
+ return mCrossProfileIntentResolvers.get(userId);
+ }
+
+ /** This method takes a specific user id as well as UserHandle.USER_ALL. */
+ void clearPackagePreferredActivities(String packageName,
+ @NonNull SparseBooleanArray outUserChanged, int userId) {
+ ArrayList<PreferredActivity> removed = null;
+ for (int i = 0; i < mPreferredActivities.size(); i++) {
+ final int thisUserId = mPreferredActivities.keyAt(i);
+ PreferredIntentResolver pir = mPreferredActivities.valueAt(i);
+ if (userId != UserHandle.USER_ALL && userId != thisUserId) {
+ continue;
+ }
+ Iterator<PreferredActivity> it = pir.filterIterator();
+ while (it.hasNext()) {
+ PreferredActivity pa = it.next();
+ // Mark entry for removal only if it matches the package name
+ // and the entry is of type "always".
+ if (packageName == null
+ || (pa.mPref.mComponent.getPackageName().equals(packageName)
+ && pa.mPref.mAlways)) {
+ if (removed == null) {
+ removed = new ArrayList<>();
+ }
+ removed.add(pa);
+ }
+ }
+ if (removed != null) {
+ for (int j = 0; j < removed.size(); j++) {
+ PreferredActivity pa = removed.get(j);
+ pir.removeFilter(pa);
+ }
+ outUserChanged.put(thisUserId, true);
+ }
+ }
+ }
+
+ boolean clearPackagePersistentPreferredActivities(String packageName, int userId) {
+ ArrayList<PersistentPreferredActivity> removed = null;
+ boolean changed = false;
+ for (int i = 0; i < mPersistentPreferredActivities.size(); i++) {
+ final int thisUserId = mPersistentPreferredActivities.keyAt(i);
+ PersistentPreferredIntentResolver ppir = mPersistentPreferredActivities.valueAt(i);
+ if (userId != thisUserId) {
+ continue;
+ }
+ Iterator<PersistentPreferredActivity> it = ppir.filterIterator();
+ while (it.hasNext()) {
+ PersistentPreferredActivity ppa = it.next();
+ // Mark entry for removal only if it matches the package name.
+ if (ppa.mComponent.getPackageName().equals(packageName)) {
+ if (removed == null) {
+ removed = new ArrayList<>();
+ }
+ removed.add(ppa);
+ }
+ }
+ if (removed != null) {
+ for (int j = 0; j < removed.size(); j++) {
+ PersistentPreferredActivity ppa = removed.get(j);
+ ppir.removeFilter(ppa);
+ }
+ changed = true;
+ }
+ }
+ return changed;
+ }
+
+ ArrayList<Integer> systemReady(ComponentResolver resolver) {
+ // Verify that all of the preferred activity components actually
+ // exist. It is possible for applications to be updated and at
+ // that point remove a previously declared activity component that
+ // had been set as a preferred activity. We try to clean this up
+ // the next time we encounter that preferred activity, but it is
+ // possible for the user flow to never be able to return to that
+ // situation so here we do a validity check to make sure we haven't
+ // left any junk around.
+ ArrayList<Integer> changed = new ArrayList<>();
+ ArrayList<PreferredActivity> removed = new ArrayList<>();
+ for (int i = 0; i < mPreferredActivities.size(); i++) {
+ PreferredIntentResolver pir = mPreferredActivities.valueAt(i);
+ removed.clear();
+ for (PreferredActivity pa : pir.filterSet()) {
+ if (!resolver.isActivityDefined(pa.mPref.mComponent)) {
+ removed.add(pa);
+ }
+ }
+ if (removed.size() > 0) {
+ for (int r = 0; r < removed.size(); r++) {
+ PreferredActivity pa = removed.get(r);
+ Slog.w(TAG, "Removing dangling preferred activity: "
+ + pa.mPref.mComponent);
+ pir.removeFilter(pa);
+ }
+ changed.add(mPreferredActivities.keyAt(i));
+ }
+ }
+ return changed;
+ }
+
+ void dumpPreferred(PrintWriter pw, DumpState dumpState, String packageName) {
+ for (int i = 0; i < mPreferredActivities.size(); i++) {
+ PreferredIntentResolver pir = mPreferredActivities.valueAt(i);
+ int user = mPreferredActivities.keyAt(i);
+ if (pir.dump(pw,
+ dumpState.getTitlePrinted()
+ ? "\nPreferred Activities User " + user + ":"
+ : "Preferred Activities User " + user + ":", " ",
+ packageName, true, false)) {
+ dumpState.setTitlePrinted(true);
+ }
+ }
+ }
}
diff --git a/services/core/java/com/android/server/pm/ShareTargetInfo.java b/services/core/java/com/android/server/pm/ShareTargetInfo.java
index fdfee773ea74..660874e7b3c3 100644
--- a/services/core/java/com/android/server/pm/ShareTargetInfo.java
+++ b/services/core/java/com/android/server/pm/ShareTargetInfo.java
@@ -17,10 +17,11 @@ package com.android.server.pm;
import android.annotation.NonNull;
import android.text.TextUtils;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
import java.io.IOException;
import java.util.ArrayList;
@@ -123,7 +124,7 @@ class ShareTargetInfo {
return strBuilder.toString();
}
- void saveToXml(@NonNull XmlSerializer out) throws IOException {
+ void saveToXml(@NonNull TypedXmlSerializer out) throws IOException {
out.startTag(null, TAG_SHARE_TARGET);
ShortcutService.writeAttr(out, ATTR_TARGET_CLASS, mTargetClass);
@@ -149,7 +150,7 @@ class ShareTargetInfo {
out.endTag(null, TAG_SHARE_TARGET);
}
- static ShareTargetInfo loadFromXml(XmlPullParser parser)
+ static ShareTargetInfo loadFromXml(TypedXmlPullParser parser)
throws IOException, XmlPullParserException {
final String targetClass = ShortcutService.parseStringAttribute(parser, ATTR_TARGET_CLASS);
final ArrayList<ShareTargetInfo.TargetData> targetData = new ArrayList<>();
@@ -178,7 +179,7 @@ class ShareTargetInfo {
targetClass, categories.toArray(new String[categories.size()]));
}
- private static ShareTargetInfo.TargetData parseTargetData(XmlPullParser parser) {
+ private static ShareTargetInfo.TargetData parseTargetData(TypedXmlPullParser parser) {
final String scheme = ShortcutService.parseStringAttribute(parser, ATTR_SCHEME);
final String host = ShortcutService.parseStringAttribute(parser, ATTR_HOST);
final String port = ShortcutService.parseStringAttribute(parser, ATTR_PORT);
diff --git a/services/core/java/com/android/server/pm/ShortcutLauncher.java b/services/core/java/com/android/server/pm/ShortcutLauncher.java
index 0ebe596111f2..2960bc9a3790 100644
--- a/services/core/java/com/android/server/pm/ShortcutLauncher.java
+++ b/services/core/java/com/android/server/pm/ShortcutLauncher.java
@@ -24,6 +24,8 @@ import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.AtomicFile;
import android.util.Slog;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
import android.util.Xml;
import com.android.internal.annotations.VisibleForTesting;
@@ -36,15 +38,12 @@ import org.json.JSONException;
import org.json.JSONObject;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
-import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintWriter;
-import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
@@ -225,7 +224,7 @@ class ShortcutLauncher extends ShortcutPackageItem {
* Persist.
*/
@Override
- public void saveToXml(XmlSerializer out, boolean forBackup)
+ public void saveToXml(TypedXmlSerializer out, boolean forBackup)
throws IOException {
if (forBackup && !getPackageInfo().isBackupAllowed()) {
// If an launcher app doesn't support backup&restore, then nothing to do.
@@ -278,11 +277,8 @@ class ShortcutLauncher extends ShortcutPackageItem {
}
try {
- final BufferedInputStream bis = new BufferedInputStream(in);
-
ShortcutLauncher ret = null;
- XmlPullParser parser = Xml.newPullParser();
- parser.setInput(bis, StandardCharsets.UTF_8.name());
+ TypedXmlPullParser parser = Xml.resolvePullParser(in);
int type;
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
@@ -313,7 +309,7 @@ class ShortcutLauncher extends ShortcutPackageItem {
/**
* Load.
*/
- public static ShortcutLauncher loadFromXml(XmlPullParser parser, ShortcutUser shortcutUser,
+ public static ShortcutLauncher loadFromXml(TypedXmlPullParser parser, ShortcutUser shortcutUser,
int ownerUserId, boolean fromBackup) throws IOException, XmlPullParserException {
final String launcherPackageName = ShortcutService.parseStringAttribute(parser,
ATTR_PACKAGE_NAME);
diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java
index f6c60ad6e2cf..0ac0c8d95423 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackage.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackage.java
@@ -35,6 +35,8 @@ import android.util.ArraySet;
import android.util.AtomicFile;
import android.util.Log;
import android.util.Slog;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
import android.util.Xml;
import com.android.internal.annotations.VisibleForTesting;
@@ -52,15 +54,12 @@ import org.json.JSONException;
import org.json.JSONObject;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
-import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintWriter;
-import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
@@ -1571,7 +1570,7 @@ class ShortcutPackage extends ShortcutPackageItem {
}
@Override
- public void saveToXml(@NonNull XmlSerializer out, boolean forBackup)
+ public void saveToXml(@NonNull TypedXmlSerializer out, boolean forBackup)
throws IOException, XmlPullParserException {
final int size = mShortcuts.size();
final int shareTargetSize = mShareTargets.size();
@@ -1601,7 +1600,7 @@ class ShortcutPackage extends ShortcutPackageItem {
out.endTag(null, TAG_ROOT);
}
- private void saveShortcut(XmlSerializer out, ShortcutInfo si, boolean forBackup,
+ private void saveShortcut(TypedXmlSerializer out, ShortcutInfo si, boolean forBackup,
boolean appSupportsBackup)
throws IOException, XmlPullParserException {
@@ -1734,11 +1733,8 @@ class ShortcutPackage extends ShortcutPackageItem {
}
try {
- final BufferedInputStream bis = new BufferedInputStream(in);
-
ShortcutPackage ret = null;
- XmlPullParser parser = Xml.newPullParser();
- parser.setInput(bis, StandardCharsets.UTF_8.name());
+ TypedXmlPullParser parser = Xml.resolvePullParser(in);
int type;
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
@@ -1767,7 +1763,7 @@ class ShortcutPackage extends ShortcutPackageItem {
}
public static ShortcutPackage loadFromXml(ShortcutService s, ShortcutUser shortcutUser,
- XmlPullParser parser, boolean fromBackup)
+ TypedXmlPullParser parser, boolean fromBackup)
throws IOException, XmlPullParserException {
final String packageName = ShortcutService.parseStringAttribute(parser,
@@ -1814,7 +1810,7 @@ class ShortcutPackage extends ShortcutPackageItem {
return ret;
}
- private static ShortcutInfo parseShortcut(XmlPullParser parser, String packageName,
+ private static ShortcutInfo parseShortcut(TypedXmlPullParser parser, String packageName,
@UserIdInt int userId, boolean fromBackup)
throws IOException, XmlPullParserException {
String id;
@@ -1948,7 +1944,7 @@ class ShortcutPackage extends ShortcutPackageItem {
disabledReason, persons.toArray(new Person[persons.size()]), locusId);
}
- private static Intent parseIntent(XmlPullParser parser)
+ private static Intent parseIntent(TypedXmlPullParser parser)
throws IOException, XmlPullParserException {
Intent intent = ShortcutService.parseIntentAttribute(parser,
@@ -1978,7 +1974,7 @@ class ShortcutPackage extends ShortcutPackageItem {
return intent;
}
- private static Person parsePerson(XmlPullParser parser)
+ private static Person parsePerson(TypedXmlPullParser parser)
throws IOException, XmlPullParserException {
CharSequence name = ShortcutService.parseStringAttribute(parser, ATTR_PERSON_NAME);
String uri = ShortcutService.parseStringAttribute(parser, ATTR_PERSON_URI);
diff --git a/services/core/java/com/android/server/pm/ShortcutPackageInfo.java b/services/core/java/com/android/server/pm/ShortcutPackageInfo.java
index 8c7871ffaf96..fce66108bede 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackageInfo.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackageInfo.java
@@ -23,6 +23,8 @@ import android.content.pm.ShortcutInfo;
import android.content.pm.Signature;
import android.content.pm.SigningInfo;
import android.util.Slog;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.LocalServices;
@@ -32,7 +34,6 @@ import libcore.util.HexEncoding;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
import java.io.IOException;
import java.io.PrintWriter;
@@ -205,7 +206,7 @@ class ShortcutPackageInfo {
mSigHashes = BackupUtils.hashSignatureArray(signatures);
}
- public void saveToXml(ShortcutService s, XmlSerializer out, boolean forBackup)
+ public void saveToXml(ShortcutService s, TypedXmlSerializer out, boolean forBackup)
throws IOException {
if (forBackup && !mBackupAllowedInitialized) {
s.wtf("Backup happened before mBackupAllowed is initialized.");
@@ -236,7 +237,7 @@ class ShortcutPackageInfo {
out.endTag(null, TAG_ROOT);
}
- public void loadFromXml(XmlPullParser parser, boolean fromBackup)
+ public void loadFromXml(TypedXmlPullParser parser, boolean fromBackup)
throws IOException, XmlPullParserException {
// Don't use the version code from the backup file.
final long versionCode = ShortcutService.parseLongAttribute(parser, ATTR_VERSION,
diff --git a/services/core/java/com/android/server/pm/ShortcutPackageItem.java b/services/core/java/com/android/server/pm/ShortcutPackageItem.java
index 801c6cbb8f46..829133c9854a 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackageItem.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackageItem.java
@@ -20,16 +20,15 @@ import android.content.pm.PackageInfo;
import android.content.pm.ShortcutInfo;
import android.util.AtomicFile;
import android.util.Slog;
+import android.util.TypedXmlSerializer;
+import android.util.Xml;
-import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.Preconditions;
import org.json.JSONException;
import org.json.JSONObject;
import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
-import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
@@ -146,7 +145,7 @@ abstract class ShortcutPackageItem {
protected abstract void onRestored(int restoreBlockReason);
- public abstract void saveToXml(@NonNull XmlSerializer out, boolean forBackup)
+ public abstract void saveToXml(@NonNull TypedXmlSerializer out, boolean forBackup)
throws IOException, XmlPullParserException;
public void saveToFile(File path, boolean forBackup) {
@@ -154,18 +153,21 @@ abstract class ShortcutPackageItem {
FileOutputStream os = null;
try {
os = file.startWrite();
- final BufferedOutputStream bos = new BufferedOutputStream(os);
// Write to XML
- XmlSerializer itemOut = new FastXmlSerializer();
- itemOut.setOutput(bos, StandardCharsets.UTF_8.name());
+ final TypedXmlSerializer itemOut;
+ if (forBackup) {
+ itemOut = Xml.newFastSerializer();
+ itemOut.setOutput(os, StandardCharsets.UTF_8.name());
+ } else {
+ itemOut = Xml.resolveSerializer(os);
+ }
itemOut.startDocument(null, true);
saveToXml(itemOut, forBackup);
itemOut.endDocument();
- bos.flush();
os.flush();
file.finishWrite(os);
} catch (XmlPullParserException | IOException e) {
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index 2d771820865d..c68fe81d0565 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -95,6 +95,8 @@ import android.util.SparseBooleanArray;
import android.util.SparseIntArray;
import android.util.SparseLongArray;
import android.util.TypedValue;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
import android.util.Xml;
import android.view.IWindowManager;
@@ -104,7 +106,6 @@ import com.android.internal.logging.MetricsLogger;
import com.android.internal.os.BackgroundThread;
import com.android.internal.util.CollectionUtils;
import com.android.internal.util.DumpUtils;
-import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.Preconditions;
import com.android.internal.util.StatLogger;
import com.android.server.LocalServices;
@@ -119,10 +120,7 @@ import org.json.JSONException;
import org.json.JSONObject;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
-import java.io.BufferedInputStream;
-import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
@@ -799,31 +797,31 @@ public class ShortcutService extends IShortcutService.Stub {
// === Persisting ===
@Nullable
- static String parseStringAttribute(XmlPullParser parser, String attribute) {
+ static String parseStringAttribute(TypedXmlPullParser parser, String attribute) {
return parser.getAttributeValue(null, attribute);
}
- static boolean parseBooleanAttribute(XmlPullParser parser, String attribute) {
+ static boolean parseBooleanAttribute(TypedXmlPullParser parser, String attribute) {
return parseLongAttribute(parser, attribute) == 1;
}
- static boolean parseBooleanAttribute(XmlPullParser parser, String attribute, boolean def) {
+ static boolean parseBooleanAttribute(TypedXmlPullParser parser, String attribute, boolean def) {
return parseLongAttribute(parser, attribute, (def ? 1 : 0)) == 1;
}
- static int parseIntAttribute(XmlPullParser parser, String attribute) {
+ static int parseIntAttribute(TypedXmlPullParser parser, String attribute) {
return (int) parseLongAttribute(parser, attribute);
}
- static int parseIntAttribute(XmlPullParser parser, String attribute, int def) {
+ static int parseIntAttribute(TypedXmlPullParser parser, String attribute, int def) {
return (int) parseLongAttribute(parser, attribute, def);
}
- static long parseLongAttribute(XmlPullParser parser, String attribute) {
+ static long parseLongAttribute(TypedXmlPullParser parser, String attribute) {
return parseLongAttribute(parser, attribute, 0);
}
- static long parseLongAttribute(XmlPullParser parser, String attribute, long def) {
+ static long parseLongAttribute(TypedXmlPullParser parser, String attribute, long def) {
final String value = parseStringAttribute(parser, attribute);
if (TextUtils.isEmpty(value)) {
return def;
@@ -837,7 +835,7 @@ public class ShortcutService extends IShortcutService.Stub {
}
@Nullable
- static ComponentName parseComponentNameAttribute(XmlPullParser parser, String attribute) {
+ static ComponentName parseComponentNameAttribute(TypedXmlPullParser parser, String attribute) {
final String value = parseStringAttribute(parser, attribute);
if (TextUtils.isEmpty(value)) {
return null;
@@ -846,7 +844,7 @@ public class ShortcutService extends IShortcutService.Stub {
}
@Nullable
- static Intent parseIntentAttributeNoDefault(XmlPullParser parser, String attribute) {
+ static Intent parseIntentAttributeNoDefault(TypedXmlPullParser parser, String attribute) {
final String value = parseStringAttribute(parser, attribute);
Intent parsed = null;
if (!TextUtils.isEmpty(value)) {
@@ -860,7 +858,7 @@ public class ShortcutService extends IShortcutService.Stub {
}
@Nullable
- static Intent parseIntentAttribute(XmlPullParser parser, String attribute) {
+ static Intent parseIntentAttribute(TypedXmlPullParser parser, String attribute) {
Intent parsed = parseIntentAttributeNoDefault(parser, attribute);
if (parsed == null) {
// Default intent.
@@ -869,7 +867,7 @@ public class ShortcutService extends IShortcutService.Stub {
return parsed;
}
- static void writeTagValue(XmlSerializer out, String tag, String value) throws IOException {
+ static void writeTagValue(TypedXmlSerializer out, String tag, String value) throws IOException {
if (TextUtils.isEmpty(value)) return;
out.startTag(null, tag);
@@ -877,16 +875,17 @@ public class ShortcutService extends IShortcutService.Stub {
out.endTag(null, tag);
}
- static void writeTagValue(XmlSerializer out, String tag, long value) throws IOException {
+ static void writeTagValue(TypedXmlSerializer out, String tag, long value) throws IOException {
writeTagValue(out, tag, Long.toString(value));
}
- static void writeTagValue(XmlSerializer out, String tag, ComponentName name) throws IOException {
+ static void writeTagValue(TypedXmlSerializer out, String tag, ComponentName name)
+ throws IOException {
if (name == null) return;
writeTagValue(out, tag, name.flattenToString());
}
- static void writeTagExtra(XmlSerializer out, String tag, PersistableBundle bundle)
+ static void writeTagExtra(TypedXmlSerializer out, String tag, PersistableBundle bundle)
throws IOException, XmlPullParserException {
if (bundle == null) return;
@@ -895,17 +894,18 @@ public class ShortcutService extends IShortcutService.Stub {
out.endTag(null, tag);
}
- static void writeAttr(XmlSerializer out, String name, CharSequence value) throws IOException {
+ static void writeAttr(TypedXmlSerializer out, String name, CharSequence value)
+ throws IOException {
if (TextUtils.isEmpty(value)) return;
out.attribute(null, name, value.toString());
}
- static void writeAttr(XmlSerializer out, String name, long value) throws IOException {
+ static void writeAttr(TypedXmlSerializer out, String name, long value) throws IOException {
writeAttr(out, name, String.valueOf(value));
}
- static void writeAttr(XmlSerializer out, String name, boolean value) throws IOException {
+ static void writeAttr(TypedXmlSerializer out, String name, boolean value) throws IOException {
if (value) {
writeAttr(out, name, "1");
} else {
@@ -913,12 +913,13 @@ public class ShortcutService extends IShortcutService.Stub {
}
}
- static void writeAttr(XmlSerializer out, String name, ComponentName comp) throws IOException {
+ static void writeAttr(TypedXmlSerializer out, String name, ComponentName comp)
+ throws IOException {
if (comp == null) return;
writeAttr(out, name, comp.flattenToString());
}
- static void writeAttr(XmlSerializer out, String name, Intent intent) throws IOException {
+ static void writeAttr(TypedXmlSerializer out, String name, Intent intent) throws IOException {
if (intent == null) return;
writeAttr(out, name, intent.toUri(/* flags =*/ 0));
@@ -937,8 +938,7 @@ public class ShortcutService extends IShortcutService.Stub {
outs = file.startWrite();
// Write to XML
- XmlSerializer out = new FastXmlSerializer();
- out.setOutput(outs, StandardCharsets.UTF_8.name());
+ TypedXmlSerializer out = Xml.resolveSerializer(outs);
out.startDocument(null, true);
out.startTag(null, TAG_ROOT);
@@ -966,8 +966,7 @@ public class ShortcutService extends IShortcutService.Stub {
Slog.d(TAG, "Loading from " + file.getBaseFile());
}
try (FileInputStream in = file.openRead()) {
- XmlPullParser parser = Xml.newPullParser();
- parser.setInput(in, StandardCharsets.UTF_8.name());
+ TypedXmlPullParser parser = Xml.resolvePullParser(in);
int type;
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
@@ -1043,18 +1042,20 @@ public class ShortcutService extends IShortcutService.Stub {
private void saveUserInternalLocked(@UserIdInt int userId, OutputStream os,
boolean forBackup) throws IOException, XmlPullParserException {
- final BufferedOutputStream bos = new BufferedOutputStream(os);
-
// Write to XML
- XmlSerializer out = new FastXmlSerializer();
- out.setOutput(bos, StandardCharsets.UTF_8.name());
+ final TypedXmlSerializer out;
+ if (forBackup) {
+ out = Xml.newFastSerializer();
+ out.setOutput(os, StandardCharsets.UTF_8.name());
+ } else {
+ out = Xml.resolveSerializer(os);
+ }
out.startDocument(null, true);
getUserShortcutsLocked(userId).saveToXml(out, forBackup);
out.endDocument();
- bos.flush();
os.flush();
}
@@ -1098,11 +1099,14 @@ public class ShortcutService extends IShortcutService.Stub {
boolean fromBackup) throws XmlPullParserException, IOException,
InvalidFileFormatException {
- final BufferedInputStream bis = new BufferedInputStream(is);
-
ShortcutUser ret = null;
- XmlPullParser parser = Xml.newPullParser();
- parser.setInput(bis, StandardCharsets.UTF_8.name());
+ TypedXmlPullParser parser;
+ if (fromBackup) {
+ parser = Xml.newFastPullParser();
+ parser.setInput(is, StandardCharsets.UTF_8.name());
+ } else {
+ parser = Xml.resolvePullParser(is);
+ }
int type;
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
diff --git a/services/core/java/com/android/server/pm/ShortcutUser.java b/services/core/java/com/android/server/pm/ShortcutUser.java
index 5c1d8fb142e9..3e3aa677912b 100644
--- a/services/core/java/com/android/server/pm/ShortcutUser.java
+++ b/services/core/java/com/android/server/pm/ShortcutUser.java
@@ -26,6 +26,8 @@ import android.text.format.Formatter;
import android.util.ArrayMap;
import android.util.Log;
import android.util.Slog;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.MetricsLogger;
@@ -38,7 +40,6 @@ import org.json.JSONException;
import org.json.JSONObject;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
import java.io.File;
import java.io.IOException;
@@ -329,7 +330,7 @@ class ShortcutUser {
});
}
- public void saveToXml(XmlSerializer out, boolean forBackup)
+ public void saveToXml(TypedXmlSerializer out, boolean forBackup)
throws IOException, XmlPullParserException {
out.startTag(null, TAG_ROOT);
@@ -371,7 +372,7 @@ class ShortcutUser {
out.endTag(null, TAG_ROOT);
}
- private void saveShortcutPackageItem(XmlSerializer out, ShortcutPackageItem spi,
+ private void saveShortcutPackageItem(TypedXmlSerializer out, ShortcutPackageItem spi,
boolean forBackup) throws IOException, XmlPullParserException {
if (forBackup) {
if (spi.getPackageUserId() != spi.getOwnerUserId()) {
@@ -408,7 +409,7 @@ class ShortcutUser {
return new File(path, fileName);
}
- public static ShortcutUser loadFromXml(ShortcutService s, XmlPullParser parser, int userId,
+ public static ShortcutUser loadFromXml(ShortcutService s, TypedXmlPullParser parser, int userId,
boolean fromBackup) throws IOException, XmlPullParserException, InvalidFileFormatException {
final ShortcutUser ret = new ShortcutUser(s, userId);
boolean readShortcutItems = false;
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index c51e75c716cc..cc814bcc7760 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -119,7 +119,6 @@ import libcore.io.IoUtils;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
import java.io.File;
import java.io.FileDescriptor;
@@ -175,6 +174,7 @@ public class UserManagerService extends IUserManager.Stub {
private static final String ATTR_CONVERTED_FROM_PRE_CREATED = "convertedFromPreCreated";
private static final String ATTR_GUEST_TO_REMOVE = "guestToRemove";
private static final String ATTR_USER_VERSION = "version";
+ private static final String ATTR_USER_TYPE_VERSION = "userTypeConfigVersion";
private static final String ATTR_PROFILE_GROUP_ID = "profileGroupId";
private static final String ATTR_PROFILE_BADGE = "profileBadge";
private static final String ATTR_RESTRICTED_PROFILE_PARENT_ID = "restrictedProfileParentId";
@@ -422,6 +422,7 @@ public class UserManagerService extends IUserManager.Stub {
@GuardedBy("mPackagesLock")
private int mNextSerialNumber;
private int mUserVersion = 0;
+ private int mUserTypeVersion = 0;
private IAppOpsService mAppOpsService;
@@ -2565,6 +2566,8 @@ public class UserManagerService extends IUserManager.Stub {
parser.getAttributeInt(null, ATTR_NEXT_SERIAL_NO, mNextSerialNumber);
mUserVersion =
parser.getAttributeInt(null, ATTR_USER_VERSION, mUserVersion);
+ mUserTypeVersion =
+ parser.getAttributeInt(null, ATTR_USER_TYPE_VERSION, mUserTypeVersion);
}
// Pre-O global user restriction were stored as a single bundle (as opposed to per-user
@@ -2627,7 +2630,7 @@ public class UserManagerService extends IUserManager.Stub {
*/
@GuardedBy({"mRestrictionsLock", "mPackagesLock"})
private void upgradeIfNecessaryLP(Bundle oldGlobalUserRestrictions) {
- upgradeIfNecessaryLP(oldGlobalUserRestrictions, mUserVersion);
+ upgradeIfNecessaryLP(oldGlobalUserRestrictions, mUserVersion, mUserTypeVersion);
}
/**
@@ -2636,9 +2639,11 @@ public class UserManagerService extends IUserManager.Stub {
*/
@GuardedBy({"mRestrictionsLock", "mPackagesLock"})
@VisibleForTesting
- void upgradeIfNecessaryLP(Bundle oldGlobalUserRestrictions, int userVersion) {
+ void upgradeIfNecessaryLP(Bundle oldGlobalUserRestrictions, int userVersion,
+ int userTypeVersion) {
Set<Integer> userIdsToWrite = new ArraySet<>();
final int originalVersion = mUserVersion;
+ final int originalUserTypeVersion = mUserTypeVersion;
if (userVersion < 1) {
// Assign a proper name for the owner, if not initialized correctly before
UserData userData = getUserDataNoChecks(UserHandle.USER_SYSTEM);
@@ -2771,13 +2776,24 @@ public class UserManagerService extends IUserManager.Stub {
userVersion = 9;
}
+ // Done with userVersion changes, moving on to deal with userTypeVersion upgrades
+ // Upgrade from previous user type to a new user type
+ final int newUserTypeVersion = UserTypeFactory.getUserTypeVersion();
+ if (newUserTypeVersion > userTypeVersion) {
+ synchronized (mUsersLock) {
+ upgradeUserTypesLU(UserTypeFactory.getUserTypeUpgrades(), mUserTypes,
+ userTypeVersion, userIdsToWrite);
+ }
+ }
+
if (userVersion < USER_VERSION) {
Slog.w(LOG_TAG, "User version " + mUserVersion + " didn't upgrade as expected to "
+ USER_VERSION);
} else {
mUserVersion = userVersion;
+ mUserTypeVersion = newUserTypeVersion;
- if (originalVersion < mUserVersion) {
+ if (originalVersion < mUserVersion || originalUserTypeVersion < mUserTypeVersion) {
for (int userId : userIdsToWrite) {
UserData userData = getUserDataNoChecks(userId);
if (userData != null) {
@@ -2801,6 +2817,7 @@ public class UserManagerService extends IUserManager.Stub {
UserData userData = putUserInfo(system);
mNextSerialNumber = MIN_USER_ID;
mUserVersion = USER_VERSION;
+ mUserTypeVersion = UserTypeFactory.getUserTypeVersion();
Bundle restrictions = new Bundle();
try {
@@ -2991,6 +3008,7 @@ public class UserManagerService extends IUserManager.Stub {
serializer.startTag(null, TAG_USERS);
serializer.attributeInt(null, ATTR_NEXT_SERIAL_NO, mNextSerialNumber);
serializer.attributeInt(null, ATTR_USER_VERSION, mUserVersion);
+ serializer.attributeInt(null, ATTR_USER_TYPE_VERSION, mUserTypeVersion);
serializer.startTag(null, TAG_GUEST_RESTRICTIONS);
synchronized (mGuestRestrictions) {
@@ -4957,6 +4975,7 @@ public class UserManagerService extends IUserManager.Stub {
// Dump UserTypes
pw.println();
+ pw.println("User types version: " + mUserTypeVersion);
pw.println("User types (" + mUserTypes.size() + " types):");
for (int i = 0; i < mUserTypes.size(); i++) {
pw.println(" " + mUserTypes.keyAt(i) + ": ");
@@ -5447,6 +5466,9 @@ public class UserManagerService extends IUserManager.Stub {
* Returns the maximum number of users allowed for the given userTypeDetails per parent user.
* This is applicable for user types that are {@link UserTypeDetails#isProfile()}.
* If there is no maximum, {@link UserTypeDetails#UNLIMITED_NUMBER_OF_USERS} is returned.
+ * Under certain circumstances (such as after a change-user-type) the max value can actually
+ * be exceeded: this is allowed in order to keep the device in a usable state.
+ * An error is logged in {@link UserManagerService#upgradeProfileToTypeLU}
*/
private static int getMaxUsersOfTypePerParent(UserTypeDetails userTypeDetails) {
final int defaultMax = userTypeDetails.getMaxAllowedPerParent();
@@ -5534,4 +5556,98 @@ public class UserManagerService extends IUserManager.Stub {
}
return mDevicePolicyManagerInternal;
}
+
+ @GuardedBy("mUsersLock")
+ @VisibleForTesting
+ void upgradeUserTypesLU(@NonNull List<UserTypeFactory.UserTypeUpgrade> upgradeOps,
+ @NonNull ArrayMap<String, UserTypeDetails> userTypes,
+ final int formerUserTypeVersion,
+ @NonNull Set<Integer> userIdsToWrite) {
+ for (UserTypeFactory.UserTypeUpgrade userTypeUpgrade : upgradeOps) {
+ if (DBG) {
+ Slog.i(LOG_TAG, "Upgrade: " + userTypeUpgrade.getFromType() + " to: "
+ + userTypeUpgrade.getToType() + " maxVersion: "
+ + userTypeUpgrade.getUpToVersion());
+ }
+
+ // upgrade user type if version up to getUpToVersion()
+ if (formerUserTypeVersion <= userTypeUpgrade.getUpToVersion()) {
+ for (int i = 0; i < mUsers.size(); i++) {
+ UserData userData = mUsers.valueAt(i);
+ if (userTypeUpgrade.getFromType().equals(userData.info.userType)) {
+ final UserTypeDetails newUserType = userTypes.get(
+ userTypeUpgrade.getToType());
+
+ if (newUserType == null) {
+ throw new IllegalStateException(
+ "Upgrade destination user type not defined: "
+ + userTypeUpgrade.getToType());
+ }
+
+ upgradeProfileToTypeLU(userData.info, newUserType);
+ userIdsToWrite.add(userData.info.id);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Changes the user type of a profile to a new user type.
+ * @param userInfo The user to be updated.
+ * @param newUserType The new user type.
+ */
+ @GuardedBy("mUsersLock")
+ @VisibleForTesting
+ void upgradeProfileToTypeLU(@NonNull UserInfo userInfo, @NonNull UserTypeDetails newUserType) {
+ Slog.i(LOG_TAG, "Upgrading user " + userInfo.id
+ + " from " + userInfo.userType
+ + " to " + newUserType.getName());
+
+ if (!userInfo.isProfile()) {
+ throw new IllegalStateException(
+ "Can only upgrade profile types. " + userInfo.userType
+ + " is not a profile type.");
+ }
+
+ // Exceeded maximum profiles for parent user: log error, but allow upgrade
+ if (!canAddMoreProfilesToUser(newUserType.getName(), userInfo.profileGroupId, false)) {
+ Slog.w(LOG_TAG,
+ "Exceeded maximum profiles of type " + newUserType.getName() + " for user "
+ + userInfo.id + ". Maximum allowed= "
+ + newUserType.getMaxAllowedPerParent());
+ }
+
+ final UserTypeDetails oldUserType = mUserTypes.get(userInfo.userType);
+ final int oldFlags;
+ if (oldUserType != null) {
+ oldFlags = oldUserType.getDefaultUserInfoFlags();
+ } else {
+ // if oldUserType is missing from config_user_types.xml -> can only assume FLAG_PROFILE
+ oldFlags = UserInfo.FLAG_PROFILE;
+ }
+
+ //convert userData to newUserType
+ userInfo.userType = newUserType.getName();
+ // remove old default flags and add newUserType's default flags
+ userInfo.flags = newUserType.getDefaultUserInfoFlags() | (userInfo.flags ^ oldFlags);
+
+ // merge existing base restrictions with the new type's default restrictions
+ synchronized (mRestrictionsLock) {
+ if (!UserRestrictionsUtils.isEmpty(newUserType.getDefaultRestrictions())) {
+ final Bundle newRestrictions = UserRestrictionsUtils.clone(
+ mBaseUserRestrictions.getRestrictions(userInfo.id));
+ UserRestrictionsUtils.merge(newRestrictions,
+ newUserType.getDefaultRestrictions());
+ updateUserRestrictionsInternalLR(newRestrictions, userInfo.id);
+ if (DBG) {
+ Slog.i(LOG_TAG, "Updated user " + userInfo.id
+ + " restrictions to " + newRestrictions);
+ }
+ }
+ }
+
+ // re-compute badge index
+ userInfo.profileBadge = getFreeProfileBadgeLU(userInfo.profileGroupId, userInfo.userType);
+ }
}
diff --git a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
index d0c3a95eafc7..0ac3030ba5dc 100644
--- a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
+++ b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
@@ -34,7 +34,6 @@ import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
-import android.provider.Settings.Global;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.util.Log;
@@ -670,15 +669,6 @@ public class UserRestrictionsUtils {
Settings.Secure.DOZE_DOUBLE_TAP_GESTURE, 0, userId);
}
break;
- case UserManager.DISALLOW_CONFIG_LOCATION:
- // When DISALLOW_CONFIG_LOCATION is set on any user, we undo the global
- // kill switch.
- if (newValue) {
- android.provider.Settings.Global.putString(
- context.getContentResolver(),
- Global.LOCATION_GLOBAL_KILL_SWITCH, "0");
- }
- break;
case UserManager.DISALLOW_APPS_CONTROL:
// Intentional fall-through
case UserManager.DISALLOW_UNINSTALL_APPS:
@@ -774,14 +764,6 @@ public class UserRestrictionsUtils {
restriction = UserManager.DISALLOW_AMBIENT_DISPLAY;
break;
- case android.provider.Settings.Global.LOCATION_GLOBAL_KILL_SWITCH:
- if ("0".equals(value)) {
- return false;
- }
- restriction = UserManager.DISALLOW_CONFIG_LOCATION;
- checkAllUser = true;
- break;
-
case android.provider.Settings.System.SCREEN_BRIGHTNESS:
case android.provider.Settings.System.SCREEN_BRIGHTNESS_FLOAT:
case android.provider.Settings.System.SCREEN_BRIGHTNESS_MODE:
diff --git a/services/core/java/com/android/server/pm/UserTypeDetails.java b/services/core/java/com/android/server/pm/UserTypeDetails.java
index d840e5d8b882..5fa46b9e4635 100644
--- a/services/core/java/com/android/server/pm/UserTypeDetails.java
+++ b/services/core/java/com/android/server/pm/UserTypeDetails.java
@@ -174,6 +174,9 @@ public final class UserTypeDetails {
/**
* Returns the maximum number of this user type allowed per parent (for user types, like
* profiles, that have parents).
+ * Under certain circumstances (such as after a change-user-type) the max value can actually
+ * be exceeded: this is allowed in order to keep the device in a usable state.
+ * An error is logged in {@link UserManagerService#upgradeProfileToTypeLU}
* <p>Returns {@link #UNLIMITED_NUMBER_OF_USERS} to indicate that there is no hard limit.
*/
public int getMaxAllowedPerParent() {
diff --git a/services/core/java/com/android/server/pm/UserTypeFactory.java b/services/core/java/com/android/server/pm/UserTypeFactory.java
index ba8a2ba6a14e..1d3aecdca8dd 100644
--- a/services/core/java/com/android/server/pm/UserTypeFactory.java
+++ b/services/core/java/com/android/server/pm/UserTypeFactory.java
@@ -49,6 +49,7 @@ import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
import java.util.ArrayList;
+import java.util.List;
import java.util.function.Consumer;
/**
@@ -73,14 +74,7 @@ public final class UserTypeFactory {
* @return mapping from the name of each user type to its {@link UserTypeDetails} object
*/
public static ArrayMap<String, UserTypeDetails> getUserTypes() {
- final ArrayMap<String, UserTypeDetails.Builder> builders = new ArrayMap<>();
- builders.put(USER_TYPE_PROFILE_MANAGED, getDefaultTypeProfileManaged());
- builders.put(USER_TYPE_FULL_SYSTEM, getDefaultTypeFullSystem());
- builders.put(USER_TYPE_FULL_SECONDARY, getDefaultTypeFullSecondary());
- builders.put(USER_TYPE_FULL_GUEST, getDefaultTypeFullGuest());
- builders.put(USER_TYPE_FULL_DEMO, getDefaultTypeFullDemo());
- builders.put(USER_TYPE_FULL_RESTRICTED, getDefaultTypeFullRestricted());
- builders.put(USER_TYPE_SYSTEM_HEADLESS, getDefaultTypeSystemHeadless());
+ final ArrayMap<String, UserTypeDetails.Builder> builders = getDefaultBuilders();
try (XmlResourceParser parser =
Resources.getSystem().getXml(com.android.internal.R.xml.config_user_types)) {
@@ -94,6 +88,20 @@ public final class UserTypeFactory {
return types;
}
+ private static ArrayMap<String, UserTypeDetails.Builder> getDefaultBuilders() {
+ final ArrayMap<String, UserTypeDetails.Builder> builders = new ArrayMap<>();
+
+ builders.put(USER_TYPE_PROFILE_MANAGED, getDefaultTypeProfileManaged());
+ builders.put(USER_TYPE_FULL_SYSTEM, getDefaultTypeFullSystem());
+ builders.put(USER_TYPE_FULL_SECONDARY, getDefaultTypeFullSecondary());
+ builders.put(USER_TYPE_FULL_GUEST, getDefaultTypeFullGuest());
+ builders.put(USER_TYPE_FULL_DEMO, getDefaultTypeFullDemo());
+ builders.put(USER_TYPE_FULL_RESTRICTED, getDefaultTypeFullRestricted());
+ builders.put(USER_TYPE_SYSTEM_HEADLESS, getDefaultTypeSystemHeadless());
+
+ return builders;
+ }
+
/**
* Returns the Builder for the default {@link UserManager#USER_TYPE_PROFILE_MANAGED}
* configuration.
@@ -232,6 +240,10 @@ public final class UserTypeFactory {
isProfile = true;
} else if ("full-type".equals(elementName)) {
isProfile = false;
+ } else if ("change-user-type".equals(elementName)) {
+ // parsed in parseUserUpgrades
+ XmlUtils.skipCurrentTag(parser);
+ continue;
} else {
Slog.w(LOG_TAG, "Skipping unknown element " + elementName + " in "
+ parser.getPositionDescription());
@@ -291,7 +303,8 @@ public final class UserTypeFactory {
while (XmlUtils.nextElementWithin(parser, depth)) {
final String childName = parser.getName();
if ("default-restrictions".equals(childName)) {
- final Bundle restrictions = UserRestrictionsUtils.readRestrictions(parser);
+ final Bundle restrictions = UserRestrictionsUtils
+ .readRestrictions(XmlUtils.makeTyped(parser));
builder.setDefaultRestrictions(restrictions);
} else if (isProfile && "badge-labels".equals(childName)) {
setResAttributeArray(parser, builder::setBadgeLabels);
@@ -387,4 +400,132 @@ public final class UserTypeFactory {
}
fcn.accept(result);
}
+
+ /**
+ * Returns the user type version of the config XML file.
+ * @return user type version defined in XML file, 0 if none.
+ */
+ public static int getUserTypeVersion() {
+ try (XmlResourceParser parser =
+ Resources.getSystem().getXml(com.android.internal.R.xml.config_user_types)) {
+ return getUserTypeVersion(parser);
+ }
+ }
+
+ @VisibleForTesting
+ static int getUserTypeVersion(XmlResourceParser parser) {
+ int version = 0;
+
+ try {
+ XmlUtils.beginDocument(parser, "user-types");
+ String versionValue = parser.getAttributeValue(null, "version");
+ if (versionValue != null) {
+ try {
+ version = Integer.parseInt(versionValue);
+ } catch (NumberFormatException e) {
+ Slog.e(LOG_TAG, "Cannot parse value of '" + versionValue + "' for version in "
+ + parser.getPositionDescription(), e);
+ throw e;
+ }
+ }
+ } catch (XmlPullParserException | IOException e) {
+ Slog.w(LOG_TAG, "Cannot read user type configuration file.", e);
+ }
+
+ return version;
+ }
+
+ /**
+ * Obtains the user type upgrades for this device.
+ * @return The list of user type upgrades.
+ */
+ public static List<UserTypeUpgrade> getUserTypeUpgrades() {
+ final List<UserTypeUpgrade> userUpgrades;
+ try (XmlResourceParser parser =
+ Resources.getSystem().getXml(com.android.internal.R.xml.config_user_types)) {
+ userUpgrades = parseUserUpgrades(getDefaultBuilders(), parser);
+ }
+ return userUpgrades;
+ }
+
+ @VisibleForTesting
+ static List<UserTypeUpgrade> parseUserUpgrades(
+ ArrayMap<String, UserTypeDetails.Builder> builders, XmlResourceParser parser) {
+ final List<UserTypeUpgrade> userUpgrades = new ArrayList<>();
+
+ try {
+ XmlUtils.beginDocument(parser, "user-types");
+ for (XmlUtils.nextElement(parser);
+ parser.getEventType() != XmlResourceParser.END_DOCUMENT;
+ XmlUtils.nextElement(parser)) {
+ final String elementName = parser.getName();
+ if ("change-user-type".equals(elementName)) {
+ final String fromType = parser.getAttributeValue(null, "from");
+ final String toType = parser.getAttributeValue(null, "to");
+ // Check that the base type doesn't change.
+ // Currently, only the base type of PROFILE is supported.
+ validateUserTypeIsProfile(fromType, builders);
+ validateUserTypeIsProfile(toType, builders);
+
+ final int maxVersionToConvert;
+ try {
+ maxVersionToConvert = Integer.parseInt(
+ parser.getAttributeValue(null, "whenVersionLeq"));
+ } catch (NumberFormatException e) {
+ Slog.e(LOG_TAG, "Cannot parse value of whenVersionLeq in "
+ + parser.getPositionDescription(), e);
+ throw e;
+ }
+
+ UserTypeUpgrade userTypeUpgrade = new UserTypeUpgrade(fromType, toType,
+ maxVersionToConvert);
+ userUpgrades.add(userTypeUpgrade);
+ continue;
+ } else {
+ XmlUtils.skipCurrentTag(parser);
+ continue;
+ }
+ }
+ } catch (XmlPullParserException | IOException e) {
+ Slog.w(LOG_TAG, "Cannot read user type configuration file.", e);
+ }
+
+ return userUpgrades;
+ }
+
+ private static void validateUserTypeIsProfile(String userType,
+ ArrayMap<String, UserTypeDetails.Builder> builders) {
+ UserTypeDetails.Builder builder = builders.get(userType);
+ if (builder != null && builder.getBaseType() != FLAG_PROFILE) {
+ throw new IllegalArgumentException("Illegal upgrade of user type " + userType
+ + " : Can only upgrade profiles user types");
+ }
+ }
+
+ /**
+ * Contains details required for an upgrade operation for {@link UserTypeDetails};
+ */
+ public static class UserTypeUpgrade {
+ private final String mFromType;
+ private final String mToType;
+ private final int mUpToVersion;
+
+ public UserTypeUpgrade(String fromType, String toType, int upToVersion) {
+ mFromType = fromType;
+ mToType = toType;
+ mUpToVersion = upToVersion;
+ }
+
+ public String getFromType() {
+ return mFromType;
+ }
+
+ public String getToType() {
+ return mToType;
+ }
+
+ public int getUpToVersion() {
+ return mUpToVersion;
+ }
+ }
}
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 e5c93a32ae90..165647205a98 100644
--- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
@@ -63,6 +63,7 @@ import android.util.SparseArray;
import android.util.TypedXmlPullParser;
import android.util.Xml;
+import com.android.internal.R;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.XmlUtils;
import com.android.server.LocalServices;
@@ -72,7 +73,6 @@ import com.android.server.pm.permission.PermissionManagerServiceInternal.SyncAda
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
-import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
@@ -766,9 +766,14 @@ public final class DefaultPermissionGrantPolicy {
grantSystemFixedPermissionsToSystemPackage(pm, wearPackage, userId, PHONE_PERMISSIONS);
// Fitness tracking on watches
- grantPermissionsToSystemPackage(pm,
+ if (mContext.getResources().getBoolean(R.bool.config_trackerAppNeedsPermissions)) {
+ Log.d(TAG, "Wear: Skipping permission grant for Default fitness tracker app : "
+ + wearPackage);
+ } else {
+ grantPermissionsToSystemPackage(pm,
getDefaultSystemHandlerActivityPackage(pm, ACTION_TRACK, userId), userId,
SENSORS_PERMISSIONS, ALWAYS_LOCATION_PERMISSIONS);
+ }
}
// Print Spooler
@@ -1408,11 +1413,8 @@ public final class DefaultPermissionGrantPolicy {
Slog.w(TAG, "Default permissions file " + file + " cannot be read");
continue;
}
- try (
- InputStream str = new BufferedInputStream(new FileInputStream(file))
- ) {
- TypedXmlPullParser parser = Xml.newFastPullParser();
- parser.setInput(str, null);
+ try (InputStream str = new FileInputStream(file)) {
+ TypedXmlPullParser parser = Xml.resolvePullParser(str);
parse(pm, parser, grantExceptions);
} catch (XmlPullParserException | IOException e) {
Slog.w(TAG, "Error reading default permissions file " + file, e);
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index fb1ed2f6b58b..52bb3d772387 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -205,6 +205,9 @@ public class PermissionManagerService extends IPermissionManager.Stub {
private static final int USER_PERMISSION_FLAGS = FLAG_PERMISSION_USER_SET
| FLAG_PERMISSION_USER_FIXED;
+ /** All storage permissions */
+ private static final List<String> STORAGE_PERMISSIONS = new ArrayList<>();
+
/** If the permission of the value is granted, so is the key */
private static final Map<String, String> FULLER_PERMISSION_MAP = new HashMap<>();
@@ -213,6 +216,9 @@ public class PermissionManagerService extends IPermissionManager.Stub {
Manifest.permission.ACCESS_FINE_LOCATION);
FULLER_PERMISSION_MAP.put(Manifest.permission.INTERACT_ACROSS_USERS,
Manifest.permission.INTERACT_ACROSS_USERS_FULL);
+ STORAGE_PERMISSIONS.add(Manifest.permission.READ_EXTERNAL_STORAGE);
+ STORAGE_PERMISSIONS.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
+ STORAGE_PERMISSIONS.add(Manifest.permission.ACCESS_MEDIA_LOCATION);
}
/** Lock to protect internal data access */
@@ -1243,47 +1249,53 @@ public class PermissionManagerService extends IPermissionManager.Stub {
final long identity = Binder.clearCallingIdentity();
try {
- synchronized (mLock) {
- final UidPermissionState uidState = getUidStateLocked(pkg, userId);
- if (uidState == null) {
- Slog.e(TAG, "Missing permissions state for " + packageName + " and user "
- + userId);
- return null;
- }
+ return getAllowlistedRestrictedPermissionsInternal(pkg, flags, userId);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
- int queryFlags = 0;
- if ((flags & PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM) != 0) {
- queryFlags |= FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT;
- }
- if ((flags & PackageManager.FLAG_PERMISSION_WHITELIST_UPGRADE) != 0) {
- queryFlags |= FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT;
- }
- if ((flags & PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER) != 0) {
- queryFlags |= FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT;
- }
- if ((flags & PackageManager.FLAG_PERMISSION_ALLOWLIST_ROLE) != 0) {
- queryFlags |= FLAG_PERMISSION_RESTRICTION_ROLE_EXEMPT;
- }
+ @Nullable
+ private List<String> getAllowlistedRestrictedPermissionsInternal(@NonNull AndroidPackage pkg,
+ @PermissionWhitelistFlags int flags, @UserIdInt int userId) {
+ synchronized (mLock) {
+ final UidPermissionState uidState = getUidStateLocked(pkg, userId);
+ if (uidState == null) {
+ Slog.e(TAG, "Missing permissions state for " + pkg.getPackageName() + " and user "
+ + userId);
+ return null;
+ }
- ArrayList<String> whitelistedPermissions = null;
+ int queryFlags = 0;
+ if ((flags & PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM) != 0) {
+ queryFlags |= FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT;
+ }
+ if ((flags & PackageManager.FLAG_PERMISSION_WHITELIST_UPGRADE) != 0) {
+ queryFlags |= FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT;
+ }
+ if ((flags & PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER) != 0) {
+ queryFlags |= FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT;
+ }
+ if ((flags & PackageManager.FLAG_PERMISSION_ALLOWLIST_ROLE) != 0) {
+ queryFlags |= FLAG_PERMISSION_RESTRICTION_ROLE_EXEMPT;
+ }
- final int permissionCount = ArrayUtils.size(pkg.getRequestedPermissions());
- for (int i = 0; i < permissionCount; i++) {
- final String permissionName = pkg.getRequestedPermissions().get(i);
- final int currentFlags =
- uidState.getPermissionFlags(permissionName);
- if ((currentFlags & queryFlags) != 0) {
- if (whitelistedPermissions == null) {
- whitelistedPermissions = new ArrayList<>();
- }
- whitelistedPermissions.add(permissionName);
+ ArrayList<String> allowlistedPermissions = null;
+
+ final int permissionCount = ArrayUtils.size(pkg.getRequestedPermissions());
+ for (int i = 0; i < permissionCount; i++) {
+ final String permissionName = pkg.getRequestedPermissions().get(i);
+ final int currentFlags =
+ uidState.getPermissionFlags(permissionName);
+ if ((currentFlags & queryFlags) != 0) {
+ if (allowlistedPermissions == null) {
+ allowlistedPermissions = new ArrayList<>();
}
+ allowlistedPermissions.add(permissionName);
}
-
- return whitelistedPermissions;
}
- } finally {
- Binder.restoreCallingIdentity(identity);
+
+ return allowlistedPermissions;
}
}
@@ -1429,8 +1441,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
final long identity = Binder.clearCallingIdentity();
try {
- setAllowlistedRestrictedPermissionsInternal(pkg, permissions, flags,
- new int[] { userId });
+ setAllowlistedRestrictedPermissionsInternal(pkg, permissions, flags, userId);
} finally {
Binder.restoreCallingIdentity(identity);
}
@@ -1453,13 +1464,6 @@ public class PermissionManagerService extends IPermissionManager.Stub {
return setAutoRevokeExemptedInternal(pkg, whitelisted, userId);
}
- private void setAutoRevokeExemptedInternal(@NonNull AndroidPackage pkg, boolean exempted,
- @NonNull int[] userIds) {
- for (final int userId : userIds) {
- setAutoRevokeExemptedInternal(pkg, exempted, userId);
- }
- }
-
private boolean setAutoRevokeExemptedInternal(@NonNull AndroidPackage pkg, boolean exempted,
@UserIdInt int userId) {
final int packageUid = UserHandle.getUid(userId, pkg.getUid());
@@ -2358,6 +2362,48 @@ public class PermissionManagerService extends IPermissionManager.Stub {
}
/**
+ * If the app is updated, and has scoped storage permissions, then it is possible that the
+ * app updated in an attempt to get unscoped storage. If so, revoke all storage permissions.
+ * @param newPackage The new package that was installed
+ * @param oldPackage The old package that was updated
+ */
+ private void revokeStoragePermissionsIfScopeExpandedInternal(
+ @NonNull AndroidPackage newPackage,
+ @NonNull AndroidPackage oldPackage) {
+ boolean downgradedSdk = oldPackage.getTargetSdkVersion() >= Build.VERSION_CODES.Q
+ && newPackage.getTargetSdkVersion() < Build.VERSION_CODES.Q;
+ boolean upgradedSdk = oldPackage.getTargetSdkVersion() < Build.VERSION_CODES.Q
+ && newPackage.getTargetSdkVersion() >= Build.VERSION_CODES.Q;
+ boolean newlyRequestsLegacy = !upgradedSdk && !oldPackage.isRequestLegacyExternalStorage()
+ && newPackage.isRequestLegacyExternalStorage();
+
+ if (!newlyRequestsLegacy && !downgradedSdk) {
+ return;
+ }
+
+ final int callingUid = Binder.getCallingUid();
+ final int userId = UserHandle.getUserId(newPackage.getUid());
+ int numRequestedPermissions = newPackage.getRequestedPermissions().size();
+ for (int i = 0; i < numRequestedPermissions; i++) {
+ PermissionInfo permInfo = getPermissionInfo(newPackage.getRequestedPermissions().get(i),
+ newPackage.getPackageName(), 0);
+ if (permInfo == null || !STORAGE_PERMISSIONS.contains(permInfo.name)) {
+ continue;
+ }
+
+ EventLog.writeEvent(0x534e4554, "171430330", newPackage.getUid(),
+ "Revoking permission " + permInfo.name + " from package "
+ + newPackage.getPackageName() + " as either the sdk downgraded "
+ + downgradedSdk + " or newly requested legacy full storage "
+ + newlyRequestsLegacy);
+
+ revokeRuntimePermissionInternal(permInfo.name, newPackage.getPackageName(),
+ false, callingUid, userId, null, mDefaultPermissionCallback);
+ }
+
+ }
+
+ /**
* We might auto-grant permissions if any permission of the group is already granted. Hence if
* the group of a granted permission changes we need to revoke it to avoid having permissions of
* the new group auto-granted.
@@ -3775,13 +3821,6 @@ public class PermissionManagerService extends IPermissionManager.Stub {
}
private void grantRequestedRuntimePermissionsInternal(@NonNull AndroidPackage pkg,
- @Nullable List<String> permissions, @NonNull int[] userIds) {
- for (int userId : userIds) {
- grantRequestedRuntimePermissionsForUser(pkg, permissions, userId);
- }
- }
-
- private void grantRequestedRuntimePermissionsForUser(@NonNull AndroidPackage pkg,
@Nullable List<String> permissions, int userId) {
final int immutableFlags = PackageManager.FLAG_PERMISSION_SYSTEM_FIXED
| PackageManager.FLAG_PERMISSION_POLICY_FIXED;
@@ -3828,123 +3867,119 @@ public class PermissionManagerService extends IPermissionManager.Stub {
private void setAllowlistedRestrictedPermissionsInternal(@NonNull AndroidPackage pkg,
@Nullable List<String> permissions, @PermissionWhitelistFlags int allowlistFlags,
- @UserIdInt int[] userIds) {
- SparseArray<ArraySet<String>> oldGrantedRestrictedPermissions = new SparseArray<>();
+ @UserIdInt int userId) {
+ ArraySet<String> oldGrantedRestrictedPermissions = null;
boolean updatePermissions = false;
final int permissionCount = pkg.getRequestedPermissions().size();
final int myUid = Process.myUid();
- for (int i = 0; i < userIds.length; i++) {
- int userId = userIds[i];
-
- for (int j = 0; j < permissionCount; j++) {
- final String permissionName = pkg.getRequestedPermissions().get(j);
-
- final boolean isGranted;
- synchronized (mLock) {
- final Permission bp = mRegistry.getPermission(permissionName);
- if (bp == null || !bp.isHardOrSoftRestricted()) {
- continue;
- }
+ for (int j = 0; j < permissionCount; j++) {
+ final String permissionName = pkg.getRequestedPermissions().get(j);
- final UidPermissionState uidState = getUidStateLocked(pkg, userId);
- if (uidState == null) {
- Slog.e(TAG, "Missing permissions state for " + pkg.getPackageName()
- + " and user " + userId);
- continue;
- }
- isGranted = uidState.isPermissionGranted(permissionName);
+ final boolean isGranted;
+ synchronized (mLock) {
+ final Permission bp = mRegistry.getPermission(permissionName);
+ if (bp == null || !bp.isHardOrSoftRestricted()) {
+ continue;
}
- if (isGranted) {
- if (oldGrantedRestrictedPermissions.get(userId) == null) {
- oldGrantedRestrictedPermissions.put(userId, new ArraySet<>());
- }
- oldGrantedRestrictedPermissions.get(userId).add(permissionName);
+ final UidPermissionState uidState = getUidStateLocked(pkg, userId);
+ if (uidState == null) {
+ Slog.e(TAG, "Missing permissions state for " + pkg.getPackageName()
+ + " and user " + userId);
+ continue;
}
+ isGranted = uidState.isPermissionGranted(permissionName);
+ }
- final int oldFlags = getPermissionFlagsInternal(permissionName,
- pkg.getPackageName(), myUid, userId);
-
- int newFlags = oldFlags;
- int mask = 0;
- int whitelistFlagsCopy = allowlistFlags;
- while (whitelistFlagsCopy != 0) {
- final int flag = 1 << Integer.numberOfTrailingZeros(whitelistFlagsCopy);
- whitelistFlagsCopy &= ~flag;
- switch (flag) {
- case FLAG_PERMISSION_WHITELIST_SYSTEM: {
- mask |= FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT;
- if (permissions != null && permissions.contains(permissionName)) {
- newFlags |= FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT;
- } else {
- newFlags &= ~FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT;
- }
+ if (isGranted) {
+ if (oldGrantedRestrictedPermissions == null) {
+ oldGrantedRestrictedPermissions = new ArraySet<>();
+ }
+ oldGrantedRestrictedPermissions.add(permissionName);
+ }
+
+ final int oldFlags = getPermissionFlagsInternal(permissionName,
+ pkg.getPackageName(), myUid, userId);
+
+ int newFlags = oldFlags;
+ int mask = 0;
+ int whitelistFlagsCopy = allowlistFlags;
+ while (whitelistFlagsCopy != 0) {
+ final int flag = 1 << Integer.numberOfTrailingZeros(whitelistFlagsCopy);
+ whitelistFlagsCopy &= ~flag;
+ switch (flag) {
+ case FLAG_PERMISSION_WHITELIST_SYSTEM: {
+ mask |= FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT;
+ if (permissions != null && permissions.contains(permissionName)) {
+ newFlags |= FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT;
+ } else {
+ newFlags &= ~FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT;
}
- break;
- case FLAG_PERMISSION_WHITELIST_UPGRADE: {
- mask |= FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT;
- if (permissions != null && permissions.contains(permissionName)) {
- newFlags |= FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT;
- } else {
- newFlags &= ~FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT;
- }
+ }
+ break;
+ case FLAG_PERMISSION_WHITELIST_UPGRADE: {
+ mask |= FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT;
+ if (permissions != null && permissions.contains(permissionName)) {
+ newFlags |= FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT;
+ } else {
+ newFlags &= ~FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT;
}
- break;
- case FLAG_PERMISSION_WHITELIST_INSTALLER: {
- mask |= FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT;
- if (permissions != null && permissions.contains(permissionName)) {
- newFlags |= FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT;
- } else {
- newFlags &= ~FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT;
- }
+ }
+ break;
+ case FLAG_PERMISSION_WHITELIST_INSTALLER: {
+ mask |= FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT;
+ if (permissions != null && permissions.contains(permissionName)) {
+ newFlags |= FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT;
+ } else {
+ newFlags &= ~FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT;
}
- break;
- case FLAG_PERMISSION_ALLOWLIST_ROLE: {
- mask |= FLAG_PERMISSION_RESTRICTION_ROLE_EXEMPT;
- if (permissions != null && permissions.contains(permissionName)) {
- newFlags |= FLAG_PERMISSION_RESTRICTION_ROLE_EXEMPT;
- } else {
- newFlags &= ~FLAG_PERMISSION_RESTRICTION_ROLE_EXEMPT;
- }
+ }
+ break;
+ case FLAG_PERMISSION_ALLOWLIST_ROLE: {
+ mask |= FLAG_PERMISSION_RESTRICTION_ROLE_EXEMPT;
+ if (permissions != null && permissions.contains(permissionName)) {
+ newFlags |= FLAG_PERMISSION_RESTRICTION_ROLE_EXEMPT;
+ } else {
+ newFlags &= ~FLAG_PERMISSION_RESTRICTION_ROLE_EXEMPT;
}
- break;
}
+ break;
}
+ }
- if (oldFlags == newFlags) {
- continue;
- }
+ if (oldFlags == newFlags) {
+ continue;
+ }
- updatePermissions = true;
-
- final boolean wasWhitelisted = (oldFlags
- & (PackageManager.FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT)) != 0;
- final boolean isWhitelisted = (newFlags
- & (PackageManager.FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT)) != 0;
-
- // If the permission is policy fixed as granted but it is no longer
- // on any of the whitelists we need to clear the policy fixed flag
- // as whitelisting trumps policy i.e. policy cannot grant a non
- // grantable permission.
- if ((oldFlags & PackageManager.FLAG_PERMISSION_POLICY_FIXED) != 0) {
- if (!isWhitelisted && isGranted) {
- mask |= PackageManager.FLAG_PERMISSION_POLICY_FIXED;
- newFlags &= ~PackageManager.FLAG_PERMISSION_POLICY_FIXED;
- }
- }
+ updatePermissions = true;
+
+ final boolean wasWhitelisted = (oldFlags
+ & (PackageManager.FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT)) != 0;
+ final boolean isWhitelisted = (newFlags
+ & (PackageManager.FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT)) != 0;
- // If we are whitelisting an app that does not support runtime permissions
- // we need to make sure it goes through the permission review UI at launch.
- if (pkg.getTargetSdkVersion() < Build.VERSION_CODES.M
- && !wasWhitelisted && isWhitelisted) {
- mask |= PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED;
- newFlags |= PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED;
+ // If the permission is policy fixed as granted but it is no longer
+ // on any of the whitelists we need to clear the policy fixed flag
+ // as whitelisting trumps policy i.e. policy cannot grant a non
+ // grantable permission.
+ if ((oldFlags & PackageManager.FLAG_PERMISSION_POLICY_FIXED) != 0) {
+ if (!isWhitelisted && isGranted) {
+ mask |= PackageManager.FLAG_PERMISSION_POLICY_FIXED;
+ newFlags &= ~PackageManager.FLAG_PERMISSION_POLICY_FIXED;
}
+ }
- updatePermissionFlagsInternal(permissionName, pkg.getPackageName(), mask, newFlags,
- myUid, userId, false, null /*callback*/);
+ // If we are whitelisting an app that does not support runtime permissions
+ // we need to make sure it goes through the permission review UI at launch.
+ if (pkg.getTargetSdkVersion() < Build.VERSION_CODES.M
+ && !wasWhitelisted && isWhitelisted) {
+ mask |= PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED;
+ newFlags |= PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED;
}
+
+ updatePermissionFlagsInternal(permissionName, pkg.getPackageName(), mask, newFlags,
+ myUid, userId, false, null /*callback*/);
}
if (updatePermissions) {
@@ -3952,31 +3987,27 @@ public class PermissionManagerService extends IPermissionManager.Stub {
restorePermissionState(pkg, false, pkg.getPackageName(), mDefaultPermissionCallback);
// If this resulted in losing a permission we need to kill the app.
- for (int i = 0; i < userIds.length; i++) {
- int userId = userIds[i];
- ArraySet<String> oldPermsForUser = oldGrantedRestrictedPermissions.get(userId);
- if (oldPermsForUser == null) {
- continue;
- }
+ if (oldGrantedRestrictedPermissions == null) {
+ return;
+ }
- final int oldGrantedCount = oldPermsForUser.size();
- for (int j = 0; j < oldGrantedCount; j++) {
- final String permissionName = oldPermsForUser.valueAt(j);
- // Sometimes we create a new permission state instance during update.
- final boolean isGranted;
- synchronized (mLock) {
- final UidPermissionState uidState = getUidStateLocked(pkg, userId);
- if (uidState == null) {
- Slog.e(TAG, "Missing permissions state for " + pkg.getPackageName()
- + " and user " + userId);
- continue;
- }
- isGranted = uidState.isPermissionGranted(permissionName);
- }
- if (!isGranted) {
- mDefaultPermissionCallback.onPermissionRevoked(pkg.getUid(), userId, null);
- break;
+ final int oldGrantedCount = oldGrantedRestrictedPermissions.size();
+ for (int j = 0; j < oldGrantedCount; j++) {
+ final String permissionName = oldGrantedRestrictedPermissions.valueAt(j);
+ // Sometimes we create a new permission state instance during update.
+ final boolean isGranted;
+ synchronized (mLock) {
+ final UidPermissionState uidState = getUidStateLocked(pkg, userId);
+ if (uidState == null) {
+ Slog.e(TAG, "Missing permissions state for " + pkg.getPackageName()
+ + " and user " + userId);
+ continue;
}
+ isGranted = uidState.isPermissionGranted(permissionName);
+ }
+ if (!isGranted) {
+ mDefaultPermissionCallback.onPermissionRevoked(pkg.getUid(), userId, null);
+ break;
}
}
}
@@ -4884,6 +4915,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
AsyncTask.execute(() -> {
if (hasOldPkg) {
revokeRuntimePermissionsIfGroupChangedInternal(pkg, oldPkg);
+ revokeStoragePermissionsIfScopeExpandedInternal(pkg, oldPkg);
}
if (hasPermissionDefinitionChanges) {
revokeRuntimePermissionsIfPermissionDefinitionChangedInternal(
@@ -4914,6 +4946,34 @@ public class PermissionManagerService extends IPermissionManager.Stub {
return true;
}
+ private void onPackageInstalledInternal(@NonNull AndroidPackage pkg,
+ @NonNull List<String> grantedPermissions,
+ @NonNull List<String> allowlistedRestrictedPermissions, int autoRevokePermissionsMode,
+ @UserIdInt int userId) {
+ addAllowlistedRestrictedPermissionsInternal(pkg, allowlistedRestrictedPermissions,
+ FLAG_PERMISSION_WHITELIST_INSTALLER, userId);
+ if (autoRevokePermissionsMode == AppOpsManager.MODE_ALLOWED
+ || autoRevokePermissionsMode == AppOpsManager.MODE_IGNORED) {
+ setAutoRevokeExemptedInternal(pkg,
+ autoRevokePermissionsMode == AppOpsManager.MODE_IGNORED, userId);
+ }
+ grantRequestedRuntimePermissionsInternal(pkg, grantedPermissions, userId);
+ }
+
+ private void addAllowlistedRestrictedPermissionsInternal(@NonNull AndroidPackage pkg,
+ @NonNull List<String> allowlistedRestrictedPermissions,
+ @PermissionWhitelistFlags int flags, @UserIdInt int userId) {
+ List<String> permissions = getAllowlistedRestrictedPermissionsInternal(pkg, flags, userId);
+ if (permissions != null) {
+ ArraySet<String> permissionSet = new ArraySet<>(permissions);
+ permissionSet.addAll(allowlistedRestrictedPermissions);
+ permissions = new ArrayList<>(permissionSet);
+ } else {
+ permissions = allowlistedRestrictedPermissions;
+ }
+ setAllowlistedRestrictedPermissionsInternal(pkg, permissions, flags, userId);
+ }
+
private void onPackageRemovedInternal(@NonNull AndroidPackage pkg) {
removeAllPermissionsInternal(pkg);
}
@@ -5080,28 +5140,6 @@ public class PermissionManagerService extends IPermissionManager.Stub {
return PermissionManagerService.this.getAppOpPermissionPackagesInternal(permissionName);
}
@Override
- public void grantRequestedRuntimePermissions(@NonNull AndroidPackage pkg,
- @Nullable List<String> permissions, @NonNull int[] userIds) {
- Objects.requireNonNull(pkg, "pkg");
- Objects.requireNonNull(userIds, "userIds");
- grantRequestedRuntimePermissionsInternal(pkg, permissions, userIds);
- }
- @Override
- public void setAllowlistedRestrictedPermissions(@NonNull AndroidPackage pkg,
- @Nullable List<String> permissions, @PermissionWhitelistFlags int allowlistFlags,
- @NonNull int[] userIds) {
- Objects.requireNonNull(pkg, "pkg");
- Objects.requireNonNull(userIds, "userIds");
- setAllowlistedRestrictedPermissionsInternal(pkg, permissions, allowlistFlags, userIds);
- }
- @Override
- public void setAutoRevokeExempted(@NonNull AndroidPackage pkg, boolean exempted,
- @NonNull int[] userIds) {
- Objects.requireNonNull(pkg, "pkg");
- Objects.requireNonNull(userIds, "userIds");
- setAutoRevokeExemptedInternal(pkg, exempted, userIds);
- }
- @Override
public void updatePermissions(@NonNull String packageName, @Nullable AndroidPackage pkg) {
PermissionManagerService.this
.updatePermissions(packageName, pkg, mDefaultPermissionCallback);
@@ -5372,6 +5410,20 @@ public class PermissionManagerService extends IPermissionManager.Stub {
}
@Override
+ public void onPackageInstalled(@NonNull AndroidPackage pkg,
+ @NonNull List<String> grantedPermissions,
+ @NonNull List<String> allowlistedRestrictedPermissions,
+ int autoRevokePermissionsMode, @UserIdInt int userId) {
+ Objects.requireNonNull(pkg, "pkg");
+ Objects.requireNonNull(grantedPermissions, "grantedPermissions");
+ Objects.requireNonNull(allowlistedRestrictedPermissions,
+ "allowlistedRestrictedPermissions");
+ Preconditions.checkArgumentNonNegative(userId, "userId");
+ onPackageInstalledInternal(pkg, grantedPermissions, allowlistedRestrictedPermissions,
+ autoRevokePermissionsMode, userId);
+ }
+
+ @Override
public void onPackageRemoved(@NonNull AndroidPackage pkg) {
Objects.requireNonNull(pkg);
onPackageRemovedInternal(pkg);
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
index 1becbedc29fb..457fe36ca2b8 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
@@ -20,7 +20,6 @@ import android.annotation.AppIdInt;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
-import android.content.pm.PackageManager;
import android.content.pm.PermissionInfo;
import android.permission.PermissionManagerInternal;
@@ -190,42 +189,6 @@ public abstract class PermissionManagerServiceInternal extends PermissionManager
@UserIdInt int userId);
/**
- * Grant the requested runtime permissions for a package, or an explicit subset of them.
- *
- * @param pkg the package
- * @param permissions the names of the subset of permissions to be granted, or {@code null} for
- * granting all the requested permissions
- * @param userIds the user IDs
- */
- //@SystemApi(client = SystemApi.Client.SYSTEM_SERVER)
- public abstract void grantRequestedRuntimePermissions(@NonNull AndroidPackage pkg,
- @Nullable List<String> permissions, @NonNull int[] userIds);
-
- /**
- * Set the allowlisted restricted permissions for a package, or an explicit subset of them.
- *
- * @param pkg the package
- * @param permissions the names of the subset of permissions to be allowlisted, or {@code null}
- * for allowlisting all the requested restricted permissions
- * @param userIds the user IDs
- */
- //@SystemApi(client = SystemApi.Client.SYSTEM_SERVER)
- public abstract void setAllowlistedRestrictedPermissions(
- @NonNull AndroidPackage pkg, @Nullable List<String> permissions,
- @PackageManager.PermissionWhitelistFlags int allowlistFlags, @NonNull int[] userIds);
-
- /**
- * Set whether a package is exempted from auto revoke.
- *
- * @param pkg the package
- * @param exempted whether the package is exempted from auto revoke
- * @param userIds the user IDs
- */
- //@SystemApi(client = SystemApi.Client.SYSTEM_SERVER)
- public abstract void setAutoRevokeExempted(@NonNull AndroidPackage pkg, boolean exempted,
- @NonNull int[] userIds);
-
- /**
* Update permissions when a package changed.
*
* <p><ol>
@@ -526,6 +489,21 @@ public abstract class PermissionManagerServiceInternal extends PermissionManager
@Nullable AndroidPackage oldPkg);
/**
+ * Callback when a package has been installed for certain users.
+ *
+ * @param pkg the installed package
+ * @param grantedPermissions the permissions to be granted
+ * @param allowlistedRestrictedPermissions the restricted permissions to be allowlisted
+ * @param autoRevokePermissionsMode the auto revoke permissions mode for this package
+ * @param userId the user ID this package is installed for
+ */
+ //@SystemApi(client = SystemApi.Client.SYSTEM_SERVER)
+ public abstract void onPackageInstalled(@NonNull AndroidPackage pkg,
+ @NonNull List<String> grantedPermissions,
+ @NonNull List<String> allowlistedRestrictedPermissions,
+ int autoRevokePermissionsMode, @UserIdInt int userId);
+
+ /**
* Callback when a package has been removed.
*
* @param pkg the removed package
diff --git a/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java b/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java
index dd287ca6ed00..1e4e0a6a04bc 100644
--- a/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java
+++ b/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java
@@ -224,10 +224,9 @@ public class BatterySaverController implements BatterySaverPolicyListener {
mFileUpdater = new FileUpdater(context);
mBatterySavingStats = batterySavingStats;
+ // TODO(79580230): remove plugin code and maybe screen on/off listeners?
// Initialize plugins.
- mPlugins = new Plugin[] {
- new BatterySaverLocationPlugin(mContext)
- };
+ mPlugins = new Plugin[0];
PowerManager.invalidatePowerSaveModeCaches();
}
diff --git a/services/core/java/com/android/server/power/batterysaver/BatterySaverLocationPlugin.java b/services/core/java/com/android/server/power/batterysaver/BatterySaverLocationPlugin.java
deleted file mode 100644
index a77d133f6c32..000000000000
--- a/services/core/java/com/android/server/power/batterysaver/BatterySaverLocationPlugin.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.power.batterysaver;
-
-import android.content.Context;
-import android.os.PowerManager;
-import android.provider.Settings;
-import android.provider.Settings.Global;
-import android.util.Slog;
-
-import com.android.server.power.batterysaver.BatterySaverController.Plugin;
-
-public class BatterySaverLocationPlugin implements Plugin {
- private static final String TAG = "BatterySaverLocationPlugin";
-
- private static final boolean DEBUG = BatterySaverController.DEBUG;
-
- private final Context mContext;
-
- public BatterySaverLocationPlugin(Context context) {
- mContext = context;
- }
-
- @Override
- public void onBatterySaverChanged(BatterySaverController caller) {
- if (DEBUG) {
- Slog.d(TAG, "onBatterySaverChanged");
- }
- updateLocationState(caller);
- }
-
- @Override
- public void onSystemReady(BatterySaverController caller) {
- if (DEBUG) {
- Slog.d(TAG, "onSystemReady");
- }
- updateLocationState(caller);
- }
-
- private void updateLocationState(BatterySaverController caller) {
- final boolean kill =
- (caller.getBatterySaverPolicy().getGpsMode()
- == PowerManager.LOCATION_MODE_ALL_DISABLED_WHEN_SCREEN_OFF)
- && !caller.isInteractive();
-
- if (DEBUG) {
- Slog.d(TAG, "Battery saver " + (kill ? "stopping" : "restoring") + " location.");
- }
- Settings.Global.putInt(mContext.getContentResolver(),
- Global.LOCATION_GLOBAL_KILL_SWITCH, kill ? 1 : 0);
- }
-}
diff --git a/services/core/java/com/android/server/powerstats/PowerStatsDataStorage.java b/services/core/java/com/android/server/powerstats/PowerStatsDataStorage.java
index 98293570507c..c9595c2eec2b 100644
--- a/services/core/java/com/android/server/powerstats/PowerStatsDataStorage.java
+++ b/services/core/java/com/android/server/powerstats/PowerStatsDataStorage.java
@@ -177,8 +177,28 @@ public class PowerStatsDataStorage {
// filename, so any files that don't match the current version number can be deleted.
File[] files = mDataStorageDir.listFiles();
for (int i = 0; i < files.length; i++) {
- if (!files[i].getName().matches(dataStorageFilename + "(.*)")) {
- files[i].delete();
+ // Meter and model files are stored in the same directory.
+ //
+ // The format of filenames on disk is:
+ // log.powerstats.meter.version.timestamp
+ // log.powerstats.model.version.timestamp
+ //
+ // The format of dataStorageFilenames is:
+ // log.powerstats.meter.version
+ // log.powerstats.model.version
+ //
+ // A PowerStatsDataStorage object is created for meter and model data. Strip off
+ // the version and check that the current file we're checking starts with the stem
+ // (log.powerstats.meter or log.powerstats.model). If the stem matches and the
+ // version number is different, delete the old file.
+ int versionDot = dataStorageFilename.lastIndexOf('.');
+ String beforeVersionDot = dataStorageFilename.substring(0, versionDot);
+ // Check that the stems match.
+ if (files[i].getName().startsWith(beforeVersionDot)) {
+ // Check that the version number matches. If not, delete the old file.
+ if (!files[i].getName().startsWith(dataStorageFilename)) {
+ files[i].delete();
+ }
}
}
diff --git a/services/core/java/com/android/server/role/RoleUserState.java b/services/core/java/com/android/server/role/RoleUserState.java
index b33dc8fab9a5..7751397d9c31 100644
--- a/services/core/java/com/android/server/role/RoleUserState.java
+++ b/services/core/java/com/android/server/role/RoleUserState.java
@@ -28,6 +28,7 @@ import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.AtomicFile;
import android.util.Slog;
+import android.util.TypedXmlPullParser;
import android.util.Xml;
import com.android.internal.annotations.GuardedBy;
@@ -391,8 +392,7 @@ public class RoleUserState {
private void readLegacyFileLocked() {
File file = getFile(mUserId);
try (FileInputStream in = new AtomicFile(file).openRead()) {
- XmlPullParser parser = Xml.newPullParser();
- parser.setInput(in, null);
+ TypedXmlPullParser parser = Xml.resolvePullParser(in);
parseXmlLocked(parser);
Slog.i(LOG_TAG, "Read roles.xml successfully");
} catch (FileNotFoundException e) {
@@ -402,7 +402,7 @@ public class RoleUserState {
}
}
- private void parseXmlLocked(@NonNull XmlPullParser parser) throws IOException,
+ private void parseXmlLocked(@NonNull TypedXmlPullParser parser) throws IOException,
XmlPullParserException {
int type;
int depth;
@@ -421,9 +421,9 @@ public class RoleUserState {
Slog.w(LOG_TAG, "Missing <" + TAG_ROLES + "> in roles.xml");
}
- private void parseRolesLocked(@NonNull XmlPullParser parser) throws IOException,
+ private void parseRolesLocked(@NonNull TypedXmlPullParser parser) throws IOException,
XmlPullParserException {
- mVersion = Integer.parseInt(parser.getAttributeValue(null, ATTRIBUTE_VERSION));
+ mVersion = parser.getAttributeInt(null, ATTRIBUTE_VERSION);
mPackagesHash = parser.getAttributeValue(null, ATTRIBUTE_PACKAGES_HASH);
mRoles.clear();
@@ -445,7 +445,7 @@ public class RoleUserState {
}
@NonNull
- private ArraySet<String> parseRoleHoldersLocked(@NonNull XmlPullParser parser)
+ private ArraySet<String> parseRoleHoldersLocked(@NonNull TypedXmlPullParser parser)
throws IOException, XmlPullParserException {
ArraySet<String> roleHolders = new ArraySet<>();
diff --git a/services/core/java/com/android/server/storage/CacheQuotaStrategy.java b/services/core/java/com/android/server/storage/CacheQuotaStrategy.java
index d2614e4698d1..4f3101dc318c 100644
--- a/services/core/java/com/android/server/storage/CacheQuotaStrategy.java
+++ b/services/core/java/com/android/server/storage/CacheQuotaStrategy.java
@@ -51,13 +51,10 @@ import android.util.TypedXmlSerializer;
import android.util.Xml;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.FastXmlSerializer;
-import com.android.internal.util.Preconditions;
import com.android.server.pm.Installer;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
import java.io.File;
import java.io.FileInputStream;
@@ -65,7 +62,6 @@ import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
-import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
@@ -319,12 +315,12 @@ public class CacheQuotaStrategy implements RemoteCallback.OnResultListener {
}
@VisibleForTesting
- static void saveToXml(XmlSerializer out,
+ static void saveToXml(TypedXmlSerializer out,
List<CacheQuotaHint> requests, long bytesWhenCalculated) throws IOException {
out.startDocument(null, true);
out.startTag(null, CACHE_INFO_TAG);
int requestSize = requests.size();
- out.attribute(null, ATTR_PREVIOUS_BYTES, Long.toString(bytesWhenCalculated));
+ out.attributeLong(null, ATTR_PREVIOUS_BYTES, bytesWhenCalculated);
for (int i = 0; i < requestSize; i++) {
CacheQuotaHint request = requests.get(i);
@@ -333,8 +329,8 @@ public class CacheQuotaStrategy implements RemoteCallback.OnResultListener {
if (uuid != null) {
out.attribute(null, ATTR_UUID, request.getVolumeUuid());
}
- out.attribute(null, ATTR_UID, Integer.toString(request.getUid()));
- out.attribute(null, ATTR_QUOTA_IN_BYTES, Long.toString(request.getQuota()));
+ out.attributeInt(null, ATTR_UID, request.getUid());
+ out.attributeLong(null, ATTR_QUOTA_IN_BYTES, request.getQuota());
out.endTag(null, TAG_QUOTA);
}
out.endTag(null, CACHE_INFO_TAG);
@@ -364,8 +360,7 @@ public class CacheQuotaStrategy implements RemoteCallback.OnResultListener {
final List<CacheQuotaHint> quotas = new ArrayList<>();
long previousBytes;
try {
- previousBytes = Long.parseLong(parser.getAttributeValue(
- null, ATTR_PREVIOUS_BYTES));
+ previousBytes = parser.getAttributeLong(null, ATTR_PREVIOUS_BYTES);
} catch (NumberFormatException e) {
throw new IllegalStateException(
"Previous bytes formatted incorrectly; aborting quota read.");
@@ -389,14 +384,14 @@ public class CacheQuotaStrategy implements RemoteCallback.OnResultListener {
}
@VisibleForTesting
- static CacheQuotaHint getRequestFromXml(XmlPullParser parser) {
+ static CacheQuotaHint getRequestFromXml(TypedXmlPullParser parser) {
try {
String uuid = parser.getAttributeValue(null, ATTR_UUID);
- int uid = Integer.parseInt(parser.getAttributeValue(null, ATTR_UID));
- long bytes = Long.parseLong(parser.getAttributeValue(null, ATTR_QUOTA_IN_BYTES));
+ int uid = parser.getAttributeInt(null, ATTR_UID);
+ long bytes = parser.getAttributeLong(null, ATTR_QUOTA_IN_BYTES);
return new CacheQuotaHint.Builder()
.setVolumeUuid(uuid).setUid(uid).setQuota(bytes).build();
- } catch (NumberFormatException e) {
+ } catch (XmlPullParserException e) {
Slog.e(TAG, "Invalid cache quota request, skipping.");
return null;
}
diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorStrategyCallbackImpl.java b/services/core/java/com/android/server/timedetector/TimeDetectorStrategyCallbackImpl.java
index 5b6de0518999..4f3f9dce8adb 100644
--- a/services/core/java/com/android/server/timedetector/TimeDetectorStrategyCallbackImpl.java
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorStrategyCallbackImpl.java
@@ -16,6 +16,8 @@
package com.android.server.timedetector;
+import static com.android.server.timedetector.TimeDetectorStrategy.ORIGIN_NETWORK;
+import static com.android.server.timedetector.TimeDetectorStrategy.ORIGIN_TELEPHONY;
import static com.android.server.timedetector.TimeDetectorStrategy.stringToOrigin;
import android.annotation.NonNull;
@@ -30,6 +32,9 @@ import android.os.SystemProperties;
import android.provider.Settings;
import android.util.Slog;
+import com.android.internal.R;
+import com.android.server.timedetector.TimeDetectorStrategy.Origin;
+
import java.time.Instant;
import java.util.Objects;
@@ -50,6 +55,13 @@ public final class TimeDetectorStrategyCallbackImpl implements TimeDetectorStrat
Long.max(Environment.getRootDirectory().lastModified(), Build.TIME));
/**
+ * By default telephony and network only suggestions are accepted and telephony takes
+ * precedence over network.
+ */
+ private static final @Origin int[] DEFAULT_AUTOMATIC_TIME_ORIGIN_PRIORITIES =
+ { ORIGIN_TELEPHONY, ORIGIN_NETWORK };
+
+ /**
* If a newly calculated system clock time and the current system clock time differs by this or
* more the system clock will actually be updated. Used to prevent the system clock being set
* for only minor differences.
@@ -76,14 +88,7 @@ public final class TimeDetectorStrategyCallbackImpl implements TimeDetectorStrat
SystemProperties.getInt("ro.sys.time_detector_update_diff",
SYSTEM_CLOCK_UPDATE_THRESHOLD_MILLIS_DEFAULT);
- // TODO(b/172230856): Obtain these values from configuration.
- String[] originStrings = { "telephony", "network" };
- int[] origins = new int[originStrings.length];
- for (int i = 0; i < originStrings.length; i++) {
- int origin = stringToOrigin(originStrings[i]);
- origins[i] = origin;
- }
- mOriginPriorities = origins;
+ mOriginPriorities = getOriginPriorities(context);
}
@Override
@@ -106,7 +111,7 @@ public final class TimeDetectorStrategyCallbackImpl implements TimeDetectorStrat
}
@Override
- public int[] getAutoOriginPriorities() {
+ public int[] autoOriginPriorities() {
return mOriginPriorities;
}
@@ -145,4 +150,20 @@ public final class TimeDetectorStrategyCallbackImpl implements TimeDetectorStrat
Slog.wtf(TAG, "WakeLock " + mWakeLock + " not held");
}
}
+
+ private static int[] getOriginPriorities(@NonNull Context context) {
+ String[] originStrings =
+ context.getResources().getStringArray(R.array.config_autoTimeSourcesPriority);
+ if (originStrings.length == 0) {
+ return DEFAULT_AUTOMATIC_TIME_ORIGIN_PRIORITIES;
+ } else {
+ int[] origins = new int[originStrings.length];
+ for (int i = 0; i < originStrings.length; i++) {
+ int origin = stringToOrigin(originStrings[i]);
+ origins[i] = origin;
+ }
+
+ return origins;
+ }
+ }
}
diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java b/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java
index d8cada55781c..b5d49cfbe9c8 100644
--- a/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java
@@ -18,6 +18,8 @@ package com.android.server.timedetector;
import static com.android.server.timedetector.TimeDetectorStrategy.originToString;
+import static java.util.stream.Collectors.joining;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.AlarmManager;
@@ -140,7 +142,7 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy {
* Returns the order to look at time suggestions when automatically detecting time.
* See {@code #ORIGIN_} constants
*/
- @Origin int[] getAutoOriginPriorities();
+ @Origin int[] autoOriginPriorities();
/** Acquire a suitable wake lock. Must be followed by {@link #releaseWakeLock()} */
void acquireWakeLock();
@@ -252,6 +254,14 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy {
ipw.println("mCallback.systemClockMillis()=" + mCallback.systemClockMillis());
ipw.println("mCallback.systemClockUpdateThresholdMillis()="
+ mCallback.systemClockUpdateThresholdMillis());
+ ipw.printf("mCallback.autoTimeLowerBound()=%s(%s)\n",
+ mCallback.autoTimeLowerBound(),
+ mCallback.autoTimeLowerBound().toEpochMilli());
+ String priorities =
+ Arrays.stream(mCallback.autoOriginPriorities())
+ .mapToObj(TimeDetectorStrategy::originToString)
+ .collect(joining(",", "[", "]"));
+ ipw.println("mCallback.autoOriginPriorities()=" + priorities);
ipw.println("Time change log:");
ipw.increaseIndent(); // level 2
@@ -353,7 +363,7 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy {
}
// Try the different origins one at a time.
- int[] originPriorities = mCallback.getAutoOriginPriorities();
+ int[] originPriorities = mCallback.autoOriginPriorities();
for (int origin : originPriorities) {
TimestampedValue<Long> newUtcTime = null;
String cause = null;
diff --git a/services/core/java/com/android/server/timezone/PackageStatusStorage.java b/services/core/java/com/android/server/timezone/PackageStatusStorage.java
index 7652c438c295..fd0df8d090ec 100644
--- a/services/core/java/com/android/server/timezone/PackageStatusStorage.java
+++ b/services/core/java/com/android/server/timezone/PackageStatusStorage.java
@@ -129,7 +129,7 @@ final class PackageStatusStorage {
@GuardedBy("this")
private PackageStatus getPackageStatusLocked() throws ParseException {
try (FileInputStream fis = mPackageStatusFile.openRead()) {
- XmlPullParser parser = parseToPackageStatusTag(fis);
+ TypedXmlPullParser parser = parseToPackageStatusTag(fis);
Integer checkStatus = getNullableIntAttribute(parser, ATTRIBUTE_CHECK_STATUS);
if (checkStatus == null) {
return null;
@@ -254,7 +254,7 @@ final class PackageStatusStorage {
@GuardedBy("this")
private int getCurrentOptimisticLockId() throws ParseException {
try (FileInputStream fis = mPackageStatusFile.openRead()) {
- XmlPullParser parser = parseToPackageStatusTag(fis);
+ TypedXmlPullParser parser = parseToPackageStatusTag(fis);
return getIntAttribute(parser, ATTRIBUTE_OPTIMISTIC_LOCK_ID);
} catch (IOException e) {
ParseException e2 = new ParseException("Unable to read file", 0);
@@ -264,7 +264,7 @@ final class PackageStatusStorage {
}
/** Returns a parser or throws ParseException, never returns null. */
- private static XmlPullParser parseToPackageStatusTag(FileInputStream fis)
+ private static TypedXmlPullParser parseToPackageStatusTag(FileInputStream fis)
throws ParseException {
try {
TypedXmlPullParser parser = Xml.resolvePullParser(fis);
@@ -358,7 +358,7 @@ final class PackageStatusStorage {
}
}
- private static Integer getNullableIntAttribute(XmlPullParser parser, String attributeName)
+ private static Integer getNullableIntAttribute(TypedXmlPullParser parser, String attributeName)
throws ParseException {
String attributeValue = parser.getAttributeValue(null, attributeName);
try {
@@ -374,7 +374,7 @@ final class PackageStatusStorage {
}
}
- private static int getIntAttribute(XmlPullParser parser, String attributeName)
+ private static int getIntAttribute(TypedXmlPullParser parser, String attributeName)
throws ParseException {
Integer value = getNullableIntAttribute(parser, attributeName);
if (value == null) {
diff --git a/services/core/java/com/android/server/tv/PersistentDataStore.java b/services/core/java/com/android/server/tv/PersistentDataStore.java
index 355c38544cb9..d3c9b3bbe7f5 100644
--- a/services/core/java/com/android/server/tv/PersistentDataStore.java
+++ b/services/core/java/com/android/server/tv/PersistentDataStore.java
@@ -26,6 +26,7 @@ import android.os.UserHandle;
import android.text.TextUtils;
import android.util.AtomicFile;
import android.util.Slog;
+import android.util.TypedXmlPullParser;
import android.util.TypedXmlSerializer;
import android.util.Xml;
@@ -166,7 +167,7 @@ final class PersistentDataStore {
return;
}
- XmlPullParser parser;
+ TypedXmlPullParser parser;
try {
parser = Xml.resolvePullParser(is);
loadFromXml(parser);
@@ -237,7 +238,7 @@ final class PersistentDataStore {
private static final String ATTR_STRING = "string";
private static final String ATTR_ENABLED = "enabled";
- private void loadFromXml(XmlPullParser parser)
+ private void loadFromXml(TypedXmlPullParser parser)
throws IOException, XmlPullParserException {
XmlUtils.beginDocument(parser, TAG_TV_INPUT_MANAGER_STATE);
final int outerDepth = parser.getDepth();
@@ -255,7 +256,7 @@ final class PersistentDataStore {
}
}
- private void loadBlockedRatingsFromXml(XmlPullParser parser)
+ private void loadBlockedRatingsFromXml(TypedXmlPullParser parser)
throws IOException, XmlPullParserException {
final int outerDepth = parser.getDepth();
while (XmlUtils.nextElementWithin(parser, outerDepth)) {
@@ -270,7 +271,7 @@ final class PersistentDataStore {
}
}
- private void saveToXml(XmlSerializer serializer) throws IOException {
+ private void saveToXml(TypedXmlSerializer serializer) throws IOException {
serializer.startDocument(null, true);
serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
serializer.startTag(null, TAG_TV_INPUT_MANAGER_STATE);
@@ -284,7 +285,7 @@ final class PersistentDataStore {
}
serializer.endTag(null, TAG_BLOCKED_RATINGS);
serializer.startTag(null, TAG_PARENTAL_CONTROLS);
- serializer.attribute(null, ATTR_ENABLED, Boolean.toString(mParentalControlsEnabled));
+ serializer.attributeBoolean(null, ATTR_ENABLED, mParentalControlsEnabled);
serializer.endTag(null, TAG_PARENTAL_CONTROLS);
serializer.endTag(null, TAG_TV_INPUT_MANAGER_STATE);
serializer.endDocument();
diff --git a/services/core/java/com/android/server/tv/tunerresourcemanager/UseCasePriorityHints.java b/services/core/java/com/android/server/tv/tunerresourcemanager/UseCasePriorityHints.java
index 367b966a46ed..beb11ed4ea0c 100644
--- a/services/core/java/com/android/server/tv/tunerresourcemanager/UseCasePriorityHints.java
+++ b/services/core/java/com/android/server/tv/tunerresourcemanager/UseCasePriorityHints.java
@@ -20,6 +20,7 @@ import android.media.tv.TvInputService.PriorityHintUseCaseType;
import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
+import android.util.TypedXmlPullParser;
import android.util.Xml;
import com.android.internal.annotations.VisibleForTesting;
@@ -114,9 +115,7 @@ public class UseCasePriorityHints {
protected void parseInternal(InputStream in)
throws IOException, XmlPullParserException {
try {
- XmlPullParser parser = Xml.newPullParser();
- parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false);
- parser.setInput(in, null);
+ TypedXmlPullParser parser = Xml.resolvePullParser(in);
parser.nextTag();
readUseCase(parser);
in.close();
@@ -137,7 +136,7 @@ public class UseCasePriorityHints {
}
}
- private void readUseCase(XmlPullParser parser)
+ private void readUseCase(TypedXmlPullParser parser)
throws XmlPullParserException, IOException {
parser.require(XmlPullParser.START_TAG, NS, "config");
while (parser.next() != XmlPullParser.END_TAG) {
@@ -176,7 +175,7 @@ public class UseCasePriorityHints {
}
}
- private void skip(XmlPullParser parser) throws XmlPullParserException, IOException {
+ private void skip(TypedXmlPullParser parser) throws XmlPullParserException, IOException {
if (parser.getEventType() != XmlPullParser.START_TAG) {
throw new IllegalStateException();
}
@@ -193,7 +192,7 @@ public class UseCasePriorityHints {
}
}
- private int readAttributeToInt(String attributeName, XmlPullParser parser) {
+ private int readAttributeToInt(String attributeName, TypedXmlPullParser parser) {
return Integer.valueOf(parser.getAttributeValue(null, attributeName));
}
@@ -203,7 +202,7 @@ public class UseCasePriorityHints {
}
@PriorityHintUseCaseType
- private static int formatTypeToNum(String attributeName, XmlPullParser parser) {
+ private static int formatTypeToNum(String attributeName, TypedXmlPullParser parser) {
String useCaseName = parser.getAttributeValue(null, attributeName);
switch (useCaseName) {
case "USE_CASE_BACKGROUND":
diff --git a/services/core/java/com/android/server/uri/UriGrantsManagerService.java b/services/core/java/com/android/server/uri/UriGrantsManagerService.java
index bbb5374ea68a..dcc15999d882 100644
--- a/services/core/java/com/android/server/uri/UriGrantsManagerService.java
+++ b/services/core/java/com/android/server/uri/UriGrantsManagerService.java
@@ -668,22 +668,22 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub {
if (TAG_URI_GRANT.equals(tag)) {
final int sourceUserId;
final int targetUserId;
- final int userHandle = readIntAttribute(in,
- ATTR_USER_HANDLE, UserHandle.USER_NULL);
+ final int userHandle = in.getAttributeInt(null, ATTR_USER_HANDLE,
+ UserHandle.USER_NULL);
if (userHandle != UserHandle.USER_NULL) {
// For backwards compatibility.
sourceUserId = userHandle;
targetUserId = userHandle;
} else {
- sourceUserId = readIntAttribute(in, ATTR_SOURCE_USER_ID);
- targetUserId = readIntAttribute(in, ATTR_TARGET_USER_ID);
+ sourceUserId = in.getAttributeInt(null, ATTR_SOURCE_USER_ID);
+ targetUserId = in.getAttributeInt(null, ATTR_TARGET_USER_ID);
}
final String sourcePkg = in.getAttributeValue(null, ATTR_SOURCE_PKG);
final String targetPkg = in.getAttributeValue(null, ATTR_TARGET_PKG);
final Uri uri = Uri.parse(in.getAttributeValue(null, ATTR_URI));
- final boolean prefix = readBooleanAttribute(in, ATTR_PREFIX);
- final int modeFlags = readIntAttribute(in, ATTR_MODE_FLAGS);
- final long createdTime = readLongAttribute(in, ATTR_CREATED_TIME, now);
+ final boolean prefix = in.getAttributeBoolean(null, ATTR_PREFIX, false);
+ final int modeFlags = in.getAttributeInt(null, ATTR_MODE_FLAGS);
+ final long createdTime = in.getAttributeLong(null, ATTR_CREATED_TIME, now);
// Validity check that provider still belongs to source package
// Both direct boot aware and unaware packages are fine as we
@@ -1319,14 +1319,14 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub {
out.startTag(null, TAG_URI_GRANTS);
for (UriPermission.Snapshot perm : persist) {
out.startTag(null, TAG_URI_GRANT);
- writeIntAttribute(out, ATTR_SOURCE_USER_ID, perm.uri.sourceUserId);
- writeIntAttribute(out, ATTR_TARGET_USER_ID, perm.targetUserId);
+ out.attributeInt(null, ATTR_SOURCE_USER_ID, perm.uri.sourceUserId);
+ out.attributeInt(null, ATTR_TARGET_USER_ID, perm.targetUserId);
out.attribute(null, ATTR_SOURCE_PKG, perm.sourcePkg);
out.attribute(null, ATTR_TARGET_PKG, perm.targetPkg);
out.attribute(null, ATTR_URI, String.valueOf(perm.uri.uri));
writeBooleanAttribute(out, ATTR_PREFIX, perm.uri.prefix);
- writeIntAttribute(out, ATTR_MODE_FLAGS, perm.persistedModeFlags);
- writeLongAttribute(out, ATTR_CREATED_TIME, perm.persistedCreateTime);
+ out.attributeInt(null, ATTR_MODE_FLAGS, perm.persistedModeFlags);
+ out.attributeLong(null, ATTR_CREATED_TIME, perm.persistedCreateTime);
out.endTag(null, TAG_URI_GRANT);
}
out.endTag(null, TAG_URI_GRANTS);
diff --git a/services/core/java/com/android/server/wm/utils/DeviceConfigInterface.java b/services/core/java/com/android/server/utils/DeviceConfigInterface.java
index ab7e7f63cafd..ff609031b57c 100644
--- a/services/core/java/com/android/server/wm/utils/DeviceConfigInterface.java
+++ b/services/core/java/com/android/server/utils/DeviceConfigInterface.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.wm.utils;
+package com.android.server.utils;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -54,6 +54,11 @@ public interface DeviceConfigInterface {
boolean getBoolean(@NonNull String namespace, @NonNull String name, boolean defaultValue);
/**
+ * @see DeviceConfig#getFloat
+ */
+ float getFloat(@NonNull String namespace, @NonNull String name, float defaultValue);
+
+ /**
* @see DeviceConfig#addOnPropertiesChangedListener
*/
void addOnPropertiesChangedListener(@NonNull String namespace, @NonNull Executor executor,
@@ -96,6 +101,12 @@ public interface DeviceConfigInterface {
}
@Override
+ public float getFloat(@NonNull String namespace, @NonNull String name,
+ float defaultValue) {
+ return DeviceConfig.getFloat(namespace, name, defaultValue);
+ }
+
+ @Override
public void addOnPropertiesChangedListener(String namespace, Executor executor,
DeviceConfig.OnPropertiesChangedListener listener) {
DeviceConfig.addOnPropertiesChangedListener(namespace, executor, listener);
diff --git a/services/core/java/com/android/server/utils/Snappable.java b/services/core/java/com/android/server/utils/Snappable.java
new file mode 100644
index 000000000000..9b9460b8f757
--- /dev/null
+++ b/services/core/java/com/android/server/utils/Snappable.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.utils;
+
+import android.annotation.NonNull;
+
+/**
+ * A class that implements Snappable can generate a read-only copy its instances. A
+ * snapshot is like a clone except that it is only required to support read-only class
+ * methods. Snapshots are immutable. Attempts to modify the state of a snapshot throw
+ * {@link UnsupporteOperationException}.
+ * @param <T> The type returned by the snapshot() method.
+ */
+public interface Snappable<T> {
+
+ /**
+ * Create an immutable copy of the object, suitable for read-only methods. A snapshot
+ * is free to omit state that is only needed for mutating methods.
+ */
+ @NonNull T snapshot();
+}
diff --git a/services/core/java/com/android/server/utils/Snapshots.java b/services/core/java/com/android/server/utils/Snapshots.java
new file mode 100644
index 000000000000..33b2bd48d802
--- /dev/null
+++ b/services/core/java/com/android/server/utils/Snapshots.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.utils;
+
+import android.annotation.NonNull;
+import android.util.SparseArray;
+import android.util.SparseIntArray;
+import android.util.SparseSetArray;
+
+/**
+ * A collection of useful methods for manipulating Snapshot classes. This is similar to
+ * java.util.Objects or java.util.Arrays.
+ */
+public class Snapshots {
+
+ /**
+ * Return the snapshot of an object, if the object extends {@link Snapper}, or the object
+ * itself.
+ * @param o The object to be copied
+ * @return A snapshot of the object, if the object extends {@link Snapper}
+ */
+ public static <T> T maybeSnapshot(T o) {
+ if (o instanceof Snappable) {
+ return ((Snappable<T>) o).snapshot();
+ } else {
+ return o;
+ }
+ }
+
+ /**
+ * Copy a SparseArray in a manner suitable for a snapshot. The destination must be
+ * empty. This is not a snapshot because the elements are copied by reference even if
+ * they are {@link Snappable}.
+ * @param dst The destination array. It must be empty.
+ * @param src The source array
+ */
+ public <E> void copy(@NonNull SparseArray<E> dst, @NonNull SparseArray<E> src) {
+ if (dst.size() != 0) {
+ throw new IllegalArgumentException("copy destination is not empty");
+ }
+ final int end = src.size();
+ for (int i = 0; i < end; i++) {
+ dst.put(src.keyAt(i), src.valueAt(i));
+ }
+ }
+
+ /**
+ * Copy a SparseSetArray in a manner suitable for a snapshot. The destination must be
+ * empty. This is not a snapshot because the elements are copied by reference even if
+ * they are {@link Snappable}.
+ * @param dst The destination array. It must be empty.
+ * @param src The source array
+ */
+ public static <E> void copy(@NonNull SparseSetArray<E> dst, @NonNull SparseSetArray<E> src) {
+ if (dst.size() != 0) {
+ throw new IllegalArgumentException("copy destination is not empty");
+ }
+ final int end = src.size();
+ for (int i = 0; i < end; i++) {
+ final int size = src.sizeAt(i);
+ for (int j = 0; j < size; j++) {
+ dst.add(src.keyAt(i), src.valueAt(i, j));
+ }
+ }
+ }
+
+ /**
+ * Make <dst> a snapshot of <src> .
+ * @param dst The destination array. It must be empty.
+ * @param src The source array
+ */
+ public void snapshot(@NonNull SparseIntArray dst, @NonNull SparseIntArray src) {
+ if (dst.size() != 0) {
+ throw new IllegalArgumentException("snapshot destination is not empty");
+ }
+ final int end = src.size();
+ for (int i = 0; i < end; i++) {
+ dst.put(src.keyAt(i), src.valueAt(i));
+ }
+ }
+
+ /**
+ * Make <dst> a "snapshot" of <src>. <dst> mst be empty. The destination is just a
+ * copy of the source except that if the source elements implement Snappable, then
+ * the elements in the destination will be snapshots of elements from the source.
+ * @param dst The destination array. It must be empty.
+ * @param src The source array
+ */
+ public static <E extends Snappable<E>> void snapshot(@NonNull SparseArray<E> dst,
+ @NonNull SparseArray<E> src) {
+ if (dst.size() != 0) {
+ throw new IllegalArgumentException("snapshot destination is not empty");
+ }
+ final int end = src.size();
+ for (int i = 0; i < end; i++) {
+ dst.put(src.keyAt(i), src.valueAt(i).snapshot());
+ }
+ }
+
+ /**
+ * Make <dst> a "snapshot" of <src>. <dst> mst be empty. The destination is a
+ * copy of the source except that snapshots are taken of the elements.
+ * @param dst The destination array. It must be empty.
+ * @param src The source array
+ */
+ public static <E extends Snappable<E>> void snapshot(@NonNull SparseSetArray<E> dst,
+ @NonNull SparseSetArray<E> src) {
+ if (dst.size() != 0) {
+ throw new IllegalArgumentException("snapshot destination is not empty");
+ }
+ final int end = src.size();
+ for (int i = 0; i < end; i++) {
+ final int size = src.sizeAt(i);
+ for (int j = 0; j < size; j++) {
+ dst.add(src.keyAt(i), src.valueAt(i, j).snapshot());
+ }
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/utils/WatchableImpl.java b/services/core/java/com/android/server/utils/WatchableImpl.java
index 94ab1d49807f..16400b186ab0 100644
--- a/services/core/java/com/android/server/utils/WatchableImpl.java
+++ b/services/core/java/com/android/server/utils/WatchableImpl.java
@@ -19,11 +19,15 @@ package com.android.server.utils;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import com.android.internal.annotations.GuardedBy;
+
import java.util.ArrayList;
import java.util.Objects;
/**
- * A concrete implementation of {@link Watchable}
+ * A concrete implementation of {@link Watchable}. This includes one commonly needed feature:
+ * the Watchable may be sealed, so that it throws an {@link IllegalStateException} if
+ * a change is detected.
*/
public class WatchableImpl implements Watchable {
/**
@@ -78,10 +82,37 @@ public class WatchableImpl implements Watchable {
@Override
public void dispatchChange(@Nullable Watchable what) {
synchronized (mObservers) {
+ if (mSealed) {
+ throw new IllegalStateException("attempt to change a sealed object");
+ }
final int end = mObservers.size();
for (int i = 0; i < end; i++) {
mObservers.get(i).onChange(what);
}
}
}
+
+ /**
+ * True if the object is sealed.
+ */
+ @GuardedBy("mObservers")
+ private boolean mSealed = false;
+
+ /**
+ * Freeze the {@link Watchable}.
+ **/
+ public void seal() {
+ synchronized (mObservers) {
+ mSealed = true;
+ }
+ }
+
+ /**
+ * Return the sealed state.
+ */
+ public boolean isFrozen() {
+ synchronized (mObservers) {
+ return mSealed;
+ }
+ }
}
diff --git a/services/core/java/com/android/server/utils/WatchedArrayMap.java b/services/core/java/com/android/server/utils/WatchedArrayMap.java
index 7b3298086aba..e8065f140af7 100644
--- a/services/core/java/com/android/server/utils/WatchedArrayMap.java
+++ b/services/core/java/com/android/server/utils/WatchedArrayMap.java
@@ -18,9 +18,7 @@ package com.android.server.utils;
import android.annotation.NonNull;
import android.annotation.Nullable;
-
import android.util.ArrayMap;
-import android.util.Log;
import java.util.Collection;
import java.util.Collections;
@@ -31,14 +29,17 @@ import java.util.Set;
* WatchedArrayMap is an {@link android.util.ArrayMap} that can report changes to itself. If its
* values are {@link Watchable} then the WatchedArrayMap will also report changes to the values.
* A {@link Watchable} is notified only once, no matter how many times it is stored in the array.
+ * @param <K> The key type.
+ * @param <V> The value type.
*/
-public class WatchedArrayMap<K, V> extends WatchableImpl implements Map<K, V> {
+public class WatchedArrayMap<K, V> extends WatchableImpl
+ implements Map<K, V>, Snappable {
// The storage
private final ArrayMap<K, V> mStorage;
// If true, the array is watching its children
- private boolean mWatching = false;
+ private volatile boolean mWatching = false;
// The local observer
private final Watcher mObserver = new Watcher() {
@@ -386,4 +387,38 @@ public class WatchedArrayMap<K, V> extends WatchableImpl implements Map<K, V> {
onChanged();
return result;
}
+
+ /**
+ * Create a copy of the array. If the element is a subclass of Snapper then the copy
+ * contains snapshots of the elements. Otherwise the copy contains references to the
+ * elements. The returned snapshot is immutable.
+ * @return A new array whose elements are the elements of <this>.
+ */
+ public WatchedArrayMap<K, V> snapshot() {
+ WatchedArrayMap<K, V> l = new WatchedArrayMap<>();
+ snapshot(l, this);
+ return l;
+ }
+
+ /**
+ * Make the destination a copy of the source. If the element is a subclass of Snapper then the
+ * copy contains snapshots of the elements. Otherwise the copy contains references to the
+ * elements. The destination must be initially empty. Upon return, the destination is
+ * immutable.
+ * @param dst The destination array. It must be empty.
+ * @param src The source array. It is not modified.
+ */
+ public static <K, V> void snapshot(@NonNull WatchedArrayMap<K, V> dst,
+ @NonNull WatchedArrayMap<K, V> src) {
+ if (dst.size() != 0) {
+ throw new IllegalArgumentException("snapshot destination is not empty");
+ }
+ final int end = src.size();
+ for (int i = 0; i < end; i++) {
+ final V val = Snapshots.maybeSnapshot(src.valueAt(i));
+ final K key = src.keyAt(i);
+ dst.put(key, val);
+ }
+ dst.seal();
+ }
}
diff --git a/services/core/java/com/android/server/utils/WatchedSparseArray.java b/services/core/java/com/android/server/utils/WatchedSparseArray.java
index 4d43b682e113..6797c6eb7801 100644
--- a/services/core/java/com/android/server/utils/WatchedSparseArray.java
+++ b/services/core/java/com/android/server/utils/WatchedSparseArray.java
@@ -18,7 +18,6 @@ package com.android.server.utils;
import android.annotation.NonNull;
import android.annotation.Nullable;
-
import android.util.SparseArray;
import java.util.ArrayList;
@@ -28,14 +27,16 @@ import java.util.ArrayList;
* array registers with the {@link Watchable}. The array registers only once with each
* {@link Watchable} no matter how many times the {@link Watchable} is stored in the
* array.
+ * @param <E> The element type, stored in the array.
*/
-public class WatchedSparseArray<E> extends WatchableImpl {
+public class WatchedSparseArray<E> extends WatchableImpl
+ implements Snappable {
// The storage
private final SparseArray<E> mStorage;
// If true, the array is watching its children
- private boolean mWatching = false;
+ private volatile boolean mWatching = false;
// The local observer
private final Watcher mObserver = new Watcher() {
@@ -398,4 +399,39 @@ public class WatchedSparseArray<E> extends WatchableImpl {
public String toString() {
return mStorage.toString();
}
+
+ /**
+ * Create a copy of the array. If the element is a subclass of Snapper then the copy
+ * contains snapshots of the elements. Otherwise the copy contains references to the
+ * elements. The returned snapshot is immutable.
+ * @return A new array whose elements are the elements of <this>.
+ */
+ public WatchedSparseArray<E> snapshot() {
+ WatchedSparseArray<E> l = new WatchedSparseArray<>();
+ snapshot(l, this);
+ return l;
+ }
+
+ /**
+ * Make the destination a copy of the source. If the element is a subclass of Snapper then the
+ * copy contains snapshots of the elements. Otherwise the copy contains references to the
+ * elements. The destination must be initially empty. Upon return, the destination is
+ * immutable.
+ * @param dst The destination array. It must be empty.
+ * @param src The source array. It is not modified.
+ */
+ public static <E> void snapshot(@NonNull WatchedSparseArray<E> dst,
+ @NonNull WatchedSparseArray<E> src) {
+ if (dst.size() != 0) {
+ throw new IllegalArgumentException("snapshot destination is not empty");
+ }
+ final int end = src.size();
+ for (int i = 0; i < end; i++) {
+ final E val = Snapshots.maybeSnapshot(src.valueAt(i));
+ final int key = src.keyAt(i);
+ dst.put(key, val);
+ }
+ dst.seal();
+ }
+
}
diff --git a/services/core/java/com/android/server/utils/WatchedSparseBooleanArray.java b/services/core/java/com/android/server/utils/WatchedSparseBooleanArray.java
index edf7d27b61dd..b845eea168a5 100644
--- a/services/core/java/com/android/server/utils/WatchedSparseBooleanArray.java
+++ b/services/core/java/com/android/server/utils/WatchedSparseBooleanArray.java
@@ -17,21 +17,20 @@
package com.android.server.utils;
import android.annotation.NonNull;
-import android.annotation.Nullable;
-
import android.util.SparseBooleanArray;
/**
* A watched variant of SparseBooleanArray. Changes to the array are notified to
* registered {@link Watcher}s.
*/
-public class WatchedSparseBooleanArray extends WatchableImpl {
+public class WatchedSparseBooleanArray extends WatchableImpl
+ implements Snappable {
// The storage
private final SparseBooleanArray mStorage;
// A private convenience function
- private void dispatchChange() {
+ private void onChanged() {
dispatchChange(this);
}
@@ -81,7 +80,7 @@ public class WatchedSparseBooleanArray extends WatchableImpl {
*/
public void delete(int key) {
mStorage.delete(key);
- dispatchChange();
+ onChanged();
}
/**
@@ -91,7 +90,7 @@ public class WatchedSparseBooleanArray extends WatchableImpl {
*/
public void removeAt(int index) {
mStorage.removeAt(index);
- dispatchChange();
+ onChanged();
}
/**
@@ -102,7 +101,7 @@ public class WatchedSparseBooleanArray extends WatchableImpl {
public void put(int key, boolean value) {
if (mStorage.get(key) != value) {
mStorage.put(key, value);
- dispatchChange();
+ onChanged();
}
}
@@ -164,7 +163,7 @@ public class WatchedSparseBooleanArray extends WatchableImpl {
public void setValueAt(int index, boolean value) {
if (mStorage.valueAt(index) != value) {
mStorage.setValueAt(index, value);
- dispatchChange();
+ onChanged();
}
}
@@ -172,7 +171,7 @@ public class WatchedSparseBooleanArray extends WatchableImpl {
public void setKeyAt(int index, int key) {
if (mStorage.keyAt(index) != key) {
mStorage.setKeyAt(index, key);
- dispatchChange();
+ onChanged();
}
}
@@ -202,7 +201,7 @@ public class WatchedSparseBooleanArray extends WatchableImpl {
*/
public void clear() {
mStorage.clear();
- dispatchChange();
+ onChanged();
}
/**
@@ -211,7 +210,7 @@ public class WatchedSparseBooleanArray extends WatchableImpl {
*/
public void append(int key, boolean value) {
mStorage.append(key, value);
- dispatchChange();
+ onChanged();
}
@Override
@@ -233,4 +232,30 @@ public class WatchedSparseBooleanArray extends WatchableImpl {
public String toString() {
return mStorage.toString();
}
+
+ /**
+ * Create a snapshot. The snapshot does not include any {@link Watchable}
+ * information.
+ */
+ public WatchedSparseBooleanArray snapshot() {
+ WatchedSparseBooleanArray l = new WatchedSparseBooleanArray(this);
+ l.seal();
+ return l;
+ }
+
+ /**
+ * Make <this> a snapshot of the argument. Note that <this> is immutable when the
+ * method returns. <this> must be empty when the function is called.
+ * @param r The source array, which is copied into <this>
+ */
+ public void snapshot(@NonNull WatchedSparseBooleanArray r) {
+ if (size() != 0) {
+ throw new IllegalArgumentException("snapshot destination is not empty");
+ }
+ final int end = r.size();
+ for (int i = 0; i < end; i++) {
+ put(r.keyAt(i), r.valueAt(i));
+ }
+ seal();
+ }
}
diff --git a/services/core/java/com/android/server/utils/eventlog/LocalEventLog.java b/services/core/java/com/android/server/utils/eventlog/LocalEventLog.java
index 12c6a7a397e3..fe51d7408153 100644
--- a/services/core/java/com/android/server/utils/eventlog/LocalEventLog.java
+++ b/services/core/java/com/android/server/utils/eventlog/LocalEventLog.java
@@ -99,6 +99,7 @@ public abstract class LocalEventLog {
private long mLastLogRealtimeMs;
public LocalEventLog(int size) {
+ Preconditions.checkArgument(size > 0);
mLog = new Log[size];
mLogSize = 0;
mLogEndIndex = 0;
@@ -163,7 +164,7 @@ public abstract class LocalEventLog {
if (mLogSize == mLog.length) {
// if log is full, size will remain the same, but update the start time
- mStartRealtimeMs += event.getTimeDeltaMs();
+ mStartRealtimeMs += mLog[startIndex()].getTimeDeltaMs();
} else {
// otherwise add an item
mLogSize++;
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index e07540a0c746..c3d5874de609 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -39,7 +39,7 @@ import android.app.WallpaperColors;
import android.app.WallpaperInfo;
import android.app.WallpaperManager;
import android.app.WallpaperManager.SetWallpaperFlags;
-import android.app.admin.DevicePolicyManager;
+import android.app.admin.DevicePolicyManagerInternal;
import android.app.backup.WallpaperBackupHelper;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
@@ -100,12 +100,12 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.content.PackageMonitor;
import com.android.internal.os.BackgroundThread;
import com.android.internal.util.DumpUtils;
-import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.JournaledFile;
import com.android.server.EventLogTags;
import com.android.server.FgThread;
import com.android.server.LocalServices;
import com.android.server.SystemService;
+import com.android.server.SystemService.TargetUser;
import com.android.server.pm.UserManagerInternal;
import com.android.server.utils.TimingsTraceAndSlog;
import com.android.server.wm.WindowManagerInternal;
@@ -114,7 +114,6 @@ import libcore.io.IoUtils;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
import java.io.BufferedOutputStream;
import java.io.File;
@@ -125,7 +124,6 @@ import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
-import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@@ -2848,10 +2846,9 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
if (!uidMatchPackage) {
return false; // callingPackage was faked.
}
-
- // TODO(b/144048540): DPM needs to take into account the userId, not just the package.
- final DevicePolicyManager dpm = mContext.getSystemService(DevicePolicyManager.class);
- if (dpm.isDeviceOwnerApp(callingPackage) || dpm.isProfileOwnerApp(callingPackage)) {
+ final DevicePolicyManagerInternal dpmi =
+ LocalServices.getService(DevicePolicyManagerInternal.class);
+ if (dpmi != null && dpmi.isDeviceOrProfileOwnerInCallingUser(callingPackage)) {
return true;
}
final int callingUserId = UserHandle.getCallingUserId();
@@ -2909,11 +2906,9 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
private void saveSettingsLocked(int userId) {
JournaledFile journal = makeJournaledFile(userId);
FileOutputStream fstream = null;
- BufferedOutputStream stream = null;
try {
fstream = new FileOutputStream(journal.chooseForWrite(), false);
- stream = new BufferedOutputStream(fstream);
- TypedXmlSerializer out = Xml.resolveSerializer(stream);
+ TypedXmlSerializer out = Xml.resolveSerializer(fstream);
out.startDocument(null, true);
WallpaperData wallpaper;
@@ -2929,56 +2924,56 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
out.endDocument();
- stream.flush(); // also flushes fstream
+ fstream.flush();
FileUtils.sync(fstream);
- stream.close(); // also closes fstream
+ fstream.close();
journal.commit();
} catch (IOException e) {
- IoUtils.closeQuietly(stream);
+ IoUtils.closeQuietly(fstream);
journal.rollback();
}
}
- private void writeWallpaperAttributes(XmlSerializer out, String tag, WallpaperData wallpaper)
+ private void writeWallpaperAttributes(TypedXmlSerializer out, String tag,
+ WallpaperData wallpaper)
throws IllegalArgumentException, IllegalStateException, IOException {
if (DEBUG) {
Slog.v(TAG, "writeWallpaperAttributes id=" + wallpaper.wallpaperId);
}
final DisplayData wpdData = getDisplayDataOrCreate(DEFAULT_DISPLAY);
out.startTag(null, tag);
- out.attribute(null, "id", Integer.toString(wallpaper.wallpaperId));
- out.attribute(null, "width", Integer.toString(wpdData.mWidth));
- out.attribute(null, "height", Integer.toString(wpdData.mHeight));
+ out.attributeInt(null, "id", wallpaper.wallpaperId);
+ out.attributeInt(null, "width", wpdData.mWidth);
+ out.attributeInt(null, "height", wpdData.mHeight);
- out.attribute(null, "cropLeft", Integer.toString(wallpaper.cropHint.left));
- out.attribute(null, "cropTop", Integer.toString(wallpaper.cropHint.top));
- out.attribute(null, "cropRight", Integer.toString(wallpaper.cropHint.right));
- out.attribute(null, "cropBottom", Integer.toString(wallpaper.cropHint.bottom));
+ out.attributeInt(null, "cropLeft", wallpaper.cropHint.left);
+ out.attributeInt(null, "cropTop", wallpaper.cropHint.top);
+ out.attributeInt(null, "cropRight", wallpaper.cropHint.right);
+ out.attributeInt(null, "cropBottom", wallpaper.cropHint.bottom);
if (wpdData.mPadding.left != 0) {
- out.attribute(null, "paddingLeft", Integer.toString(wpdData.mPadding.left));
+ out.attributeInt(null, "paddingLeft", wpdData.mPadding.left);
}
if (wpdData.mPadding.top != 0) {
- out.attribute(null, "paddingTop", Integer.toString(wpdData.mPadding.top));
+ out.attributeInt(null, "paddingTop", wpdData.mPadding.top);
}
if (wpdData.mPadding.right != 0) {
- out.attribute(null, "paddingRight", Integer.toString(wpdData.mPadding.right));
+ out.attributeInt(null, "paddingRight", wpdData.mPadding.right);
}
if (wpdData.mPadding.bottom != 0) {
- out.attribute(null, "paddingBottom", Integer.toString(wpdData.mPadding.bottom));
+ out.attributeInt(null, "paddingBottom", wpdData.mPadding.bottom);
}
if (wallpaper.primaryColors != null) {
int colorsCount = wallpaper.primaryColors.getMainColors().size();
- out.attribute(null, "colorsCount", Integer.toString(colorsCount));
+ out.attributeInt(null, "colorsCount", colorsCount);
if (colorsCount > 0) {
for (int i = 0; i < colorsCount; i++) {
final Color wc = wallpaper.primaryColors.getMainColors().get(i);
- out.attribute(null, "colorValue"+i, Integer.toString(wc.toArgb()));
+ out.attributeInt(null, "colorValue" + i, wc.toArgb());
}
}
- out.attribute(null, "colorHints",
- Integer.toString(wallpaper.primaryColors.getColorHints()));
+ out.attributeInt(null, "colorHints", wallpaper.primaryColors.getColorHints());
}
out.attribute(null, "name", wallpaper.name);
@@ -3028,12 +3023,8 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
}
}
- private int getAttributeInt(XmlPullParser parser, String name, int defValue) {
- String value = parser.getAttributeValue(null, name);
- if (value == null) {
- return defValue;
- }
- return Integer.parseInt(value);
+ private int getAttributeInt(TypedXmlPullParser parser, String name, int defValue) {
+ return parser.getAttributeInt(null, name, defValue);
}
/**
@@ -3213,11 +3204,11 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
}
}
- private void parseWallpaperAttributes(XmlPullParser parser, WallpaperData wallpaper,
- boolean keepDimensionHints) {
- final String idString = parser.getAttributeValue(null, "id");
- if (idString != null) {
- final int id = wallpaper.wallpaperId = Integer.parseInt(idString);
+ private void parseWallpaperAttributes(TypedXmlPullParser parser, WallpaperData wallpaper,
+ boolean keepDimensionHints) throws XmlPullParserException {
+ final int id = parser.getAttributeInt(null, "id", -1);
+ if (id != -1) {
+ wallpaper.wallpaperId = id;
if (id > mWallpaperId) {
mWallpaperId = id;
}
@@ -3228,8 +3219,8 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
final DisplayData wpData = getDisplayDataOrCreate(DEFAULT_DISPLAY);
if (!keepDimensionHints) {
- wpData.mWidth = Integer.parseInt(parser.getAttributeValue(null, "width"));
- wpData.mHeight = Integer.parseInt(parser.getAttributeValue(null, "height"));
+ wpData.mWidth = parser.getAttributeInt(null, "width");
+ wpData.mHeight = parser.getAttributeInt(null, "height");
}
wallpaper.cropHint.left = getAttributeInt(parser, "cropLeft", 0);
wallpaper.cropHint.top = getAttributeInt(parser, "cropTop", 0);
diff --git a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
index b4ca7c5f6ff1..6a50b793de0f 100644
--- a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
@@ -425,20 +425,20 @@ class ActivityMetricsLogger {
mLastLogTimeSecs = now;
mWindowState = WINDOW_STATE_INVALID;
- Task stack = mSupervisor.mRootWindowContainer.getTopDisplayFocusedStack();
- if (stack == null) {
+ Task rootTask = mSupervisor.mRootWindowContainer.getTopDisplayFocusedRootTask();
+ if (rootTask == null) {
return;
}
- if (stack.isActivityTypeAssistant()) {
+ if (rootTask.isActivityTypeAssistant()) {
mWindowState = WINDOW_STATE_ASSISTANT;
return;
}
- @WindowingMode int windowingMode = stack.getWindowingMode();
+ @WindowingMode int windowingMode = rootTask.getWindowingMode();
if (windowingMode == WINDOWING_MODE_PINNED) {
- stack = mSupervisor.mRootWindowContainer.findStackBehind(stack);
- windowingMode = stack.getWindowingMode();
+ rootTask = mSupervisor.mRootWindowContainer.findRootTaskBehind(rootTask);
+ windowingMode = rootTask.getWindowingMode();
}
switch (windowingMode) {
case WINDOWING_MODE_FULLSCREEN:
@@ -456,7 +456,7 @@ class ActivityMetricsLogger {
break;
default:
if (windowingMode != WINDOWING_MODE_UNDEFINED) {
- throw new IllegalStateException("Unknown windowing mode for stack=" + stack
+ throw new IllegalStateException("Unknown windowing mode for task=" + rootTask
+ " windowingMode=" + windowingMode);
}
}
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 913c3e580adf..1b8cc082f598 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -18,7 +18,6 @@ package com.android.server.wm;
import static android.app.ActivityManager.LOCK_TASK_MODE_NONE;
import static android.app.ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
-import static android.app.ActivityManager.TaskDescription.ATTR_TASKDESCRIPTION_PREFIX;
import static android.app.ActivityOptions.ANIM_CLIP_REVEAL;
import static android.app.ActivityOptions.ANIM_CUSTOM;
import static android.app.ActivityOptions.ANIM_NONE;
@@ -96,18 +95,18 @@ import static android.view.Display.COLOR_MODE_DEFAULT;
import static android.view.Display.INVALID_DISPLAY;
import static android.view.Surface.ROTATION_270;
import static android.view.Surface.ROTATION_90;
+import static android.view.WindowManager.TRANSIT_CLOSE;
+import static android.view.WindowManager.TRANSIT_OLD_ACTIVITY_CLOSE;
+import static android.view.WindowManager.TRANSIT_OLD_TASK_CLOSE;
+import static android.view.WindowManager.TRANSIT_OLD_TASK_OPEN_BEHIND;
+import static android.view.WindowManager.TRANSIT_OLD_UNSET;
import static android.view.WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD;
import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
-import static android.view.WindowManager.TRANSIT_CLOSE;
import static android.view.WindowManager.TRANSIT_FLAG_OPEN_BEHIND;
-import static android.view.WindowManager.TRANSIT_OLD_ACTIVITY_CLOSE;
-import static android.view.WindowManager.TRANSIT_OLD_TASK_CLOSE;
-import static android.view.WindowManager.TRANSIT_OLD_UNSET;
-import static android.view.WindowManager.TransitionOldType;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ADD_REMOVE;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS;
@@ -183,6 +182,7 @@ import static com.android.server.wm.IdentifierProto.USER_ID;
import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION;
import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_RECENTS;
import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_WINDOW_ANIMATION;
+import static com.android.server.wm.Task.TASK_VISIBILITY_VISIBLE;
import static com.android.server.wm.Task.ActivityState.DESTROYED;
import static com.android.server.wm.Task.ActivityState.DESTROYING;
import static com.android.server.wm.Task.ActivityState.FINISHING;
@@ -194,7 +194,6 @@ import static com.android.server.wm.Task.ActivityState.RESUMED;
import static com.android.server.wm.Task.ActivityState.STARTED;
import static com.android.server.wm.Task.ActivityState.STOPPED;
import static com.android.server.wm.Task.ActivityState.STOPPING;
-import static com.android.server.wm.Task.TASK_VISIBILITY_VISIBLE;
import static com.android.server.wm.TaskPersister.DEBUG;
import static com.android.server.wm.TaskPersister.IMAGE_EXTENSION;
import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN;
@@ -277,6 +276,8 @@ import android.util.Log;
import android.util.MergedConfiguration;
import android.util.Slog;
import android.util.TimeUtils;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
import android.util.proto.ProtoOutputStream;
import android.view.AppTransitionAnimationSpec;
import android.view.DisplayCutout;
@@ -291,6 +292,7 @@ import android.view.SurfaceControl.Transaction;
import android.view.WindowInsets.Type;
import android.view.WindowManager;
import android.view.WindowManager.LayoutParams;
+import android.view.WindowManager.TransitionOldType;
import android.view.animation.Animation;
import android.window.WindowContainerToken;
@@ -320,9 +322,7 @@ import com.android.server.wm.utils.InsetUtils;
import com.google.android.collect.Sets;
-import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
import java.io.File;
import java.io.IOException;
@@ -1491,13 +1491,14 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
}
- ActivityRecord(ActivityTaskManagerService _service, WindowProcessController _caller,
+ private ActivityRecord(ActivityTaskManagerService _service, WindowProcessController _caller,
int _launchedFromPid, int _launchedFromUid, String _launchedFromPackage,
@Nullable String _launchedFromFeature, Intent _intent, String _resolvedType,
ActivityInfo aInfo, Configuration _configuration, ActivityRecord _resultTo,
String _resultWho, int _reqCode, boolean _componentSpecified,
boolean _rootVoiceInteraction, ActivityTaskSupervisor supervisor,
- ActivityOptions options, ActivityRecord sourceRecord) {
+ ActivityOptions options, ActivityRecord sourceRecord, PersistableBundle persistentState,
+ TaskDescription _taskDescription, long _createTime) {
super(_service.mWindowManager, new Token(_intent).asBinder(), TYPE_APPLICATION, true,
null /* displayContent */, false /* ownerCanManageAppTokens */);
@@ -1652,6 +1653,12 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
mHandoverLaunchDisplayId = options.getLaunchDisplayId();
mLaunchCookie = options.getLaunchCookie();
}
+
+ mPersistentState = persistentState;
+ taskDescription = _taskDescription;
+ if (_createTime > 0) {
+ createTime = _createTime;
+ }
}
/**
@@ -2550,15 +2557,15 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
return FINISH_RESULT_CANCELLED;
}
- final Task stack = getRootTask();
- final boolean mayAdjustTop = (isState(RESUMED) || stack.mResumedActivity == null)
- && stack.isFocusedStackOnDisplay()
+ final Task rootTask = getRootTask();
+ final boolean mayAdjustTop = (isState(RESUMED) || rootTask.mResumedActivity == null)
+ && rootTask.isFocusedStackOnDisplay()
// Do not adjust focus task because the task will be reused to launch new activity.
&& !task.isClearingToReuseTask();
final boolean shouldAdjustGlobalFocus = mayAdjustTop
// It must be checked before {@link #makeFinishingLocked} is called, because a stack
// is not visible if it only contains finishing activities.
- && mRootWindowContainer.isTopDisplayFocusedStack(stack);
+ && mRootWindowContainer.isTopDisplayFocusedRootTask(rootTask);
mAtmService.deferWindowLayout();
try {
@@ -2623,12 +2630,12 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// Tell window manager to prepare for this one to be removed.
setVisibility(false);
- if (stack.mPausingActivity == null) {
+ if (rootTask.mPausingActivity == null) {
ProtoLog.v(WM_DEBUG_STATES, "Finish needs to pause: %s", this);
if (DEBUG_USER_LEAVING) {
Slog.v(TAG_USER_LEAVING, "finish() => pause with userLeaving=false");
}
- stack.startPausingLocked(false /* userLeaving */, false /* uiSleeping */,
+ rootTask.startPausingLocked(false /* userLeaving */, false /* uiSleeping */,
null /* resuming */, "finish");
}
@@ -2827,7 +2834,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
false /* markFrozenIfConfigChanged */, true /* deferResume */);
}
if (activityRemoved) {
- mRootWindowContainer.resumeFocusedStacksTopActivities();
+ mRootWindowContainer.resumeFocusedTasksTopActivities();
}
ProtoLog.d(WM_DEBUG_CONTAINERS, "destroyIfPossible: r=%s destroy returned "
@@ -2849,7 +2856,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
mTaskSupervisor.mFinishingActivities.add(this);
}
resumeKeyDispatchingLocked();
- return mRootWindowContainer.resumeFocusedStacksTopActivities();
+ return mRootWindowContainer.resumeFocusedTasksTopActivities();
}
/**
@@ -3014,7 +3021,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
removeFromHistory(reason);
}
- mRootWindowContainer.resumeFocusedStacksTopActivities();
+ mRootWindowContainer.resumeFocusedTasksTopActivities();
}
/**
@@ -5206,7 +5213,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
} else {
if (deferRelaunchUntilPaused) {
destroyImmediately("stop-config");
- mRootWindowContainer.resumeFocusedStacksTopActivities();
+ mRootWindowContainer.resumeFocusedTasksTopActivities();
} else {
mRootWindowContainer.updatePreviousProcess(this);
}
@@ -5703,7 +5710,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// First find the real culprit... if this activity has stopped, then the key dispatching
// timeout should not be caused by this.
if (stopped) {
- final Task stack = mRootWindowContainer.getTopDisplayFocusedStack();
+ final Task stack = mRootWindowContainer.getTopDisplayFocusedRootTask();
if (stack == null) {
return this;
}
@@ -6091,7 +6098,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
@Override
public void onAnimationLeashCreated(Transaction t, SurfaceControl leash) {
t.setLayer(leash, getAnimationLayer());
- getDisplayContent().assignStackOrdering();
+ getDisplayContent().assignRootTaskOrdering();
}
@Override
@@ -6372,14 +6379,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
void setRequestedOrientation(int requestedOrientation) {
- setOrientation(requestedOrientation, mayFreezeScreenLocked());
- mAtmService.getTaskChangeNotificationController().notifyActivityRequestedOrientationChanged(
- task.mTaskId, requestedOrientation);
- }
-
- private void setOrientation(int requestedOrientation, boolean freezeScreenIfNeeded) {
- final IBinder binder = freezeScreenIfNeeded ? appToken.asBinder() : null;
- setOrientation(requestedOrientation, binder, this);
+ setOrientation(requestedOrientation, this);
// Push the new configuration to the requested app in case where it's not pushed, e.g. when
// the request is handled at task level with letterbox.
@@ -6387,6 +6387,9 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
mLastReportedConfiguration.getMergedConfiguration())) {
ensureActivityConfiguration(0 /* globalChanges */, false /* preserveWindow */);
}
+
+ mAtmService.getTaskChangeNotificationController().notifyActivityRequestedOrientationChanged(
+ task.mTaskId, requestedOrientation);
}
/*
@@ -6403,8 +6406,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
return;
}
- final IBinder freezeToken = mayFreezeScreenLocked() ? appToken : null;
- if (onDescendantOrientationChanged(freezeToken, this)) {
+ if (onDescendantOrientationChanged(this)) {
// The app is just becoming visible, and the parent Task has updated with the
// orientation request. Update the size compat mode.
updateSizeCompatMode();
@@ -7081,6 +7083,12 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
return true;
}
+ if (isState(DESTROYED)) {
+ ProtoLog.v(WM_DEBUG_CONFIGURATION, "Skipping config check "
+ + "in destroyed state %s", this);
+ return true;
+ }
+
if (!ignoreVisibility && (mState == STOPPING || mState == STOPPED || !shouldBeVisible())) {
ProtoLog.v(WM_DEBUG_CONFIGURATION, "Skipping config check "
+ "invisible: %s", this);
@@ -7464,9 +7472,9 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
|| (info.flags & FLAG_NO_HISTORY) != 0;
}
- void saveToXml(XmlSerializer out) throws IOException, XmlPullParserException {
- out.attribute(null, ATTR_ID, String.valueOf(createTime));
- out.attribute(null, ATTR_LAUNCHEDFROMUID, String.valueOf(launchedFromUid));
+ void saveToXml(TypedXmlSerializer out) throws IOException, XmlPullParserException {
+ out.attributeLong(null, ATTR_ID, createTime);
+ out.attributeInt(null, ATTR_LAUNCHEDFROMUID, launchedFromUid);
if (launchedFromPackage != null) {
out.attribute(null, ATTR_LAUNCHEDFROMPACKAGE, launchedFromPackage);
}
@@ -7476,8 +7484,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
if (resolvedType != null) {
out.attribute(null, ATTR_RESOLVEDTYPE, resolvedType);
}
- out.attribute(null, ATTR_COMPONENTSPECIFIED, String.valueOf(componentSpecified));
- out.attribute(null, ATTR_USERID, String.valueOf(mUserId));
+ out.attributeBoolean(null, ATTR_COMPONENTSPECIFIED, componentSpecified);
+ out.attributeInt(null, ATTR_USERID, mUserId);
if (taskDescription != null) {
taskDescription.saveToXml(out);
@@ -7494,43 +7502,20 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
}
- static ActivityRecord restoreFromXml(XmlPullParser in,
+ static ActivityRecord restoreFromXml(TypedXmlPullParser in,
ActivityTaskSupervisor taskSupervisor) throws IOException, XmlPullParserException {
Intent intent = null;
PersistableBundle persistentState = null;
- int launchedFromUid = 0;
- String launchedFromPackage = null;
- String launchedFromFeature = null;
- String resolvedType = null;
- boolean componentSpecified = false;
- int userId = 0;
- long createTime = -1;
+ int launchedFromUid = in.getAttributeInt(null, ATTR_LAUNCHEDFROMUID, 0);
+ String launchedFromPackage = in.getAttributeValue(null, ATTR_LAUNCHEDFROMPACKAGE);
+ String launchedFromFeature = in.getAttributeValue(null, ATTR_LAUNCHEDFROMFEATURE);
+ String resolvedType = in.getAttributeValue(null, ATTR_RESOLVEDTYPE);
+ boolean componentSpecified = in.getAttributeBoolean(null, ATTR_COMPONENTSPECIFIED, false);
+ int userId = in.getAttributeInt(null, ATTR_USERID, 0);
+ long createTime = in.getAttributeLong(null, ATTR_ID, -1);
final int outerDepth = in.getDepth();
- TaskDescription taskDescription = new TaskDescription();
- for (int attrNdx = in.getAttributeCount() - 1; attrNdx >= 0; --attrNdx) {
- final String attrName = in.getAttributeName(attrNdx);
- final String attrValue = in.getAttributeValue(attrNdx);
- if (DEBUG) Slog.d(TaskPersister.TAG,
- "ActivityRecord: attribute name=" + attrName + " value=" + attrValue);
- if (ATTR_ID.equals(attrName)) {
- createTime = Long.parseLong(attrValue);
- } else if (ATTR_LAUNCHEDFROMUID.equals(attrName)) {
- launchedFromUid = Integer.parseInt(attrValue);
- } else if (ATTR_LAUNCHEDFROMPACKAGE.equals(attrName)) {
- launchedFromPackage = attrValue;
- } else if (ATTR_LAUNCHEDFROMFEATURE.equals(attrName)) {
- launchedFromFeature = attrValue;
- } else if (ATTR_RESOLVEDTYPE.equals(attrName)) {
- resolvedType = attrValue;
- } else if (ATTR_COMPONENTSPECIFIED.equals(attrName)) {
- componentSpecified = Boolean.parseBoolean(attrValue);
- } else if (ATTR_USERID.equals(attrName)) {
- userId = Integer.parseInt(attrValue);
- } else if (!attrName.startsWith(ATTR_TASKDESCRIPTION_PREFIX)) {
- Log.d(TAG, "Unknown ActivityRecord attribute=" + attrName);
- }
- }
+ TaskDescription taskDescription = new TaskDescription();
taskDescription.restoreFromXml(in);
int event;
@@ -7566,18 +7551,18 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
throw new XmlPullParserException("restoreActivity resolver error. Intent=" + intent +
" resolvedType=" + resolvedType);
}
- final ActivityRecord r = new ActivityRecord(service, null /* caller */,
- 0 /* launchedFromPid */, launchedFromUid, launchedFromPackage, launchedFromFeature,
- intent, resolvedType, aInfo, service.getConfiguration(), null /* resultTo */,
- null /* resultWho */, 0 /* reqCode */, componentSpecified,
- false /* rootVoiceInteraction */, taskSupervisor, null /* options */,
- null /* sourceRecord */);
-
- r.mPersistentState = persistentState;
- r.taskDescription = taskDescription;
- r.createTime = createTime;
-
- return r;
+ return new ActivityRecord.Builder(service)
+ .setLaunchedFromUid(launchedFromUid)
+ .setLaunchedFromPackage(launchedFromPackage)
+ .setLaunchedFromFeature(launchedFromFeature)
+ .setIntent(intent)
+ .setResolvedType(resolvedType)
+ .setActivityInfo(aInfo)
+ .setComponentSpecified(componentSpecified)
+ .setPersistentState(persistentState)
+ .setTaskDescription(taskDescription)
+ .setCreateTime(createTime)
+ .build();
}
private static boolean isInVrUiMode(Configuration config) {
@@ -8005,4 +7990,138 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
return false;
}
+
+ static class Builder {
+ private final ActivityTaskManagerService mAtmService;
+ private WindowProcessController mCallerApp;
+ private int mLaunchedFromPid;
+ private int mLaunchedFromUid;
+ private String mLaunchedFromPackage;
+ private String mLaunchedFromFeature;
+ private Intent mIntent;
+ private String mResolvedType;
+ private ActivityInfo mActivityInfo;
+ private Configuration mConfiguration;
+ private ActivityRecord mResultTo;
+ private String mResultWho;
+ private int mRequestCode;
+ private boolean mComponentSpecified;
+ private boolean mRootVoiceInteraction;
+ private ActivityOptions mOptions;
+ private ActivityRecord mSourceRecord;
+ private PersistableBundle mPersistentState;
+ private TaskDescription mTaskDescription;
+ private long mCreateTime;
+
+ Builder(ActivityTaskManagerService service) {
+ mAtmService = service;
+ }
+
+ Builder setCaller(@NonNull WindowProcessController caller) {
+ mCallerApp = caller;
+ return this;
+ }
+
+ Builder setLaunchedFromPid(int pid) {
+ mLaunchedFromPid = pid;
+ return this;
+ }
+
+ Builder setLaunchedFromUid(int uid) {
+ mLaunchedFromUid = uid;
+ return this;
+ }
+
+ Builder setLaunchedFromPackage(String fromPackage) {
+ mLaunchedFromPackage = fromPackage;
+ return this;
+ }
+
+ Builder setLaunchedFromFeature(String fromFeature) {
+ mLaunchedFromFeature = fromFeature;
+ return this;
+ }
+
+ Builder setIntent(Intent intent) {
+ mIntent = intent;
+ return this;
+ }
+
+ Builder setResolvedType(String resolvedType) {
+ mResolvedType = resolvedType;
+ return this;
+ }
+
+ Builder setActivityInfo(ActivityInfo activityInfo) {
+ mActivityInfo = activityInfo;
+ return this;
+ }
+
+ Builder setResultTo(ActivityRecord resultTo) {
+ mResultTo = resultTo;
+ return this;
+ }
+
+ Builder setResultWho(String resultWho) {
+ mResultWho = resultWho;
+ return this;
+ }
+
+ Builder setRequestCode(int reqCode) {
+ mRequestCode = reqCode;
+ return this;
+ }
+
+ Builder setComponentSpecified(boolean componentSpecified) {
+ mComponentSpecified = componentSpecified;
+ return this;
+ }
+
+ Builder setRootVoiceInteraction(boolean rootVoiceInteraction) {
+ mRootVoiceInteraction = rootVoiceInteraction;
+ return this;
+ }
+
+ Builder setActivityOptions(ActivityOptions options) {
+ mOptions = options;
+ return this;
+ }
+
+ Builder setConfiguration(Configuration config) {
+ mConfiguration = config;
+ return this;
+ }
+
+ Builder setSourceRecord(ActivityRecord source) {
+ mSourceRecord = source;
+ return this;
+ }
+
+ private Builder setPersistentState(PersistableBundle persistentState) {
+ mPersistentState = persistentState;
+ return this;
+ }
+
+ private Builder setTaskDescription(TaskDescription taskDescription) {
+ mTaskDescription = taskDescription;
+ return this;
+ }
+
+ private Builder setCreateTime(long createTime) {
+ mCreateTime = createTime;
+ return this;
+ }
+
+ ActivityRecord build() {
+ if (mConfiguration == null) {
+ mConfiguration = mAtmService.getConfiguration();
+ }
+ return new ActivityRecord(mAtmService, mCallerApp, mLaunchedFromPid,
+ mLaunchedFromUid, mLaunchedFromPackage, mLaunchedFromFeature, mIntent,
+ mResolvedType, mActivityInfo, mConfiguration, mResultTo, mResultWho,
+ mRequestCode, mComponentSpecified, mRootVoiceInteraction,
+ mAtmService.mTaskSupervisor, mOptions, mSourceRecord, mPersistentState,
+ mTaskDescription, mCreateTime);
+ }
+ }
}
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index b88b54ef08f5..1ff3a3fb1d35 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -664,7 +664,7 @@ class ActivityStarter {
synchronized (mService.mGlobalLock) {
final boolean globalConfigWillChange = mRequest.globalConfig != null
&& mService.getGlobalConfiguration().diff(mRequest.globalConfig) != 0;
- final Task stack = mRootWindowContainer.getTopDisplayFocusedStack();
+ final Task stack = mRootWindowContainer.getTopDisplayFocusedRootTask();
if (stack != null) {
stack.mConfigWillChange = globalConfigWillChange;
}
@@ -900,7 +900,7 @@ class ActivityStarter {
ActivityRecord sourceRecord = null;
ActivityRecord resultRecord = null;
if (resultTo != null) {
- sourceRecord = mRootWindowContainer.isInAnyStack(resultTo);
+ sourceRecord = mRootWindowContainer.isInAnyTask(resultTo);
if (DEBUG_RESULTS) {
Slog.v(TAG_RESULTS, "Will send result to " + resultTo + " " + sourceRecord);
}
@@ -1135,7 +1135,7 @@ class ActivityStarter {
if (DEBUG_PERMISSIONS_REVIEW) {
final Task focusedStack =
- mRootWindowContainer.getTopDisplayFocusedStack();
+ mRootWindowContainer.getTopDisplayFocusedRootTask();
Slog.i(TAG, "START u" + userId + " {" + intent.toShortString(true, true,
true, false) + "} from uid " + callingUid + " on display "
+ (focusedStack == null ? DEFAULT_DISPLAY
@@ -1161,12 +1161,25 @@ class ActivityStarter {
aInfo = mSupervisor.resolveActivity(intent, rInfo, startFlags, null /*profilerInfo*/);
}
+ final ActivityRecord r = new ActivityRecord.Builder(mService)
+ .setCaller(callerApp)
+ .setLaunchedFromPid(callingPid)
+ .setLaunchedFromUid(callingUid)
+ .setLaunchedFromPackage(callingPackage)
+ .setLaunchedFromFeature(callingFeatureId)
+ .setIntent(intent)
+ .setResolvedType(resolvedType)
+ .setActivityInfo(aInfo)
+ .setConfiguration(mService.getGlobalConfiguration())
+ .setResultTo(resultRecord)
+ .setResultWho(resultWho)
+ .setRequestCode(requestCode)
+ .setComponentSpecified(request.componentSpecified)
+ .setRootVoiceInteraction(voiceSession != null)
+ .setActivityOptions(checkedOptions)
+ .setSourceRecord(sourceRecord)
+ .build();
- final ActivityRecord r = new ActivityRecord(mService, callerApp, callingPid, callingUid,
- callingPackage, callingFeatureId, intent, resolvedType, aInfo,
- mService.getGlobalConfiguration(), resultRecord, resultWho, requestCode,
- request.componentSpecified, voiceSession != null, mSupervisor, checkedOptions,
- sourceRecord);
mLastStartActivityRecord = r;
if (r.appTimeTracker == null && sourceRecord != null) {
@@ -1175,7 +1188,7 @@ class ActivityStarter {
r.appTimeTracker = sourceRecord.appTimeTracker;
}
- final Task stack = mRootWindowContainer.getTopDisplayFocusedStack();
+ final Task stack = mRootWindowContainer.getTopDisplayFocusedRootTask();
// If we are starting an activity that is not from the same uid as the currently resumed
// one, check whether app switches are allowed.
@@ -1718,7 +1731,7 @@ class ActivityStarter {
// If the activity being launched is the same as the one currently at the top, then
// we need to check if it should only be launched once.
- final Task topStack = mRootWindowContainer.getTopDisplayFocusedStack();
+ final Task topStack = mRootWindowContainer.getTopDisplayFocusedRootTask();
if (topStack != null) {
startResult = deliverToCurrentTopIfNeeded(topStack, intentGrants);
if (startResult != START_SUCCESS) {
@@ -1806,14 +1819,14 @@ class ActivityStarter {
// task stack to be focusable, then ensure that we now update the focused stack
// accordingly.
if (mTargetStack.isTopActivityFocusable()
- && !mRootWindowContainer.isTopDisplayFocusedStack(mTargetStack)) {
+ && !mRootWindowContainer.isTopDisplayFocusedRootTask(mTargetStack)) {
mTargetStack.moveToFront("startActivityInner");
}
- mRootWindowContainer.resumeFocusedStacksTopActivities(
+ mRootWindowContainer.resumeFocusedTasksTopActivities(
mTargetStack, mStartActivity, mOptions);
}
}
- mRootWindowContainer.updateUserStack(mStartActivity.mUserId, mTargetStack);
+ mRootWindowContainer.updateUserRootTask(mStartActivity.mUserId, mTargetStack);
// Update the recent tasks list immediately when the activity starts
mSupervisor.mRecentTasks.add(mStartActivity.getTask());
@@ -1849,7 +1862,7 @@ class ActivityStarter {
private void computeLaunchParams(ActivityRecord r, ActivityRecord sourceRecord,
Task targetTask) {
final Task sourceStack = mSourceStack != null ? mSourceStack
- : mRootWindowContainer.getTopDisplayFocusedStack();
+ : mRootWindowContainer.getTopDisplayFocusedRootTask();
if (sourceStack != null && sourceStack.inSplitScreenWindowingMode()
&& (mOptions == null
|| mOptions.getLaunchWindowingMode() == WINDOWING_MODE_UNDEFINED)) {
@@ -2048,7 +2061,7 @@ class ActivityStarter {
// For paranoia, make sure we have correctly resumed the top activity.
topStack.mLastPausedActivity = null;
if (mDoResume) {
- mRootWindowContainer.resumeFocusedStacksTopActivities();
+ mRootWindowContainer.resumeFocusedTasksTopActivities();
}
ActivityOptions.abort(mOptions);
if ((mStartFlags & START_FLAG_ONLY_IF_NEEDED) != 0) {
@@ -2347,7 +2360,7 @@ class ActivityStarter {
if ((startFlags & START_FLAG_ONLY_IF_NEEDED) != 0) {
ActivityRecord checkedCaller = sourceRecord;
if (checkedCaller == null) {
- Task topFocusedStack = mRootWindowContainer.getTopDisplayFocusedStack();
+ Task topFocusedStack = mRootWindowContainer.getTopDisplayFocusedRootTask();
if (topFocusedStack != null) {
checkedCaller = topFocusedStack.topRunningNonDelayedActivityLocked(mNotTop);
}
@@ -2567,7 +2580,7 @@ class ActivityStarter {
// to the front if the caller is not itself in the front.
final boolean differentTopTask;
if (mTargetStack.getDisplayArea() == mPreferredTaskDisplayArea) {
- final Task focusStack = mTargetStack.mDisplayContent.getFocusedStack();
+ final Task focusStack = mTargetStack.mDisplayContent.getFocusedRootTask();
final ActivityRecord curTop = (focusStack == null)
? null : focusStack.topRunningNonDelayedActivityLocked(mNotTop);
final Task topTask = curTop != null ? curTop.getTask() : null;
@@ -2634,11 +2647,11 @@ class ActivityStarter {
if (next != null) {
next.setCurrentLaunchCanTurnScreenOn(true);
}
- mRootWindowContainer.resumeFocusedStacksTopActivities(mTargetStack, null, mOptions);
+ mRootWindowContainer.resumeFocusedTasksTopActivities(mTargetStack, null, mOptions);
} else {
ActivityOptions.abort(mOptions);
}
- mRootWindowContainer.updateUserStack(mStartActivity.mUserId, mTargetStack);
+ mRootWindowContainer.updateUserRootTask(mStartActivity.mUserId, mTargetStack);
}
private void setNewTask(Task taskToAffiliate) {
@@ -2713,7 +2726,7 @@ class ActivityStarter {
final boolean onTop =
(aOptions == null || !aOptions.getAvoidMoveToFront()) && !mLaunchTaskBehind;
- return mRootWindowContainer.getLaunchStack(r, aOptions, task, onTop, mLaunchParams,
+ return mRootWindowContainer.getLaunchRootTask(r, aOptions, task, onTop, mLaunchParams,
mRequest.realCallingPid, mRequest.realCallingUid);
}
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index e12dc2bd56a8..3710120a7934 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -1156,7 +1156,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
synchronized (mGlobalLock) {
// If this is coming from the currently resumed activity, it is
// effectively saying that app switches are allowed at this point.
- final Task stack = getTopDisplayFocusedStack();
+ final Task stack = getTopDisplayFocusedRootTask();
if (stack != null && stack.mResumedActivity != null
&& stack.mResumedActivity.info.applicationInfo.uid == Binder.getCallingUid()) {
mAppSwitchesAllowedTime = 0;
@@ -1470,7 +1470,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
sourceToken = resultTo;
}
- sourceRecord = mRootWindowContainer.isInAnyStack(sourceToken);
+ sourceRecord = mRootWindowContainer.isInAnyTask(sourceToken);
if (sourceRecord == null) {
throw new SecurityException("Called with bad activity token: " + sourceToken);
}
@@ -2039,7 +2039,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
public boolean isTopActivityImmersive() {
enforceNotIsolatedCaller("isTopActivityImmersive");
synchronized (mGlobalLock) {
- final Task topFocusedStack = getTopDisplayFocusedStack();
+ final Task topFocusedStack = getTopDisplayFocusedRootTask();
if (topFocusedStack == null) {
return false;
}
@@ -2074,7 +2074,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
public int getFrontActivityScreenCompatMode() {
enforceNotIsolatedCaller("getFrontActivityScreenCompatMode");
synchronized (mGlobalLock) {
- final Task stack = getTopDisplayFocusedStack();
+ final Task stack = getTopDisplayFocusedRootTask();
final ActivityRecord r = stack != null ? stack.topRunningActivity() : null;
if (r == null) {
return ActivityManager.COMPAT_MODE_UNKNOWN;
@@ -2089,7 +2089,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
"setFrontActivityScreenCompatMode");
ApplicationInfo ai;
synchronized (mGlobalLock) {
- final Task stack = getTopDisplayFocusedStack();
+ final Task stack = getTopDisplayFocusedRootTask();
final ActivityRecord r = stack != null ? stack.topRunningActivity() : null;
if (r == null) {
Slog.w(TAG, "setFrontActivityScreenCompatMode failed: no top activity");
@@ -2165,7 +2165,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
public void notifyActivityDrawn(IBinder token) {
if (DEBUG_VISIBILITY) Slog.d(TAG_VISIBILITY, "notifyActivityDrawn: token=" + token);
synchronized (mGlobalLock) {
- ActivityRecord r = mRootWindowContainer.isInAnyStack(token);
+ ActivityRecord r = mRootWindowContainer.isInAnyTask(token);
if (r != null) {
r.getRootTask().notifyActivityDrawnLocked(r);
}
@@ -2201,7 +2201,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
final long ident = Binder.clearCallingIdentity();
try {
synchronized (mGlobalLock) {
- Task focusedStack = getTopDisplayFocusedStack();
+ Task focusedStack = getTopDisplayFocusedRootTask();
if (focusedStack != null) {
return mRootWindowContainer.getRootTaskInfo(focusedStack.mTaskId);
}
@@ -2219,14 +2219,14 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
final long callingId = Binder.clearCallingIdentity();
try {
synchronized (mGlobalLock) {
- final Task task = mRootWindowContainer.getStack(taskId);
+ final Task task = mRootWindowContainer.getRootTask(taskId);
if (task == null) {
Slog.w(TAG, "setFocusedRootTask: No task with id=" + taskId);
return;
}
final ActivityRecord r = task.topRunningActivity();
if (r != null && r.moveFocusableActivityToTop("setFocusedRootTask")) {
- mRootWindowContainer.resumeFocusedStacksTopActivities();
+ mRootWindowContainer.resumeFocusedTasksTopActivities();
}
}
} finally {
@@ -2248,7 +2248,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
}
final ActivityRecord r = task.topRunningActivityLocked();
if (r != null && r.moveFocusableActivityToTop("setFocusedTask")) {
- mRootWindowContainer.resumeFocusedStacksTopActivities();
+ mRootWindowContainer.resumeFocusedTasksTopActivities();
}
}
} finally {
@@ -2508,7 +2508,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
synchronized (mGlobalLock) {
final long origId = Binder.clearCallingIdentity();
try {
- final Task topFocusedStack = getTopDisplayFocusedStack();
+ final Task topFocusedStack = getTopDisplayFocusedRootTask();
if (topFocusedStack != null) {
topFocusedStack.unhandledBackLocked();
}
@@ -2738,9 +2738,8 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
}
}
- @Override
- public List<ActivityManager.RunningTaskInfo> getTasks(int maxNum) {
- return getFilteredTasks(maxNum, false /* filterForVisibleRecents */);
+ List<ActivityManager.RunningTaskInfo> getTasks(int maxNum) {
+ return getTasks(maxNum, false /* filterForVisibleRecents */);
}
/**
@@ -2748,7 +2747,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
* be visible in the recent task list in systemui
*/
@Override
- public List<ActivityManager.RunningTaskInfo> getFilteredTasks(int maxNum,
+ public List<ActivityManager.RunningTaskInfo> getTasks(int maxNum,
boolean filterOnlyVisibleRecents) {
final int callingUid = Binder.getCallingUid();
final int callingPid = Binder.getCallingPid();
@@ -2821,7 +2820,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
ProtoLog.d(WM_DEBUG_TASKS, "moveTaskToRootTask: moving task=%d to "
+ "rootTaskId=%d toTop=%b", taskId, rootTaskId, toTop);
- final Task rootTask = mRootWindowContainer.getStack(rootTaskId);
+ final Task rootTask = mRootWindowContainer.getRootTask(rootTaskId);
if (rootTask == null) {
throw new IllegalStateException(
"moveTaskToRootTask: No rootTask for rootTaskId=" + rootTaskId);
@@ -3089,8 +3088,8 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
return;
}
- final Task stack = mRootWindowContainer.getTopDisplayFocusedStack();
- if (stack == null || task != stack.getTopMostTask()) {
+ final Task rootTask = mRootWindowContainer.getTopDisplayFocusedRootTask();
+ if (rootTask == null || task != rootTask.getTopMostTask()) {
throw new IllegalArgumentException("Invalid task, not in foreground");
}
@@ -3371,7 +3370,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
}
final Task stack = r.getRootTask();
- final Task task = stack.getDisplayArea().createStack(stack.getWindowingMode(),
+ final Task task = stack.getDisplayArea().createRootTask(stack.getWindowingMode(),
stack.getActivityType(), !ON_TOP, ainfo, intent,
false /* createdByOrganizer */);
@@ -3534,7 +3533,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
try {
ProtoLog.d(WM_DEBUG_TASKS, "moveRootTaskToDisplay: moving taskId=%d to "
+ "displayId=%d", taskId, displayId);
- mRootWindowContainer.moveStackToDisplay(taskId, displayId, ON_TOP);
+ mRootWindowContainer.moveRootTaskToDisplay(taskId, displayId, ON_TOP);
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -3742,7 +3741,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
"enqueueAssistContext()");
synchronized (mGlobalLock) {
- final Task stack = getTopDisplayFocusedStack();
+ final Task stack = getTopDisplayFocusedRootTask();
ActivityRecord activity = stack != null ? stack.getTopNonFinishingActivity() : null;
if (activity == null) {
Slog.w(TAG, "getAssistContextExtras failed: no top activity");
@@ -3871,7 +3870,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
public boolean isAssistDataAllowedOnCurrentActivity() {
int userId;
synchronized (mGlobalLock) {
- final Task focusedStack = getTopDisplayFocusedStack();
+ final Task focusedStack = getTopDisplayFocusedRootTask();
if (focusedStack == null || focusedStack.isActivityTypeAssistant()) {
return false;
}
@@ -3891,7 +3890,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
try {
synchronized (mGlobalLock) {
ActivityRecord caller = ActivityRecord.forTokenLocked(token);
- ActivityRecord top = getTopDisplayFocusedStack().getTopNonFinishingActivity();
+ ActivityRecord top = getTopDisplayFocusedRootTask().getTopNonFinishingActivity();
if (top != caller) {
Slog.w(TAG, "showAssistFromActivity failed: caller " + caller
+ " is not current top " + top);
@@ -4070,7 +4069,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
final long ident = Binder.clearCallingIdentity();
try {
- return mRootWindowContainer.moveTopStackActivityToPinnedRootTask(rootTaskId);
+ return mRootWindowContainer.moveTopRootTaskActivityToPinnedRootTask(rootTaskId);
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -4114,7 +4113,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
r.setPictureInPictureParams(params);
final float aspectRatio = r.pictureInPictureArgs.getAspectRatio();
final List<RemoteAction> actions = r.pictureInPictureArgs.getActions();
- mRootWindowContainer.moveActivityToPinnedStack(
+ mRootWindowContainer.moveActivityToPinnedRootTask(
r, "enterPictureInPictureMode");
final Task stack = r.getRootTask();
stack.setPictureInPictureAspectRatio(aspectRatio);
@@ -4346,7 +4345,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
public void startLocalVoiceInteraction(IBinder callingActivity, Bundle options) {
Slog.i(TAG, "Activity tried to startLocalVoiceInteraction");
synchronized (mGlobalLock) {
- ActivityRecord activity = getTopDisplayFocusedStack().getTopNonFinishingActivity();
+ ActivityRecord activity = getTopDisplayFocusedRootTask().getTopNonFinishingActivity();
if (ActivityRecord.forTokenLocked(callingActivity) != activity) {
throw new SecurityException("Only focused activity can call startVoiceInteraction");
}
@@ -4750,7 +4749,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
if (r.requestedVrComponent != null && r.getDisplayId() != DEFAULT_DISPLAY) {
Slog.i(TAG, "Moving " + r.shortComponentName + " from display " + r.getDisplayId()
+ " to main display for VR");
- mRootWindowContainer.moveStackToDisplay(
+ mRootWindowContainer.moveRootTaskToDisplay(
r.getRootTaskId(), DEFAULT_DISPLAY, true /* toTop */);
}
mH.post(() -> {
@@ -4814,8 +4813,8 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
}
}
- Task getTopDisplayFocusedStack() {
- return mRootWindowContainer.getTopDisplayFocusedStack();
+ Task getTopDisplayFocusedRootTask() {
+ return mRootWindowContainer.getTopDisplayFocusedRootTask();
}
/** Pokes the task persister. */
@@ -5828,7 +5827,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
/** Applies latest configuration and/or visibility updates if needed. */
boolean ensureConfigAndVisibilityAfterUpdate(ActivityRecord starting, int changes) {
boolean kept = true;
- final Task mainStack = mRootWindowContainer.getTopDisplayFocusedStack();
+ final Task mainStack = mRootWindowContainer.getTopDisplayFocusedRootTask();
// mainStack is null during startup.
if (mainStack != null) {
if (changes != 0 && starting == null) {
@@ -6083,8 +6082,8 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
static final int REPORT_TIME_TRACKER_MSG = 1;
- static final int FIRST_ACTIVITY_STACK_MSG = 100;
- static final int FIRST_SUPERVISOR_STACK_MSG = 200;
+ static final int FIRST_ACTIVITY_TASK_MSG = 100;
+ static final int FIRST_SUPERVISOR_TASK_MSG = 200;
H(Looper looper) {
super(looper);
@@ -6293,7 +6292,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
"setFocusedActivity: No activity record matching token=" + token);
}
if (r.moveFocusableActivityToTop("setFocusedActivity")) {
- mRootWindowContainer.resumeFocusedStacksTopActivities();
+ mRootWindowContainer.resumeFocusedTasksTopActivities();
}
}
}
@@ -6797,7 +6796,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
if (!restarting && hasVisibleActivities) {
deferWindowLayout();
try {
- if (!mRootWindowContainer.resumeFocusedStacksTopActivities()) {
+ if (!mRootWindowContainer.resumeFocusedTasksTopActivities()) {
// 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
@@ -6850,7 +6849,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
if (mRootWindowContainer.finishDisabledPackageActivities(
packageName, disabledClasses, true /* doit */, false /* evenPersistent */,
userId, false /* onlyRemoveNoProcess */) && booted) {
- mRootWindowContainer.resumeFocusedStacksTopActivities();
+ mRootWindowContainer.resumeFocusedTasksTopActivities();
mTaskSupervisor.scheduleIdle();
}
@@ -6880,7 +6879,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
@Override
public void resumeTopActivities(boolean scheduleIdle) {
synchronized (mGlobalLock) {
- mRootWindowContainer.resumeFocusedStacksTopActivities();
+ mRootWindowContainer.resumeFocusedTasksTopActivities();
if (scheduleIdle) {
mTaskSupervisor.scheduleIdle();
}
@@ -7057,7 +7056,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
mRootWindowContainer.dumpDisplayConfigs(pw, " ");
}
if (dumpAll) {
- final Task topFocusedStack = getTopDisplayFocusedStack();
+ final Task topFocusedStack = getTopDisplayFocusedRootTask();
if (dumpPackage == null && topFocusedStack != null) {
pw.println(" mConfigWillChange: " + topFocusedStack.mConfigWillChange);
}
@@ -7140,7 +7139,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
synchronized (mGlobalLock) {
if (dumpPackage == null) {
getGlobalConfiguration().dumpDebug(proto, GLOBAL_CONFIGURATION);
- final Task topFocusedStack = getTopDisplayFocusedStack();
+ final Task topFocusedStack = getTopDisplayFocusedRootTask();
if (topFocusedStack != null) {
proto.write(CONFIG_WILL_CHANGE, topFocusedStack.mConfigWillChange);
}
diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
index d0c26af82d99..73d99724c65f 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
@@ -63,7 +63,7 @@ import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_TASKS
import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.ActivityTaskManagerService.ANIMATE;
-import static com.android.server.wm.ActivityTaskManagerService.H.FIRST_SUPERVISOR_STACK_MSG;
+import static com.android.server.wm.ActivityTaskManagerService.H.FIRST_SUPERVISOR_TASK_MSG;
import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_NONE;
import static com.android.server.wm.LockTaskController.LOCK_TASK_AUTH_ALLOWLISTED;
import static com.android.server.wm.LockTaskController.LOCK_TASK_AUTH_LAUNCHABLE;
@@ -176,18 +176,18 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks {
/** How long we wait until giving up on the activity telling us it released the top state. */
private static final int TOP_RESUMED_STATE_LOSS_TIMEOUT = 500;
- private static final int IDLE_TIMEOUT_MSG = FIRST_SUPERVISOR_STACK_MSG;
- private static final int IDLE_NOW_MSG = FIRST_SUPERVISOR_STACK_MSG + 1;
- private static final int RESUME_TOP_ACTIVITY_MSG = FIRST_SUPERVISOR_STACK_MSG + 2;
- private static final int SLEEP_TIMEOUT_MSG = FIRST_SUPERVISOR_STACK_MSG + 3;
- private static final int LAUNCH_TIMEOUT_MSG = FIRST_SUPERVISOR_STACK_MSG + 4;
- private static final int PROCESS_STOPPING_AND_FINISHING_MSG = FIRST_SUPERVISOR_STACK_MSG + 5;
- private static final int LAUNCH_TASK_BEHIND_COMPLETE = FIRST_SUPERVISOR_STACK_MSG + 12;
- private static final int RESTART_ACTIVITY_PROCESS_TIMEOUT_MSG = FIRST_SUPERVISOR_STACK_MSG + 13;
- private static final int REPORT_MULTI_WINDOW_MODE_CHANGED_MSG = FIRST_SUPERVISOR_STACK_MSG + 14;
- private static final int REPORT_PIP_MODE_CHANGED_MSG = FIRST_SUPERVISOR_STACK_MSG + 15;
- private static final int START_HOME_MSG = FIRST_SUPERVISOR_STACK_MSG + 16;
- private static final int TOP_RESUMED_STATE_LOSS_TIMEOUT_MSG = FIRST_SUPERVISOR_STACK_MSG + 17;
+ private static final int IDLE_TIMEOUT_MSG = FIRST_SUPERVISOR_TASK_MSG;
+ private static final int IDLE_NOW_MSG = FIRST_SUPERVISOR_TASK_MSG + 1;
+ private static final int RESUME_TOP_ACTIVITY_MSG = FIRST_SUPERVISOR_TASK_MSG + 2;
+ private static final int SLEEP_TIMEOUT_MSG = FIRST_SUPERVISOR_TASK_MSG + 3;
+ private static final int LAUNCH_TIMEOUT_MSG = FIRST_SUPERVISOR_TASK_MSG + 4;
+ private static final int PROCESS_STOPPING_AND_FINISHING_MSG = FIRST_SUPERVISOR_TASK_MSG + 5;
+ private static final int LAUNCH_TASK_BEHIND_COMPLETE = FIRST_SUPERVISOR_TASK_MSG + 12;
+ private static final int RESTART_ACTIVITY_PROCESS_TIMEOUT_MSG = FIRST_SUPERVISOR_TASK_MSG + 13;
+ private static final int REPORT_MULTI_WINDOW_MODE_CHANGED_MSG = FIRST_SUPERVISOR_TASK_MSG + 14;
+ private static final int REPORT_PIP_MODE_CHANGED_MSG = FIRST_SUPERVISOR_TASK_MSG + 15;
+ private static final int START_HOME_MSG = FIRST_SUPERVISOR_TASK_MSG + 16;
+ private static final int TOP_RESUMED_STATE_LOSS_TIMEOUT_MSG = FIRST_SUPERVISOR_TASK_MSG + 17;
// Used to indicate that windows of activities should be preserved during the resize.
static final boolean PRESERVE_WINDOWS = true;
@@ -202,8 +202,8 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks {
// Used to indicate that a task is removed it should also be removed from recents.
static final boolean REMOVE_FROM_RECENTS = true;
- /** True if the docked stack is currently being resized. */
- private boolean mDockedStackResizing;
+ /** True if the docked root task is currently being resized. */
+ private boolean mDockedRootTaskResizing;
// Activity actions an app cannot start if it uses a permission which is not granted.
private static final ArrayMap<String, String> ACTION_TO_RUNTIME_PERMISSION =
@@ -307,7 +307,7 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks {
/** The target stack bounds for the picture-in-picture mode changed that we need to report to
* the application */
- private Rect mPipModeChangedTargetStackBounds;
+ private Rect mPipModeChangedTargetRootTaskBounds;
/** Used on user changes */
final ArrayList<UserState> mStartingUsers = new ArrayList<>();
@@ -386,17 +386,17 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks {
final ActivityRecord r;
final ActivityRecord sourceRecord;
final int startFlags;
- final Task stack;
+ final Task rootTask;
final WindowProcessController callerApp;
final NeededUriGrants intentGrants;
PendingActivityLaunch(ActivityRecord r, ActivityRecord sourceRecord,
- int startFlags, Task stack, WindowProcessController callerApp,
+ int startFlags, Task rootTask, WindowProcessController callerApp,
NeededUriGrants intentGrants) {
this.r = r;
this.sourceRecord = sourceRecord;
this.startFlags = startFlags;
- this.stack = stack;
+ this.rootTask = rootTask;
this.callerApp = callerApp;
this.intentGrants = intentGrants;
}
@@ -501,11 +501,11 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks {
getKeyguardController().setWindowManager(wm);
}
- void moveRecentsStackToFront(String reason) {
- final Task recentsStack = mRootWindowContainer.getDefaultTaskDisplayArea()
- .getStack(WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_RECENTS);
- if (recentsStack != null) {
- recentsStack.moveToFront(reason);
+ void moveRecentsRootTaskToFront(String reason) {
+ final Task recentsRootTask = mRootWindowContainer.getDefaultTaskDisplayArea()
+ .getRootTask(WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_RECENTS);
+ if (recentsRootTask != null) {
+ recentsRootTask.moveToFront(reason);
}
}
@@ -944,7 +944,7 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks {
// launching the initial activity (that is, home), so that it can have
// a chance to initialize itself while in the background, making the
// switch back to it faster and look better.
- if (mRootWindowContainer.isTopDisplayFocusedStack(rootTask)) {
+ if (mRootWindowContainer.isTopDisplayFocusedRootTask(rootTask)) {
mService.getActivityStartController().startSetupActivity();
}
@@ -1376,10 +1376,10 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks {
task.setBounds(bounds);
Task stack =
- mRootWindowContainer.getLaunchStack(null, options, task, ON_TOP);
+ mRootWindowContainer.getLaunchRootTask(null, options, task, ON_TOP);
if (stack != currentStack) {
- moveHomeStackToFrontIfNeeded(flags, stack.getDisplayArea(), reason);
+ moveHomeRootTaskToFrontIfNeeded(flags, stack.getDisplayArea(), reason);
task.reparent(stack, ON_TOP, REPARENT_KEEP_ROOT_TASK_AT_FRONT, !ANIMATE,
DEFER_RESUME, reason);
currentStack = stack;
@@ -1398,7 +1398,7 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks {
}
if (!reparented) {
- moveHomeStackToFrontIfNeeded(flags, currentStack.getDisplayArea(), reason);
+ moveHomeRootTaskToFrontIfNeeded(flags, currentStack.getDisplayArea(), reason);
}
final ActivityRecord r = task.getTopNonFinishingActivity();
@@ -1412,16 +1412,16 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks {
mRootWindowContainer.getDefaultTaskDisplayArea(), currentStack, forceNonResizeable);
}
- private void moveHomeStackToFrontIfNeeded(int flags, TaskDisplayArea taskDisplayArea,
+ private void moveHomeRootTaskToFrontIfNeeded(int flags, TaskDisplayArea taskDisplayArea,
String reason) {
- final Task focusedStack = taskDisplayArea.getFocusedStack();
+ final Task focusedRootTask = taskDisplayArea.getFocusedRootTask();
if ((taskDisplayArea.getWindowingMode() == WINDOWING_MODE_FULLSCREEN
&& (flags & ActivityManager.MOVE_TASK_WITH_HOME) != 0)
- || (focusedStack != null && focusedStack.isActivityTypeRecents())) {
+ || (focusedRootTask != null && focusedRootTask.isActivityTypeRecents())) {
// We move home stack to front when we are on a fullscreen display area and caller has
// requested the home activity to move with it. Or the previous stack is recents.
- taskDisplayArea.moveHomeStackToFront(reason);
+ taskDisplayArea.moveHomeRootTaskToFront(reason);
}
}
@@ -1441,15 +1441,15 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks {
}
void setSplitScreenResizing(boolean resizing) {
- if (resizing == mDockedStackResizing) {
+ if (resizing == mDockedRootTaskResizing) {
return;
}
- mDockedStackResizing = resizing;
+ mDockedRootTaskResizing = resizing;
mWindowManager.setDockedStackResizing(resizing);
}
- private void removePinnedStackInSurfaceTransaction(Task stack) {
+ private void removePinnedRootTaskInSurfaceTransaction(Task rootTask) {
/**
* Workaround: Force-stop all the activities in the pinned stack before we reparent them
* to the fullscreen stack. This is to guarantee that when we are removing a stack,
@@ -1459,9 +1459,9 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks {
* marked invisible as well and added to the stopping list. After which we process the
* stopping list by handling the idle.
*/
- stack.cancelAnimation();
- stack.setForceHidden(FLAG_FORCE_HIDDEN_FOR_PINNED_TASK, true /* set */);
- stack.ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS);
+ rootTask.cancelAnimation();
+ rootTask.setForceHidden(FLAG_FORCE_HIDDEN_FOR_PINNED_TASK, true /* set */);
+ rootTask.ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS);
activityIdleInternal(null /* idleActivity */, false /* fromTimeout */,
true /* processPausingActivities */, null /* configuration */);
@@ -1471,17 +1471,17 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks {
mService.deferWindowLayout();
try {
- stack.setWindowingMode(WINDOWING_MODE_UNDEFINED);
- if (stack.getWindowingMode() != WINDOWING_MODE_FREEFORM) {
- stack.setBounds(null);
+ rootTask.setWindowingMode(WINDOWING_MODE_UNDEFINED);
+ if (rootTask.getWindowingMode() != WINDOWING_MODE_FREEFORM) {
+ rootTask.setBounds(null);
}
- toDisplay.getDefaultTaskDisplayArea().positionTaskBehindHome(stack);
+ toDisplay.getDefaultTaskDisplayArea().positionTaskBehindHome(rootTask);
// Follow on the workaround: activities are kept force hidden till the new windowing
// mode is set.
- stack.setForceHidden(FLAG_FORCE_HIDDEN_FOR_PINNED_TASK, false /* set */);
+ rootTask.setForceHidden(FLAG_FORCE_HIDDEN_FOR_PINNED_TASK, false /* set */);
mRootWindowContainer.ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS);
- mRootWindowContainer.resumeFocusedStacksTopActivities();
+ mRootWindowContainer.resumeFocusedTasksTopActivities();
} finally {
mService.continueWindowLayout();
}
@@ -1489,7 +1489,7 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks {
private void removeRootTaskInSurfaceTransaction(Task rootTask) {
if (rootTask.getWindowingMode() == WINDOWING_MODE_PINNED) {
- removePinnedStackInSurfaceTransaction(rootTask);
+ removePinnedRootTaskInSurfaceTransaction(rootTask);
} else {
final PooledConsumer c = PooledLambda.obtainConsumer(
ActivityTaskSupervisor::processRemoveTask, this, PooledLambda.__(Task.class));
@@ -1627,7 +1627,7 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks {
*/
boolean restoreRecentTaskLocked(Task task, ActivityOptions aOptions, boolean onTop) {
final Task stack =
- mRootWindowContainer.getLaunchStack(null, aOptions, task, onTop);
+ mRootWindowContainer.getLaunchRootTask(null, aOptions, task, onTop);
final WindowContainer parent = task.getParent();
if (parent == stack || task == stack) {
@@ -1668,7 +1668,7 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks {
* the various checks on tasks that are going to be reparented from one stack to another.
*/
// TODO: Look into changing users to this method to DisplayContent.resolveWindowingMode()
- Task getReparentTargetStack(Task task, Task stack, boolean toTop) {
+ Task getReparentTargetRootTask(Task task, Task stack, boolean toTop) {
final Task prevStack = task.getRootTask();
final int rootTaskId = stack.mTaskId;
final boolean inMultiWindowMode = stack.inMultiWindowMode();
@@ -1709,7 +1709,7 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks {
if (prevStack != null) {
return prevStack;
}
- stack = stack.getDisplayArea().createStack(
+ stack = stack.getDisplayArea().createRootTask(
WINDOWING_MODE_FULLSCREEN, stack.getActivityType(), toTop);
}
return stack;
@@ -1739,7 +1739,7 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks {
boolean timedout = false;
final long endTime = System.currentTimeMillis() + timeout;
while (true) {
- if (!mRootWindowContainer.putStacksToSleep(
+ if (!mRootWindowContainer.putTasksToSleep(
true /* allowDelay */, true /* shuttingDown */)) {
long timeRemaining = endTime - System.currentTimeMillis();
if (timeRemaining > 0) {
@@ -1776,7 +1776,7 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks {
return;
}
- if (!mRootWindowContainer.putStacksToSleep(
+ if (!mRootWindowContainer.putTasksToSleep(
allowDelay, false /* shuttingDown */)) {
return;
}
@@ -1931,7 +1931,7 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks {
mService.getLockTaskController().dump(pw, prefix);
pw.print(prefix);
pw.println("mCurTaskIdForUser=" + mCurTaskIdForUser);
- pw.println(prefix + "mUserStackInFront=" + mRootWindowContainer.mUserStackInFront);
+ pw.println(prefix + "mUserRootTaskInFront=" + mRootWindowContainer.mUserRootTaskInFront);
pw.println(prefix + "mVisibilityTransactionDepth=" + mVisibilityTransactionDepth);
if (!mWaitingForActivityVisible.isEmpty()) {
pw.println(prefix + "mWaitingForActivityVisible=");
@@ -2058,7 +2058,7 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks {
*/
void updateTopResumedActivityIfNeeded() {
final ActivityRecord prevTopActivity = mTopResumedActivity;
- final Task topStack = mRootWindowContainer.getTopDisplayFocusedStack();
+ final Task topStack = mRootWindowContainer.getTopDisplayFocusedRootTask();
if (topStack == null || topStack.mResumedActivity == prevTopActivity) {
if (mService.isSleepingLocked()) {
// There won't be a next resumed activity. The top process should still be updated
@@ -2242,7 +2242,7 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks {
}
}
- void logStackState() {
+ void logRootTaskState() {
mActivityMetricsLogger.logWindowState();
}
@@ -2281,7 +2281,7 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks {
task.forAllActivities(c);
c.recycle();
- mPipModeChangedTargetStackBounds = targetStackBounds;
+ mPipModeChangedTargetRootTaskBounds = targetStackBounds;
if (!mHandler.hasMessages(REPORT_PIP_MODE_CHANGED_MSG)) {
mHandler.sendEmptyMessage(REPORT_PIP_MODE_CHANGED_MSG);
@@ -2436,7 +2436,7 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks {
case REPORT_PIP_MODE_CHANGED_MSG: {
for (int i = mPipModeChangedActivities.size() - 1; i >= 0; i--) {
final ActivityRecord r = mPipModeChangedActivities.remove(i);
- r.updatePictureInPictureMode(mPipModeChangedTargetStackBounds,
+ r.updatePictureInPictureMode(mPipModeChangedTargetRootTaskBounds,
false /* forceUpdate */);
}
} break;
@@ -2452,7 +2452,7 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks {
activityIdleFromMessage((ActivityRecord) msg.obj, false /* fromTimeout */);
} break;
case RESUME_TOP_ACTIVITY_MSG: {
- mRootWindowContainer.resumeFocusedStacksTopActivities();
+ mRootWindowContainer.resumeFocusedTasksTopActivities();
} break;
case SLEEP_TIMEOUT_MSG: {
if (mService.isSleepingOrShuttingDownLocked()) {
@@ -2542,7 +2542,7 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks {
// from whatever is started from the recents activity, so move the home stack
// forward.
// TODO (b/115289124): Multi-display supports for recents.
- mRootWindowContainer.getDefaultTaskDisplayArea().moveHomeStackToFront(
+ mRootWindowContainer.getDefaultTaskDisplayArea().moveHomeRootTaskToFront(
"startActivityFromRecents");
}
@@ -2570,6 +2570,11 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks {
mService.getActivityStartController().postStartActivityProcessingForLastStarter(
task.getTopNonFinishingActivity(), ActivityManager.START_TASK_TO_FRONT,
task.getRootTask());
+
+ // As it doesn't go to ActivityStarter.executeRequest() path, we need to resume
+ // app switching here also.
+ mService.resumeAppSwitches();
+
return ActivityManager.START_TASK_TO_FRONT;
}
callingPackage = task.mCallingPackage;
diff --git a/services/core/java/com/android/server/wm/AppWarnings.java b/services/core/java/com/android/server/wm/AppWarnings.java
index d40dea299ff6..55200b566979 100644
--- a/services/core/java/com/android/server/wm/AppWarnings.java
+++ b/services/core/java/com/android/server/wm/AppWarnings.java
@@ -492,7 +492,7 @@ class AppWarnings {
}
out.startTag(null, "package");
out.attribute(null, "name", pkg);
- out.attribute(null, "flags", Integer.toString(mode));
+ out.attributeInt(null, "flags", mode);
out.endTag(null, "package");
}
diff --git a/services/core/java/com/android/server/wm/CompatModePackages.java b/services/core/java/com/android/server/wm/CompatModePackages.java
index 89c5f62a252a..c22bd20da042 100644
--- a/services/core/java/com/android/server/wm/CompatModePackages.java
+++ b/services/core/java/com/android/server/wm/CompatModePackages.java
@@ -17,10 +17,10 @@
package com.android.server.wm;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_CONFIGURATION;
-import static com.android.server.wm.ActivityTaskSupervisor.PRESERVE_WINDOWS;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_CONFIGURATION;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.server.wm.ActivityTaskSupervisor.PRESERVE_WINDOWS;
import android.app.ActivityManager;
import android.app.AppGlobals;
@@ -43,7 +43,6 @@ import com.android.internal.protolog.common.ProtoLog;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
import java.io.File;
import java.io.FileInputStream;
@@ -113,14 +112,7 @@ public final class CompatModePackages {
if ("pkg".equals(tagName)) {
String pkg = parser.getAttributeValue(null, "name");
if (pkg != null) {
- String mode = parser.getAttributeValue(null, "mode");
- int modeInt = 0;
- if (mode != null) {
- try {
- modeInt = Integer.parseInt(mode);
- } catch (NumberFormatException e) {
- }
- }
+ int modeInt = parser.getAttributeInt(null, "mode", 0);
mPackages.put(pkg, modeInt);
}
}
@@ -321,7 +313,7 @@ public final class CompatModePackages {
scheduleWrite();
- final Task stack = mService.getTopDisplayFocusedStack();
+ final Task stack = mService.getTopDisplayFocusedRootTask();
ActivityRecord starting = stack.restartPackage(packageName);
// Tell all processes that loaded this package about the change.
@@ -396,7 +388,7 @@ public final class CompatModePackages {
}
out.startTag(null, "pkg");
out.attribute(null, "name", pkg);
- out.attribute(null, "mode", Integer.toString(mode));
+ out.attributeInt(null, "mode", mode);
out.endTag(null, "pkg");
}
diff --git a/services/core/java/com/android/server/wm/ConfigurationContainer.java b/services/core/java/com/android/server/wm/ConfigurationContainer.java
index 60a62dc0b64c..36a1ef9f49b4 100644
--- a/services/core/java/com/android/server/wm/ConfigurationContainer.java
+++ b/services/core/java/com/android/server/wm/ConfigurationContainer.java
@@ -182,6 +182,11 @@ public abstract class ConfigurationContainer<E extends ConfigurationContainer> {
// writing to proto (which has significant cost if we write a lot of empty configurations).
mHasOverrideConfiguration = !Configuration.EMPTY.equals(overrideConfiguration);
mRequestedOverrideConfiguration.setTo(overrideConfiguration);
+ final Rect newBounds = mRequestedOverrideConfiguration.windowConfiguration.getBounds();
+ if (mHasOverrideConfiguration && providesMaxBounds()
+ && diffRequestedOverrideMaxBounds(newBounds) != BOUNDS_CHANGE_NONE) {
+ mRequestedOverrideConfiguration.windowConfiguration.setMaxBounds(newBounds);
+ }
// Update full configuration of this container and all its children.
final ConfigurationContainer parent = getParent();
onConfigurationChanged(parent != null ? parent.getConfiguration() : Configuration.EMPTY);
@@ -341,9 +346,6 @@ public abstract class ConfigurationContainer<E extends ConfigurationContainer> {
mRequestsTmpConfig.setTo(getRequestedOverrideConfiguration());
mRequestsTmpConfig.windowConfiguration.setBounds(bounds);
- if (overrideMaxBounds) {
- mRequestsTmpConfig.windowConfiguration.setMaxBounds(bounds);
- }
onRequestedOverrideConfigurationChanged(mRequestsTmpConfig);
return boundsChange;
diff --git a/services/core/java/com/android/server/wm/DisplayArea.java b/services/core/java/com/android/server/wm/DisplayArea.java
index 48e030050b07..a4ac16f2ec77 100644
--- a/services/core/java/com/android/server/wm/DisplayArea.java
+++ b/services/core/java/com/android/server/wm/DisplayArea.java
@@ -33,7 +33,6 @@ import static com.android.server.wm.WindowContainerChildProto.DISPLAY_AREA;
import android.annotation.Nullable;
import android.content.res.Configuration;
import android.graphics.Rect;
-import android.os.IBinder;
import android.util.proto.ProtoOutputStream;
import android.window.DisplayAreaInfo;
import android.window.IDisplayAreaOrganizer;
@@ -151,12 +150,11 @@ public class DisplayArea<T extends WindowContainer> extends WindowContainer<T> {
}
@Override
- boolean onDescendantOrientationChanged(IBinder freezeDisplayToken,
- WindowContainer requestingContainer) {
+ boolean onDescendantOrientationChanged(WindowContainer requestingContainer) {
// If this is set to ignore the orientation request, we don't propagate descendant
// orientation request.
return !mIgnoreOrientationRequest
- && super.onDescendantOrientationChanged(freezeDisplayToken, requestingContainer);
+ && super.onDescendantOrientationChanged(requestingContainer);
}
/**
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index ccc85f834bc1..1d2cd0a0a350 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -55,6 +55,8 @@ import static android.view.WindowInsets.Type.displayCutout;
import static android.view.WindowInsets.Type.ime;
import static android.view.WindowInsets.Type.systemBars;
import static android.view.WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE;
+import static android.view.WindowManager.DISPLAY_IME_POLICY_FALLBACK_DISPLAY;
+import static android.view.WindowManager.DISPLAY_IME_POLICY_LOCAL;
import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
@@ -73,8 +75,6 @@ import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG;
import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;
import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
-import static android.view.WindowManager.DISPLAY_IME_POLICY_LOCAL;
-import static android.view.WindowManager.DISPLAY_IME_POLICY_FALLBACK_DISPLAY;
import static android.view.WindowManager.TRANSIT_OPEN;
import static android.view.WindowManager.TRANSIT_TO_FRONT;
import static android.window.DisplayAreaOrganizer.FEATURE_ROOT;
@@ -93,7 +93,6 @@ import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_C
import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
import static com.android.server.wm.DisplayContentProto.APP_TRANSITION;
-import static com.android.server.wm.DisplayContentProto.IME_POLICY;
import static com.android.server.wm.DisplayContentProto.CLOSING_APPS;
import static com.android.server.wm.DisplayContentProto.CURRENT_FOCUS;
import static com.android.server.wm.DisplayContentProto.DISPLAY_FRAMES;
@@ -105,6 +104,7 @@ import static com.android.server.wm.DisplayContentProto.FOCUSED_APP;
import static com.android.server.wm.DisplayContentProto.FOCUSED_ROOT_TASK_ID;
import static com.android.server.wm.DisplayContentProto.ID;
import static com.android.server.wm.DisplayContentProto.IME_INSETS_SOURCE_PROVIDER;
+import static com.android.server.wm.DisplayContentProto.IME_POLICY;
import static com.android.server.wm.DisplayContentProto.INPUT_METHOD_CONTROL_TARGET;
import static com.android.server.wm.DisplayContentProto.INPUT_METHOD_INPUT_TARGET;
import static com.android.server.wm.DisplayContentProto.INPUT_METHOD_TARGET;
@@ -559,6 +559,9 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
*/
InsetsControlTarget mInputMethodControlTarget;
+ /** The surface parent of the IME container. */
+ private SurfaceControl mInputMethodSurfaceParent;
+
/** If true hold off on modifying the animation layer of mInputMethodTarget */
boolean mInputMethodTargetWaitingAnim;
@@ -1300,10 +1303,9 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
}
@Override
- boolean onDescendantOrientationChanged(IBinder freezeDisplayToken,
- WindowContainer requestingContainer) {
+ boolean onDescendantOrientationChanged(WindowContainer requestingContainer) {
final Configuration config = updateOrientation(
- getRequestedOverrideConfiguration(), freezeDisplayToken, false /* forceUpdate */);
+ getRequestedOverrideConfiguration(), requestingContainer, false /* forceUpdate */);
// If display rotation class tells us that it doesn't consider app requested orientation,
// this display won't rotate just because of an app changes its requested orientation. Thus
// it indicates that this display chooses not to handle this request.
@@ -1318,7 +1320,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
false /* deferResume */, null /* result */);
activityRecord.frozenBeforeDestroy = true;
if (!kept) {
- mRootWindowContainer.resumeFocusedStacksTopActivities();
+ mRootWindowContainer.resumeFocusedTasksTopActivities();
}
} else {
// We have a new configuration to push so we need to update ATMS for now.
@@ -1355,11 +1357,11 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
* @param currentConfig The current requested override configuration (it is usually set from
* the last {@link #sendNewConfiguration}) of the display. It is used to
* check if the configuration container has the latest state.
- * @param freezeDisplayToken Freeze the app window token if the orientation is changed.
+ * @param freezeDisplayWindow Freeze the app window if the orientation is changed.
* @param forceUpdate See {@link DisplayRotation#updateRotationUnchecked(boolean)}
*/
- Configuration updateOrientation(Configuration currentConfig, IBinder freezeDisplayToken,
- boolean forceUpdate) {
+ Configuration updateOrientation(Configuration currentConfig,
+ WindowContainer freezeDisplayWindow, boolean forceUpdate) {
if (!mDisplayReady) {
return null;
}
@@ -1368,9 +1370,9 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
if (updateOrientation(forceUpdate)) {
// If we changed the orientation but mOrientationChangeComplete is already true,
// we used seamless rotation, and we don't need to freeze the screen.
- if (freezeDisplayToken != null && !mWmService.mRoot.mOrientationChangeComplete) {
- final ActivityRecord activity = getActivityRecord(freezeDisplayToken);
- if (activity != null) {
+ if (freezeDisplayWindow != null && !mWmService.mRoot.mOrientationChangeComplete) {
+ final ActivityRecord activity = freezeDisplayWindow.asActivityRecord();
+ if (activity != null && activity.mayFreezeScreenLocked()) {
activity.startFreezingScreen();
}
}
@@ -1677,6 +1679,28 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
}
}
+ void notifyInsetsChanged(Consumer<WindowState> dispatchInsetsChanged) {
+ if (mFixedRotationLaunchingApp != null) {
+ // The insets state of fixed rotation app is a rotated copy. Make sure the visibilities
+ // of insets sources are consistent with the latest state.
+ final InsetsState rotatedState =
+ mFixedRotationLaunchingApp.getFixedRotationTransformInsetsState();
+ if (rotatedState != null) {
+ final InsetsState state = mInsetsStateController.getRawInsetsState();
+ for (int i = 0; i < InsetsState.SIZE; i++) {
+ final InsetsSource source = state.peekSource(i);
+ if (source != null) {
+ rotatedState.setSourceVisible(i, source.isVisible());
+ }
+ }
+ }
+ }
+ forAllWindows(dispatchInsetsChanged, true /* traverseTopToBottom */);
+ if (mRemoteInsetsControlTarget != null) {
+ mRemoteInsetsControlTarget.notifyInsetsChanged();
+ }
+ }
+
/**
* Update rotation of the display.
*
@@ -2219,26 +2243,26 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
* activity type. Null is no compatible stack on the display.
*/
@Nullable
- Task getStack(int windowingMode, int activityType) {
+ Task getRootTask(int windowingMode, int activityType) {
return getItemFromTaskDisplayAreas(taskDisplayArea ->
- taskDisplayArea.getStack(windowingMode, activityType));
+ taskDisplayArea.getRootTask(windowingMode, activityType));
}
@Nullable
- Task getStack(int rootTaskId) {
+ Task getRootTask(int rootTaskId) {
return getItemFromTaskDisplayAreas(taskDisplayArea ->
- taskDisplayArea.getStack(rootTaskId));
+ taskDisplayArea.getRootTask(rootTaskId));
}
- protected int getStackCount() {
+ protected int getRootTaskCount() {
return reduceOnAllTaskDisplayAreas((taskDisplayArea, count) ->
- count + taskDisplayArea.getStackCount(), 0 /* initValue */);
+ count + taskDisplayArea.getRootTaskCount(), 0 /* initValue */);
}
@VisibleForTesting
@Nullable
- Task getTopStack() {
- return getItemFromTaskDisplayAreas(TaskDisplayArea::getTopStack);
+ Task getTopRootTask() {
+ return getItemFromTaskDisplayAreas(TaskDisplayArea::getTopRootTask);
}
/**
@@ -2902,7 +2926,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
mClosingApps.valueAt(i).writeIdentifierToProto(proto, CLOSING_APPS);
}
- final Task focusedStack = getFocusedStack();
+ final Task focusedStack = getFocusedRootTask();
if (focusedStack != null) {
proto.write(FOCUSED_ROOT_TASK_ID, focusedStack.getRootTaskId());
final ActivityRecord focusedActivity = focusedStack.getDisplayArea()
@@ -2946,7 +2970,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
public void dump(PrintWriter pw, String prefix, boolean dumpAll) {
super.dump(pw, prefix, dumpAll);
pw.print(prefix);
- pw.println("Display: mDisplayId=" + mDisplayId + " stacks=" + getStackCount());
+ pw.println("Display: mDisplayId=" + mDisplayId + " stacks=" + getRootTaskCount());
final String subPrefix = " " + prefix;
pw.print(subPrefix); pw.print("init="); pw.print(mInitialDisplayWidth); pw.print("x");
pw.print(mInitialDisplayHeight); pw.print(" "); pw.print(mInitialDisplayDensity);
@@ -3044,13 +3068,13 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
pw.println(prefix + "splitScreenPrimaryStack=" + splitScreenPrimaryStack.getName());
}
// TODO: Support recents on non-default task containers
- final Task recentsStack = getDefaultTaskDisplayArea().getStack(
+ final Task recentsStack = getDefaultTaskDisplayArea().getRootTask(
WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_RECENTS);
if (recentsStack != null) {
pw.println(prefix + "recentsStack=" + recentsStack.getName());
}
final Task dreamStack =
- getStack(WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_DREAM);
+ getRootTask(WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_DREAM);
if (dreamStack != null) {
pw.println(prefix + "dreamStack=" + dreamStack.getName());
}
@@ -3610,7 +3634,9 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
ProtoLog.i(WM_DEBUG_IME, "setInputMethodTarget %s", target);
mInputMethodTarget = target;
mInputMethodTargetWaitingAnim = targetWaitingAnim;
- assignWindowLayers(true /* setLayoutNeeded */);
+
+ // 1. Reparent the IME container window to the target root DA to get the correct bounds and
+ // config. (Only happens when the target window is in a different root DA)
if (target != null) {
RootDisplayArea targetRoot = target.getRootDisplayArea();
if (targetRoot != null) {
@@ -3619,7 +3645,13 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
targetRoot.placeImeContainer(mImeWindowsContainers);
}
}
+ // 2. Reparent the IME container surface to either the input target app, or the IME window
+ // parent.
updateImeParent();
+ // 3. Assign window layers based on the IME surface parent to make sure it is on top of the
+ // app.
+ assignWindowLayers(true /* setLayoutNeeded */);
+ // 4. Update the IME control target to apply any inset change and animation.
updateImeControlTarget();
}
@@ -3649,7 +3681,8 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
void updateImeParent() {
final SurfaceControl newParent = computeImeParent();
- if (newParent != null) {
+ if (newParent != null && newParent != mInputMethodSurfaceParent) {
+ mInputMethodSurfaceParent = newParent;
getPendingTransaction().reparent(mImeWindowsContainers.mSurfaceControl, newParent);
scheduleAnimation();
}
@@ -4426,18 +4459,15 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
//
// In the case of split-screen windowing mode, we need to elevate the IME above the
// docked divider while keeping the app itself below the docked divider, so instead
- // we use relative layering of the IME targets child windows, and place the IME in
- // the non-app layer (see {@link AboveAppWindowContainers#assignChildLayers}).
+ // we will put the docked divider below the IME. @see #assignRelativeLayerForImeTargetChild
//
// In the case the IME target is animating, the animation Z order may be different
// than the WindowContainer Z order, so it's difficult to be sure we have the correct
- // IME target. In this case we just layer the IME over all transitions by placing it
- // in the above applications layer.
+ // IME target. In this case we just layer the IME over its parent surface.
//
- // In the case where we have no IME target we assign it where its base layer would
- // place it in the AboveAppWindowContainers.
+ // In the case where we have no IME target we let its window parent to place it.
//
- // Keep IME window in mAboveAppWindowsContainers as long as app's starting window
+ // Keep IME window in surface parent as long as app's starting window
// exists so it get's layered above the starting window.
if (imeTarget != null && !(imeTarget.mActivityRecord != null
&& imeTarget.mActivityRecord.hasStartingWindow()) && (
@@ -4448,6 +4478,11 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
// TODO: We need to use an extra level on the app surface to ensure
// this is always above SurfaceView but always below attached window.
1);
+ } else if (mInputMethodSurfaceParent != null) {
+ // The IME surface parent may not be its window parent's surface
+ // (@see #computeImeParent), so set relative layer here instead of letting the window
+ // parent to assign layer.
+ mImeWindowsContainers.assignRelativeLayer(t, mInputMethodSurfaceParent, 1);
}
super.assignChildLayers(t);
}
@@ -4481,9 +4516,9 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
}
}
- void assignStackOrdering() {
+ void assignRootTaskOrdering() {
forAllTaskDisplayAreas(taskDisplayArea -> {
- taskDisplayArea.assignStackOrdering(getPendingTransaction());
+ taskDisplayArea.assignRootTaskOrdering(getPendingTransaction());
});
}
@@ -5048,7 +5083,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
mWmService.requestTraversal();
}
- static boolean alwaysCreateStack(int windowingMode, int activityType) {
+ static boolean alwaysCreateRootTask(int windowingMode, int activityType) {
// Always create a stack for fullscreen, freeform, and split-screen-secondary windowing
// modes so that we can manage visual ordering and return types correctly.
return activityType == ACTIVITY_TYPE_STANDARD
@@ -5062,13 +5097,13 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
static boolean canReuseExistingTask(int windowingMode, int activityType) {
// Existing Tasks can be reused if a new stack will be created anyway, or for the Dream -
// because there can only ever be one DreamActivity.
- return alwaysCreateStack(windowingMode, activityType)
+ return alwaysCreateRootTask(windowingMode, activityType)
|| activityType == ACTIVITY_TYPE_DREAM;
}
@Nullable
- Task getFocusedStack() {
- return getItemFromTaskDisplayAreas(TaskDisplayArea::getFocusedStack);
+ Task getFocusedRootTask() {
+ return getItemFromTaskDisplayAreas(TaskDisplayArea::getFocusedRootTask);
}
/**
@@ -5197,7 +5232,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
mCurrentOverrideConfigurationChanges = currOverrideConfig.diff(overrideConfiguration);
super.onRequestedOverrideConfigurationChanged(overrideConfiguration);
mCurrentOverrideConfigurationChanges = 0;
- mWmService.setNewDisplayOverrideConfiguration(overrideConfiguration, this);
+ mWmService.setNewDisplayOverrideConfiguration(currOverrideConfig, this);
mAtmService.addWindowLayoutReasons(
ActivityTaskManagerService.LAYOUT_REASON_CONFIG_CHANGED);
}
@@ -5305,19 +5340,19 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
// Check if all task display areas have only the empty home stacks left.
boolean hasNonEmptyHomeStack = forAllTaskDisplayAreas(taskDisplayArea -> {
- if (taskDisplayArea.getStackCount() != 1) {
+ if (taskDisplayArea.getRootTaskCount() != 1) {
return true;
}
- final Task stack = taskDisplayArea.getStackAt(0);
+ final Task stack = taskDisplayArea.getRootTaskAt(0);
return !stack.isActivityTypeHome() || stack.hasChild();
});
if (!hasNonEmptyHomeStack) {
// Release this display if only empty home stack(s) are left. This display will be
// released along with the stack(s) removal.
forAllTaskDisplayAreas(taskDisplayArea -> {
- taskDisplayArea.getStackAt(0).removeIfPossible();
+ taskDisplayArea.getRootTaskAt(0).removeIfPossible();
});
- } else if (getTopStack() == null) {
+ } else if (getTopRootTask() == null) {
removeIfPossible();
mRootWindowContainer.mTaskSupervisor
.getKeyguardController().onDisplayRemoved(mDisplayId);
@@ -5344,7 +5379,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
}
boolean shouldSleep() {
- return (getStackCount() == 0 || !mAllSleepTokens.isEmpty())
+ return (getRootTaskCount() == 0 || !mAllSleepTokens.isEmpty())
&& (mAtmService.mRunningVoice == null);
}
@@ -5689,4 +5724,8 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
}
return count;
}
+
+ MagnificationSpec getMagnificationSpec() {
+ return mMagnificationSpec;
+ }
}
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 042dd6db9800..2ddd00101769 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -66,7 +66,6 @@ import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DRAW_BA
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_SHOW_STATUS_BAR;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_INSET_PARENT_FRAME_BY_IME;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_INTERCEPT_GLOBAL_DRAG_AND_DROP;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_IS_SCREEN_DECOR;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
@@ -279,7 +278,6 @@ public class DisplayPolicy {
private volatile boolean mKeyguardDrawComplete;
private volatile boolean mWindowManagerDrawComplete;
- private final ArraySet<WindowState> mScreenDecorWindows = new ArraySet<>();
private WindowState mStatusBar = null;
private WindowState mNotificationShade = null;
private final int[] mStatusBarHeightForRotation = new int[4];
@@ -864,19 +862,7 @@ public class DisplayPolicy {
* @param attrs The window layout parameters to be modified. These values
* are modified in-place.
*/
- public void adjustWindowParamsLw(WindowState win, WindowManager.LayoutParams attrs,
- int callingPid, int callingUid) {
-
- final boolean isScreenDecor = (attrs.privateFlags & PRIVATE_FLAG_IS_SCREEN_DECOR) != 0;
- if (mScreenDecorWindows.contains(win)) {
- if (!isScreenDecor) {
- // No longer has the flag set, so remove from the set.
- mScreenDecorWindows.remove(win);
- }
- } else if (isScreenDecor && hasStatusBarServicePermission(callingPid, callingUid)) {
- mScreenDecorWindows.add(win);
- }
-
+ public void adjustWindowParamsLw(WindowState win, WindowManager.LayoutParams attrs) {
switch (attrs.type) {
case TYPE_SYSTEM_OVERLAY:
case TYPE_SECURE_SYSTEM_OVERLAY:
@@ -966,11 +952,6 @@ public class DisplayPolicy {
* WindowManagerImpl.ADD_MULTIPLE_SINGLETON
*/
int validateAddingWindowLw(WindowManager.LayoutParams attrs, int callingPid, int callingUid) {
- if ((attrs.privateFlags & PRIVATE_FLAG_IS_SCREEN_DECOR) != 0) {
- mContext.enforcePermission(
- android.Manifest.permission.STATUS_BAR_SERVICE, callingPid, callingUid,
- "DisplayPolicy");
- }
if ((attrs.privateFlags & PRIVATE_FLAG_TRUSTED_OVERLAY) != 0) {
mContext.enforcePermission(
android.Manifest.permission.INTERNAL_SYSTEM_WINDOW, callingPid, callingUid,
@@ -1090,10 +1071,6 @@ public class DisplayPolicy {
* @param attrs Information about the window to be added.
*/
void addWindowLw(WindowState win, WindowManager.LayoutParams attrs) {
- if ((attrs.privateFlags & PRIVATE_FLAG_IS_SCREEN_DECOR) != 0) {
- mScreenDecorWindows.add(win);
- }
-
switch (attrs.type) {
case TYPE_NOTIFICATION_SHADE:
mNotificationShade = win;
@@ -1275,7 +1252,6 @@ public class DisplayPolicy {
if (mLastFocusedWindow == win) {
mLastFocusedWindow = null;
}
- mScreenDecorWindows.remove(win);
}
private int getStatusBarHeight(DisplayFrames displayFrames) {
@@ -1457,14 +1433,12 @@ public class DisplayPolicy {
}
final int fl = attrs.flags;
- final int pfl = attrs.privateFlags;
final boolean layoutInScreenAndInsetDecor = (fl & FLAG_LAYOUT_IN_SCREEN) != 0
&& (fl & FLAG_LAYOUT_INSET_DECOR) != 0;
- final boolean screenDecor = (pfl & PRIVATE_FLAG_IS_SCREEN_DECOR) != 0;
final DisplayFrames displayFrames = isFixedRotationTransforming
? windowToken.getFixedRotationTransformDisplayFrames()
: mDisplayContent.mDisplayFrames;
- if (layoutInScreenAndInsetDecor && !screenDecor) {
+ if (layoutInScreenAndInsetDecor) {
outDisplayCutout.set(
displayFrames.mDisplayCutout.calculateRelativeTo(outFrame).getDisplayCutout());
} else {
@@ -1564,7 +1538,6 @@ public class DisplayPolicy {
simulatedWindowFrames, barContentFrames,
contentFrame -> layoutStatusBar(displayFrames, contentFrame));
}
- layoutScreenDecorWindows(displayFrames, simulatedWindowFrames);
}
/**
@@ -1585,7 +1558,6 @@ public class DisplayPolicy {
layoutNavigationBar(displayFrames, uiMode, null /* simulatedContentFrame */);
layoutStatusBar(displayFrames, null /* simulatedContentFrame */);
- layoutScreenDecorWindows(displayFrames, null /* simulatedFrames */);
}
void updateHideNavInputEventReceiver() {
@@ -1640,47 +1612,6 @@ public class DisplayPolicy {
state.getSource(ITYPE_BOTTOM_DISPLAY_CUTOUT).setFrame(u.left, s.bottom, u.right, u.bottom);
}
- /**
- * Layout the decor windows with {@link #PRIVATE_FLAG_IS_SCREEN_DECOR}.
- *
- * @param displayFrames The display frames to be layouted.
- * @param simulatedFrames Non-null if the caller only needs the result of display frames (see
- * {@link WindowState#mSimulatedWindowFrames}).
- */
- private void layoutScreenDecorWindows(DisplayFrames displayFrames,
- WindowFrames simulatedFrames) {
- if (mScreenDecorWindows.isEmpty()) {
- return;
- }
-
- sTmpRect.setEmpty();
- final int displayId = displayFrames.mDisplayId;
-
- for (int i = mScreenDecorWindows.size() - 1; i >= 0; --i) {
- final WindowState w = mScreenDecorWindows.valueAt(i);
- if (w.getDisplayId() != displayId || !w.isVisible()) {
- // Skip if not on the same display or not visible.
- continue;
- }
-
- final boolean isSimulatedLayout = simulatedFrames != null;
- if (isSimulatedLayout) {
- w.setSimulatedWindowFrames(simulatedFrames);
- }
- getRotatedWindowBounds(displayFrames, w, sTmpScreenDecorFrame);
- final WindowFrames windowFrames = w.getLayoutingWindowFrames();
- windowFrames.setFrames(sTmpScreenDecorFrame /* parentFrame */,
- sTmpScreenDecorFrame /* displayFrame */);
- try {
- w.computeFrame(displayFrames);
- } finally {
- if (isSimulatedLayout) {
- w.setSimulatedWindowFrames(null);
- }
- }
- }
- }
-
private void layoutStatusBar(DisplayFrames displayFrames, Rect simulatedContentFrame) {
// decide where the status bar goes ahead of time
if (mStatusBar == null) {
@@ -1819,8 +1750,7 @@ public class DisplayPolicy {
// We've already done the navigation bar, status bar, and all screen decor windows. If the
// status bar can receive input, we need to layout it again to accommodate for the IME
// window.
- if ((win == mStatusBar && !canReceiveInput(win)) || win == mNavigationBar
- || mScreenDecorWindows.contains(win)) {
+ if ((win == mStatusBar && !canReceiveInput(win)) || win == mNavigationBar) {
return;
}
final WindowManager.LayoutParams attrs = win.getAttrs();
@@ -2116,7 +2046,7 @@ public class DisplayPolicy {
// requests to hide the status bar. Not sure if there is another way that to be the
// case though.
if (!topIsFullscreen || mDisplayContent.getDefaultTaskDisplayArea()
- .isStackVisible(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY)) {
+ .isRootTaskVisible(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY)) {
topAppHidesStatusBar = false;
}
}
@@ -2900,9 +2830,9 @@ public class DisplayPolicy {
private int updateSystemBarsLw(WindowState win, int disableFlags) {
final boolean dockedStackVisible = mDisplayContent.getDefaultTaskDisplayArea()
- .isStackVisible(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
+ .isRootTaskVisible(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
final boolean freeformStackVisible = mDisplayContent.getDefaultTaskDisplayArea()
- .isStackVisible(WINDOWING_MODE_FREEFORM);
+ .isRootTaskVisible(WINDOWING_MODE_FREEFORM);
final boolean resizing = mDisplayContent.getDockedDividerController().isResizing();
// We need to force system bars when the docked stack is visible, when the freeform stack
diff --git a/services/core/java/com/android/server/wm/DisplayWindowSettingsProvider.java b/services/core/java/com/android/server/wm/DisplayWindowSettingsProvider.java
index 78f1426348a7..f4fdd7370e9c 100644
--- a/services/core/java/com/android/server/wm/DisplayWindowSettingsProvider.java
+++ b/services/core/java/com/android/server/wm/DisplayWindowSettingsProvider.java
@@ -16,9 +16,9 @@
package com.android.server.wm;
+import static android.view.WindowManager.DISPLAY_IME_POLICY_FALLBACK_DISPLAY;
import static android.view.WindowManager.DISPLAY_IME_POLICY_LOCAL;
import static android.view.WindowManager.REMOVE_CONTENT_MODE_UNDEFINED;
-import static android.view.WindowManager.DISPLAY_IME_POLICY_FALLBACK_DISPLAY;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
@@ -64,7 +64,7 @@ class DisplayWindowSettingsProvider implements SettingsProvider {
? "DisplayWindowSettingsProvider" : TAG_WM;
private static final String DATA_DISPLAY_SETTINGS_FILE_PATH = "system/display_settings.xml";
- private static final String VENDOR_DISPLAY_SETTINGS_PATH = "etc/display_settings.xml";
+ private static final String VENDOR_DISPLAY_SETTINGS_FILE_PATH = "etc/display_settings.xml";
private static final String WM_DISPLAY_COMMIT_TAG = "wm-displays";
private static final int IDENTIFIER_UNIQUE_ID = 0;
@@ -86,34 +86,8 @@ class DisplayWindowSettingsProvider implements SettingsProvider {
void finishWrite(OutputStream os, boolean success);
}
- private final ReadableSettingsStorage mVendorSettingsStorage;
- /**
- * The preferred type of a display identifier to use when storing and retrieving entries from
- * the base (vendor) settings file.
- *
- * @see #getIdentifier(DisplayInfo, int)
- */
- @DisplayIdentifierType
- private int mVendorIdentifierType;
- private final Map<String, SettingsEntry> mVendorSettings = new HashMap<>();
-
- private final WritableSettingsStorage mOverrideSettingsStorage;
- /**
- * The preferred type of a display identifier to use when storing and retrieving entries from
- * the data (override) settings file.
- *
- * @see #getIdentifier(DisplayInfo, int)
- */
- @DisplayIdentifierType
- private int mOverrideIdentifierType;
- private final Map<String, SettingsEntry> mOverrideSettings = new HashMap<>();
-
- /**
- * Enables or disables settings provided from the vendor settings storage.
- *
- * @see #setVendorSettingsIgnored(boolean)
- */
- private boolean mIgnoreVendorSettings = true;
+ private ReadableSettings mBaseSettings;
+ private final WritableSettings mOverrideSettings;
DisplayWindowSettingsProvider() {
this(new AtomicFileStorage(getVendorSettingsFile()),
@@ -121,43 +95,48 @@ class DisplayWindowSettingsProvider implements SettingsProvider {
}
@VisibleForTesting
- DisplayWindowSettingsProvider(@NonNull ReadableSettingsStorage vendorSettingsStorage,
+ DisplayWindowSettingsProvider(@NonNull ReadableSettingsStorage baseSettingsStorage,
@NonNull WritableSettingsStorage overrideSettingsStorage) {
- mVendorSettingsStorage = vendorSettingsStorage;
- mOverrideSettingsStorage = overrideSettingsStorage;
- readSettings();
+ mBaseSettings = new ReadableSettings(baseSettingsStorage);
+ mOverrideSettings = new WritableSettings(overrideSettingsStorage);
}
/**
- * Enables or disables settings provided from the vendor settings storage. If {@code true}, the
- * vendor settings will be ignored and only the override settings will be returned from
- * {@link #getSettings(DisplayInfo)}. If {@code false}, settings returned from
- * {@link #getSettings(DisplayInfo)} will be a merged result of the vendor settings and the
- * override settings.
+ * Overrides the path for the file that should be used to read base settings. If {@code null} is
+ * passed the default base settings file path will be used.
+ *
+ * @see #VENDOR_DISPLAY_SETTINGS_FILE_PATH
*/
- void setVendorSettingsIgnored(boolean ignored) {
- mIgnoreVendorSettings = ignored;
+ void setBaseSettingsFilePath(@Nullable String path) {
+ AtomicFile settingsFile;
+ if (path != null) {
+ settingsFile = new AtomicFile(new File(path), WM_DISPLAY_COMMIT_TAG);
+ } else {
+ settingsFile = getVendorSettingsFile();
+ }
+
+ setBaseSettingsStorage(new AtomicFileStorage(settingsFile));
}
/**
- * Returns whether or not the vendor settings are being ignored.
+ * Overrides the storage that should be used to read base settings.
*
- * @see #setVendorSettingsIgnored(boolean)
+ * @see #setBaseSettingsFilePath(String)
*/
@VisibleForTesting
- boolean getVendorSettingsIgnored() {
- return mIgnoreVendorSettings;
+ void setBaseSettingsStorage(@NonNull ReadableSettingsStorage baseSettingsStorage) {
+ mBaseSettings = new ReadableSettings(baseSettingsStorage);
}
@Override
@NonNull
public SettingsEntry getSettings(@NonNull DisplayInfo info) {
- SettingsEntry vendorSettings = getVendorSettingsEntry(info);
- SettingsEntry overrideSettings = getOrCreateOverrideSettingsEntry(info);
- if (vendorSettings == null) {
+ SettingsEntry baseSettings = mBaseSettings.getSettingsEntry(info);
+ SettingsEntry overrideSettings = mOverrideSettings.getOrCreateSettingsEntry(info);
+ if (baseSettings == null) {
return new SettingsEntry(overrideSettings);
} else {
- SettingsEntry mergedSettings = new SettingsEntry(vendorSettings);
+ SettingsEntry mergedSettings = new SettingsEntry(baseSettings);
mergedSettings.updateFrom(overrideSettings);
return mergedSettings;
}
@@ -166,99 +145,126 @@ class DisplayWindowSettingsProvider implements SettingsProvider {
@Override
@NonNull
public SettingsEntry getOverrideSettings(@NonNull DisplayInfo info) {
- return new SettingsEntry(getOrCreateOverrideSettingsEntry(info));
+ return new SettingsEntry(mOverrideSettings.getOrCreateSettingsEntry(info));
}
@Override
public void updateOverrideSettings(@NonNull DisplayInfo info,
@NonNull SettingsEntry overrides) {
- final SettingsEntry overrideSettings = getOrCreateOverrideSettingsEntry(info);
- boolean changed = overrideSettings.setTo(overrides);
- if (changed) {
- writeOverrideSettings();
- }
+ mOverrideSettings.updateSettingsEntry(info, overrides);
}
- @Nullable
- private SettingsEntry getVendorSettingsEntry(DisplayInfo info) {
- if (mIgnoreVendorSettings) {
+ /**
+ * Class that allows reading {@link SettingsEntry entries} from a
+ * {@link ReadableSettingsStorage}.
+ */
+ private static class ReadableSettings {
+ /**
+ * The preferred type of a display identifier to use when storing and retrieving entries
+ * from the settings entries.
+ *
+ * @see #getIdentifier(DisplayInfo)
+ */
+ @DisplayIdentifierType
+ protected int mIdentifierType;
+ protected final Map<String, SettingsEntry> mSettings = new HashMap<>();
+
+ ReadableSettings(ReadableSettingsStorage settingsStorage) {
+ loadSettings(settingsStorage);
+ }
+
+ @Nullable
+ final SettingsEntry getSettingsEntry(DisplayInfo info) {
+ final String identifier = getIdentifier(info);
+ SettingsEntry settings;
+ // Try to get corresponding settings using preferred identifier for the current config.
+ if ((settings = mSettings.get(identifier)) != null) {
+ return settings;
+ }
+ // Else, fall back to the display name.
+ if ((settings = mSettings.get(info.name)) != null) {
+ // Found an entry stored with old identifier.
+ mSettings.remove(info.name);
+ mSettings.put(identifier, settings);
+ return settings;
+ }
return null;
}
- final String identifier = getIdentifier(info, mVendorIdentifierType);
- SettingsEntry settings;
- // Try to get corresponding settings using preferred identifier for the current config.
- if ((settings = mVendorSettings.get(identifier)) != null) {
- return settings;
+ /** Gets the identifier of choice for the current config. */
+ protected final String getIdentifier(DisplayInfo displayInfo) {
+ if (mIdentifierType == IDENTIFIER_PORT && displayInfo.address != null) {
+ // Config suggests using port as identifier for physical displays.
+ if (displayInfo.address instanceof DisplayAddress.Physical) {
+ return "port:" + ((DisplayAddress.Physical) displayInfo.address).getPort();
+ }
+ }
+ return displayInfo.uniqueId;
}
- // Else, fall back to the display name.
- if ((settings = mVendorSettings.get(info.name)) != null) {
- // Found an entry stored with old identifier.
- mVendorSettings.remove(info.name);
- mVendorSettings.put(identifier, settings);
- return settings;
+
+ private void loadSettings(ReadableSettingsStorage settingsStorage) {
+ FileData fileData = readSettings(settingsStorage);
+ if (fileData != null) {
+ mIdentifierType = fileData.mIdentifierType;
+ mSettings.putAll(fileData.mSettings);
+ }
}
- return null;
}
- @NonNull
- private SettingsEntry getOrCreateOverrideSettingsEntry(DisplayInfo info) {
- final String identifier = getIdentifier(info, mOverrideIdentifierType);
- SettingsEntry settings;
- // Try to get corresponding settings using preferred identifier for the current config.
- if ((settings = mOverrideSettings.get(identifier)) != null) {
- return settings;
- }
- // Else, fall back to the display name.
- if ((settings = mOverrideSettings.get(info.name)) != null) {
- // Found an entry stored with old identifier.
- mOverrideSettings.remove(info.name);
- mOverrideSettings.put(identifier, settings);
- writeOverrideSettings();
- return settings;
+ /**
+ * Class that allows reading {@link SettingsEntry entries} from, and writing entries to, a
+ * {@link WritableSettingsStorage}.
+ */
+ private static final class WritableSettings extends ReadableSettings {
+ private final WritableSettingsStorage mSettingsStorage;
+
+ WritableSettings(WritableSettingsStorage settingsStorage) {
+ super(settingsStorage);
+ mSettingsStorage = settingsStorage;
}
- settings = new SettingsEntry();
- mOverrideSettings.put(identifier, settings);
- return settings;
- }
+ @NonNull
+ SettingsEntry getOrCreateSettingsEntry(DisplayInfo info) {
+ final String identifier = getIdentifier(info);
+ SettingsEntry settings;
+ // Try to get corresponding settings using preferred identifier for the current config.
+ if ((settings = mSettings.get(identifier)) != null) {
+ return settings;
+ }
+ // Else, fall back to the display name.
+ if ((settings = mSettings.get(info.name)) != null) {
+ // Found an entry stored with old identifier.
+ mSettings.remove(info.name);
+ mSettings.put(identifier, settings);
+ writeSettings();
+ return settings;
+ }
- private void readSettings() {
- FileData vendorFileData = readSettings(mVendorSettingsStorage);
- if (vendorFileData != null) {
- mVendorIdentifierType = vendorFileData.mIdentifierType;
- mVendorSettings.putAll(vendorFileData.mSettings);
+ settings = new SettingsEntry();
+ mSettings.put(identifier, settings);
+ return settings;
}
- FileData overrideFileData = readSettings(mOverrideSettingsStorage);
- if (overrideFileData != null) {
- mOverrideIdentifierType = overrideFileData.mIdentifierType;
- mOverrideSettings.putAll(overrideFileData.mSettings);
+ void updateSettingsEntry(DisplayInfo info, SettingsEntry settings) {
+ final SettingsEntry overrideSettings = getOrCreateSettingsEntry(info);
+ final boolean changed = overrideSettings.setTo(settings);
+ if (changed) {
+ writeSettings();
+ }
}
- }
- private void writeOverrideSettings() {
- FileData fileData = new FileData();
- fileData.mIdentifierType = mOverrideIdentifierType;
- fileData.mSettings.putAll(mOverrideSettings);
- writeSettings(mOverrideSettingsStorage, fileData);
- }
-
- /** Gets the identifier of choice for the current config. */
- private static String getIdentifier(DisplayInfo displayInfo, @DisplayIdentifierType int type) {
- if (type == IDENTIFIER_PORT && displayInfo.address != null) {
- // Config suggests using port as identifier for physical displays.
- if (displayInfo.address instanceof DisplayAddress.Physical) {
- return "port:" + ((DisplayAddress.Physical) displayInfo.address).getPort();
- }
+ private void writeSettings() {
+ FileData fileData = new FileData();
+ fileData.mIdentifierType = mIdentifierType;
+ fileData.mSettings.putAll(mSettings);
+ DisplayWindowSettingsProvider.writeSettings(mSettingsStorage, fileData);
}
- return displayInfo.uniqueId;
}
@NonNull
private static AtomicFile getVendorSettingsFile() {
final File vendorFile = new File(Environment.getVendorDirectory(),
- VENDOR_DISPLAY_SETTINGS_PATH);
+ VENDOR_DISPLAY_SETTINGS_FILE_PATH);
return new AtomicFile(vendorFile, WM_DISPLAY_COMMIT_TAG);
}
@@ -335,36 +341,31 @@ class DisplayWindowSettingsProvider implements SettingsProvider {
return fileData;
}
- private static int getIntAttribute(XmlPullParser parser, String name, int defaultValue) {
- try {
- final String str = parser.getAttributeValue(null, name);
- return str != null ? Integer.parseInt(str) : defaultValue;
- } catch (NumberFormatException e) {
- Slog.w(TAG, "Failed to parse display window settings attribute: " + name, e);
- return defaultValue;
- }
+ private static int getIntAttribute(TypedXmlPullParser parser, String name, int defaultValue) {
+ return parser.getAttributeInt(null, name, defaultValue);
}
@Nullable
- private static Integer getIntegerAttribute(XmlPullParser parser, String name,
+ private static Integer getIntegerAttribute(TypedXmlPullParser parser, String name,
@Nullable Integer defaultValue) {
try {
- final String str = parser.getAttributeValue(null, name);
- return str != null ? Integer.valueOf(str) : defaultValue;
- } catch (NumberFormatException e) {
- Slog.w(TAG, "Failed to parse display window settings attribute: " + name, e);
+ return parser.getAttributeInt(null, name);
+ } catch (Exception ignored) {
return defaultValue;
}
}
@Nullable
- private static Boolean getBooleanAttribute(XmlPullParser parser, String name,
+ private static Boolean getBooleanAttribute(TypedXmlPullParser parser, String name,
@Nullable Boolean defaultValue) {
- final String str = parser.getAttributeValue(null, name);
- return str != null ? Boolean.valueOf(str) : defaultValue;
+ try {
+ return parser.getAttributeBoolean(null, name);
+ } catch (Exception ignored) {
+ return defaultValue;
+ }
}
- private static void readDisplay(XmlPullParser parser, FileData fileData)
+ private static void readDisplay(TypedXmlPullParser parser, FileData fileData)
throws NumberFormatException, XmlPullParserException, IOException {
String name = parser.getAttributeValue(null, "name");
if (name != null) {
@@ -407,7 +408,7 @@ class DisplayWindowSettingsProvider implements SettingsProvider {
XmlUtils.skipCurrentTag(parser);
}
- private static void readConfig(XmlPullParser parser, FileData fileData)
+ private static void readConfig(TypedXmlPullParser parser, FileData fileData)
throws NumberFormatException,
XmlPullParserException, IOException {
fileData.mIdentifierType = getIntAttribute(parser, "identifier",
@@ -432,8 +433,7 @@ class DisplayWindowSettingsProvider implements SettingsProvider {
out.startTag(null, "display-settings");
out.startTag(null, "config");
- out.attribute(null, "identifier",
- Integer.toString(data.mIdentifierType));
+ out.attributeInt(null, "identifier", data.mIdentifierType);
out.endTag(null, "config");
for (Map.Entry<String, SettingsEntry> entry
@@ -447,8 +447,7 @@ class DisplayWindowSettingsProvider implements SettingsProvider {
out.startTag(null, "display");
out.attribute(null, "name", displayIdentifier);
if (settingsEntry.mWindowingMode != WindowConfiguration.WINDOWING_MODE_UNDEFINED) {
- out.attribute(null, "windowingMode",
- Integer.toString(settingsEntry.mWindowingMode));
+ out.attributeInt(null, "windowingMode", settingsEntry.mWindowingMode);
}
if (settingsEntry.mUserRotationMode != null) {
out.attribute(null, "userRotationMode",
@@ -459,22 +458,18 @@ class DisplayWindowSettingsProvider implements SettingsProvider {
settingsEntry.mUserRotation.toString());
}
if (settingsEntry.mForcedWidth != 0 && settingsEntry.mForcedHeight != 0) {
- out.attribute(null, "forcedWidth",
- Integer.toString(settingsEntry.mForcedWidth));
- out.attribute(null, "forcedHeight",
- Integer.toString(settingsEntry.mForcedHeight));
+ out.attributeInt(null, "forcedWidth", settingsEntry.mForcedWidth);
+ out.attributeInt(null, "forcedHeight", settingsEntry.mForcedHeight);
}
if (settingsEntry.mForcedDensity != 0) {
- out.attribute(null, "forcedDensity",
- Integer.toString(settingsEntry.mForcedDensity));
+ out.attributeInt(null, "forcedDensity", settingsEntry.mForcedDensity);
}
if (settingsEntry.mForcedScalingMode != null) {
out.attribute(null, "forcedScalingMode",
settingsEntry.mForcedScalingMode.toString());
}
if (settingsEntry.mRemoveContentMode != REMOVE_CONTENT_MODE_UNDEFINED) {
- out.attribute(null, "removeContentMode",
- Integer.toString(settingsEntry.mRemoveContentMode));
+ out.attributeInt(null, "removeContentMode", settingsEntry.mRemoveContentMode);
}
if (settingsEntry.mShouldShowWithInsecureKeyguard != null) {
out.attribute(null, "shouldShowWithInsecureKeyguard",
diff --git a/services/core/java/com/android/server/wm/HighRefreshRateDenylist.java b/services/core/java/com/android/server/wm/HighRefreshRateDenylist.java
index cdc14cd11228..92baadf5ee69 100644
--- a/services/core/java/com/android/server/wm/HighRefreshRateDenylist.java
+++ b/services/core/java/com/android/server/wm/HighRefreshRateDenylist.java
@@ -27,7 +27,7 @@ import android.util.ArraySet;
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.BackgroundThread;
-import com.android.server.wm.utils.DeviceConfigInterface;
+import com.android.server.utils.DeviceConfigInterface;
import java.io.PrintWriter;
diff --git a/services/core/java/com/android/server/wm/ImpressionAttestationController.java b/services/core/java/com/android/server/wm/ImpressionAttestationController.java
index 4793e1b6fb9f..b0afc57b647b 100644
--- a/services/core/java/com/android/server/wm/ImpressionAttestationController.java
+++ b/services/core/java/com/android/server/wm/ImpressionAttestationController.java
@@ -18,6 +18,9 @@ package com.android.server.wm;
import static android.service.attestation.ImpressionAttestationService.SERVICE_META_DATA_KEY_AVAILABLE_ALGORITHMS;
+import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+
import android.Manifest;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -29,7 +32,9 @@ import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.content.res.Resources;
+import android.graphics.Matrix;
import android.graphics.Rect;
+import android.graphics.RectF;
import android.hardware.HardwareBuffer;
import android.os.Binder;
import android.os.Bundle;
@@ -43,6 +48,7 @@ import android.service.attestation.IImpressionAttestationService;
import android.service.attestation.ImpressionAttestationService;
import android.service.attestation.ImpressionToken;
import android.util.Slog;
+import android.view.MagnificationSpec;
import com.android.internal.annotations.GuardedBy;
@@ -59,7 +65,8 @@ import java.util.function.BiConsumer;
* blocking calls into another service.
*/
public class ImpressionAttestationController {
- private static final String TAG = "ImpressionAttestationController";
+ private static final String TAG =
+ TAG_WITH_CLASS_NAME ? "ImpressionAttestationController" : TAG_WM;
private static final boolean DEBUG = false;
private final Object mServiceConnectionLock = new Object();
@@ -81,6 +88,10 @@ public class ImpressionAttestationController {
private final String mSalt;
+ private final float[] mTmpFloat9 = new float[9];
+ private final Matrix mTmpMatrix = new Matrix();
+ private final RectF mTmpRectF = new RectF();
+
private interface Command {
void run(IImpressionAttestationService service) throws RemoteException;
}
@@ -151,6 +162,79 @@ public class ImpressionAttestationController {
}
/**
+ * Calculate the bounds to take the screenshot when generating the impression token. This takes
+ * into account window transform, magnification, and display bounds.
+ *
+ * Call while holding {@link WindowManagerService#mGlobalLock}
+ *
+ * @param win Window that the impression token is generated for.
+ * @param boundsInWindow The bounds passed in about where in the window to take the screenshot.
+ * @param outBounds The result of the calculated bounds
+ */
+ void calculateImpressionTokenBoundsLocked(WindowState win, Rect boundsInWindow,
+ Rect outBounds) {
+ if (DEBUG) {
+ Slog.d(TAG, "calculateImpressionTokenBounds: boundsInWindow=" + boundsInWindow);
+ }
+ outBounds.set(boundsInWindow);
+
+ DisplayContent displayContent = win.getDisplayContent();
+ if (displayContent == null) {
+ return;
+ }
+
+ // Intersect boundsInWindow with the window to make sure it's not outside the window
+ // requesting the token. Offset the window bounds to 0,0 since the boundsInWindow are
+ // offset from the window location, not display.
+ final Rect windowBounds = new Rect();
+ win.getBounds(windowBounds);
+ windowBounds.offsetTo(0, 0);
+ outBounds.intersectUnchecked(windowBounds);
+
+ if (DEBUG) {
+ Slog.d(TAG, "calculateImpressionTokenBounds: boundsIntersectWindow=" + outBounds);
+ }
+
+ if (outBounds.isEmpty()) {
+ return;
+ }
+
+ // Transform the bounds using the window transform in case there's a scale or offset.
+ // This allows the bounds to be in display space.
+ win.getTransformationMatrix(mTmpFloat9, mTmpMatrix);
+ mTmpRectF.set(outBounds);
+ mTmpMatrix.mapRect(mTmpRectF, mTmpRectF);
+ outBounds.set((int) mTmpRectF.left, (int) mTmpRectF.top, (int) mTmpRectF.right,
+ (int) mTmpRectF.bottom);
+ if (DEBUG) {
+ Slog.d(TAG, "calculateImpressionTokenBounds: boundsInDisplay=" + outBounds);
+ }
+
+ // Apply the magnification spec values to the bounds since the content could be magnified
+ final MagnificationSpec magSpec = displayContent.getMagnificationSpec();
+ if (magSpec != null) {
+ outBounds.scale(magSpec.scale);
+ outBounds.offset((int) magSpec.offsetX, (int) magSpec.offsetY);
+ }
+
+ if (DEBUG) {
+ Slog.d(TAG, "calculateImpressionTokenBounds: boundsWithMagnification=" + outBounds);
+ }
+
+ if (outBounds.isEmpty()) {
+ return;
+ }
+
+ // Intersect with the display bounds since it shouldn't take a screenshot of content
+ // outside the display since it's not visible to the user.
+ final Rect displayBounds = displayContent.getBounds();
+ outBounds.intersectUnchecked(displayBounds);
+ if (DEBUG) {
+ Slog.d(TAG, "calculateImpressionTokenBounds: finalBounds=" + outBounds);
+ }
+ }
+
+ /**
* Run a command, starting the service connection if necessary.
*/
private void connectAndRun(@NonNull Command command) {
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index b49d83d93d54..25d779f0fb33 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -40,6 +40,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL;
import static android.view.WindowManager.LayoutParams.TYPE_NOTIFICATION_SHADE;
import static android.view.WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
+import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION;
import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_FOCUS_LIGHT;
@@ -655,6 +656,7 @@ final class InputMonitor {
|| type == TYPE_SECURE_SYSTEM_OVERLAY
|| type == TYPE_DOCK_DIVIDER
|| type == TYPE_ACCESSIBILITY_OVERLAY
- || type == TYPE_INPUT_CONSUMER;
+ || type == TYPE_INPUT_CONSUMER
+ || type == TYPE_VOICE_INTERACTION;
}
}
diff --git a/services/core/java/com/android/server/wm/InsetsPolicy.java b/services/core/java/com/android/server/wm/InsetsPolicy.java
index d308766b9fe5..ee150c31184c 100644
--- a/services/core/java/com/android/server/wm/InsetsPolicy.java
+++ b/services/core/java/com/android/server/wm/InsetsPolicy.java
@@ -392,9 +392,9 @@ class InsetsPolicy {
private boolean forceShowsSystemBarsForWindowingMode() {
final boolean isDockedStackVisible = mDisplayContent.getDefaultTaskDisplayArea()
- .isStackVisible(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
+ .isRootTaskVisible(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
final boolean isFreeformStackVisible = mDisplayContent.getDefaultTaskDisplayArea()
- .isStackVisible(WINDOWING_MODE_FREEFORM);
+ .isRootTaskVisible(WINDOWING_MODE_FREEFORM);
final boolean isResizing = mDisplayContent.getDockedDividerController().isResizing();
// We need to force system bars when the docked stack is visible, when the freeform stack
diff --git a/services/core/java/com/android/server/wm/InsetsStateController.java b/services/core/java/com/android/server/wm/InsetsStateController.java
index 9d70fd771f31..752d6b4fc908 100644
--- a/services/core/java/com/android/server/wm/InsetsStateController.java
+++ b/services/core/java/com/android/server/wm/InsetsStateController.java
@@ -496,10 +496,7 @@ class InsetsStateController {
}
void notifyInsetsChanged() {
- mDisplayContent.forAllWindows(mDispatchInsetsChanged, true /* traverseTopToBottom */);
- if (mDisplayContent.mRemoteInsetsControlTarget != null) {
- mDisplayContent.mRemoteInsetsControlTarget.notifyInsetsChanged();
- }
+ mDisplayContent.notifyInsetsChanged(mDispatchInsetsChanged);
}
void dump(String prefix, PrintWriter pw) {
diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java
index ebd91a093326..e45310a99fbd 100644
--- a/services/core/java/com/android/server/wm/KeyguardController.java
+++ b/services/core/java/com/android/server/wm/KeyguardController.java
@@ -211,7 +211,7 @@ class KeyguardController {
updateKeyguardSleepToken();
// Some stack visibility might change (e.g. docked stack)
- mRootWindowContainer.resumeFocusedStacksTopActivities();
+ mRootWindowContainer.resumeFocusedTasksTopActivities();
mRootWindowContainer.ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS);
mRootWindowContainer.addStartingWindowsForVisibleActivities();
mWindowManager.executeAppTransition();
@@ -595,8 +595,8 @@ class KeyguardController {
@Nullable
private Task getRootTaskForControllingOccluding(DisplayContent display) {
return display.getItemFromTaskDisplayAreas(taskDisplayArea -> {
- for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {
- final Task task = taskDisplayArea.getStackAt(sNdx);
+ for (int sNdx = taskDisplayArea.getRootTaskCount() - 1; sNdx >= 0; --sNdx) {
+ final Task task = taskDisplayArea.getRootTaskAt(sNdx);
if (task != null && task.isFocusableAndVisible()
&& !task.inPinnedWindowingMode()) {
return task;
diff --git a/services/core/java/com/android/server/wm/LaunchParamsController.java b/services/core/java/com/android/server/wm/LaunchParamsController.java
index b6b172eeae5b..8745e95dba4d 100644
--- a/services/core/java/com/android/server/wm/LaunchParamsController.java
+++ b/services/core/java/com/android/server/wm/LaunchParamsController.java
@@ -143,7 +143,7 @@ class LaunchParamsController {
try {
if (mTmpParams.mPreferredTaskDisplayArea != null
&& task.getDisplayArea() != mTmpParams.mPreferredTaskDisplayArea) {
- mService.mRootWindowContainer.moveStackToTaskDisplayArea(task.getRootTaskId(),
+ mService.mRootWindowContainer.moveRootTaskToTaskDisplayArea(task.getRootTaskId(),
mTmpParams.mPreferredTaskDisplayArea, true /* onTop */);
}
diff --git a/services/core/java/com/android/server/wm/LaunchParamsPersister.java b/services/core/java/com/android/server/wm/LaunchParamsPersister.java
index 2f8cfdd7002c..391e6598dca2 100644
--- a/services/core/java/com/android/server/wm/LaunchParamsPersister.java
+++ b/services/core/java/com/android/server/wm/LaunchParamsPersister.java
@@ -27,26 +27,24 @@ import android.util.ArraySet;
import android.util.AtomicFile;
import android.util.Slog;
import android.util.SparseArray;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
import android.util.Xml;
import android.view.DisplayInfo;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.FastXmlSerializer;
import com.android.server.LocalServices;
import com.android.server.pm.PackageList;
import com.android.server.wm.LaunchParamsController.LaunchParams;
-import libcore.io.IoUtils;
-
import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlSerializer;
-import java.io.BufferedReader;
+import java.io.ByteArrayOutputStream;
import java.io.File;
+import java.io.FileInputStream;
import java.io.FileOutputStream;
-import java.io.FileReader;
import java.io.IOException;
-import java.io.StringWriter;
+import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@@ -195,12 +193,9 @@ class LaunchParamsPersister {
continue;
}
- BufferedReader reader = null;
- try {
- reader = new BufferedReader(new FileReader(paramsFile));
+ try (InputStream in = new FileInputStream(paramsFile)) {
final PersistableLaunchParams params = new PersistableLaunchParams();
- final XmlPullParser parser = Xml.newPullParser();
- parser.setInput(reader);
+ final TypedXmlPullParser parser = Xml.resolvePullParser(in);
int event;
while ((event = parser.next()) != XmlPullParser.END_DOCUMENT
&& event != XmlPullParser.END_TAG) {
@@ -223,8 +218,6 @@ class LaunchParamsPersister {
} catch (Exception e) {
Slog.w(TAG, "Failed to restore launch params for " + name, e);
filesToDelete.add(paramsFile);
- } finally {
- IoUtils.closeQuietly(reader);
}
}
@@ -410,12 +403,11 @@ class LaunchParamsPersister {
mLaunchParams = launchParams;
}
- private StringWriter saveParamsToXml() {
- final StringWriter writer = new StringWriter();
- final XmlSerializer serializer = new FastXmlSerializer();
-
+ private byte[] saveParamsToXml() {
try {
- serializer.setOutput(writer);
+ final ByteArrayOutputStream os = new ByteArrayOutputStream();
+ final TypedXmlSerializer serializer = Xml.resolveSerializer(os);
+
serializer.startDocument(/* encoding */ null, /* standalone */ true);
serializer.startTag(null, TAG_LAUNCH_PARAMS);
@@ -425,7 +417,7 @@ class LaunchParamsPersister {
serializer.endDocument();
serializer.flush();
- return writer;
+ return os.toByteArray();
} catch (IOException e) {
return null;
}
@@ -433,7 +425,7 @@ class LaunchParamsPersister {
@Override
public void process() {
- final StringWriter writer = saveParamsToXml();
+ final byte[] data = saveParamsToXml();
final File launchParamFolder = getLaunchParamFolder(mUserId);
if (!launchParamFolder.isDirectory() && !launchParamFolder.mkdirs()) {
@@ -447,7 +439,7 @@ class LaunchParamsPersister {
FileOutputStream stream = null;
try {
stream = atomicFile.startWrite();
- stream.write(writer.toString().getBytes());
+ stream.write(data);
} catch (Exception e) {
Slog.e(TAG, "Failed to write param file for " + mComponentName, e);
if (stream != null) {
@@ -513,17 +505,16 @@ class LaunchParamsPersister {
*/
long mTimestamp;
- void saveToXml(XmlSerializer serializer) throws IOException {
+ void saveToXml(TypedXmlSerializer serializer) throws IOException {
serializer.attribute(null, ATTR_DISPLAY_UNIQUE_ID, mDisplayUniqueId);
- serializer.attribute(null, ATTR_WINDOWING_MODE,
- Integer.toString(mWindowingMode));
+ serializer.attributeInt(null, ATTR_WINDOWING_MODE, mWindowingMode);
serializer.attribute(null, ATTR_BOUNDS, mBounds.flattenToString());
if (mWindowLayoutAffinity != null) {
serializer.attribute(null, ATTR_WINDOW_LAYOUT_AFFINITY, mWindowLayoutAffinity);
}
}
- void restore(File xmlFile, XmlPullParser parser) {
+ void restore(File xmlFile, TypedXmlPullParser parser) {
for (int i = 0; i < parser.getAttributeCount(); ++i) {
final String attrValue = parser.getAttributeValue(i);
switch (parser.getAttributeName(i)) {
diff --git a/services/core/java/com/android/server/wm/LockTaskController.java b/services/core/java/com/android/server/wm/LockTaskController.java
index ee3978746488..4b3a43432fc5 100644
--- a/services/core/java/com/android/server/wm/LockTaskController.java
+++ b/services/core/java/com/android/server/wm/LockTaskController.java
@@ -504,7 +504,7 @@ public class LockTaskController {
return;
}
task.performClearTaskLocked();
- mSupervisor.mRootWindowContainer.resumeFocusedStacksTopActivities();
+ mSupervisor.mRootWindowContainer.resumeFocusedTasksTopActivities();
}
/**
@@ -640,7 +640,7 @@ public class LockTaskController {
if (andResume) {
mSupervisor.findTaskToMoveToFront(task, 0, null, reason,
lockTaskModeState != LOCK_TASK_MODE_NONE);
- mSupervisor.mRootWindowContainer.resumeFocusedStacksTopActivities();
+ mSupervisor.mRootWindowContainer.resumeFocusedTasksTopActivities();
final Task rootTask = task.getRootTask();
if (rootTask != null) {
rootTask.mDisplayContent.executeAppTransition();
@@ -717,7 +717,7 @@ public class LockTaskController {
}
if (taskChanged) {
- mSupervisor.mRootWindowContainer.resumeFocusedStacksTopActivities();
+ mSupervisor.mRootWindowContainer.resumeFocusedTasksTopActivities();
}
}
diff --git a/services/core/java/com/android/server/wm/RecentTasks.java b/services/core/java/com/android/server/wm/RecentTasks.java
index ba6b27ac3252..5598937da63d 100644
--- a/services/core/java/com/android/server/wm/RecentTasks.java
+++ b/services/core/java/com/android/server/wm/RecentTasks.java
@@ -36,13 +36,13 @@ import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static android.os.Process.SYSTEM_UID;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_TASKS;
-import static com.android.server.wm.ActivityTaskSupervisor.REMOVE_FROM_RECENTS;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RECENTS;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RECENTS_TRIM_TASKS;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_RECENTS;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_TASKS;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.server.wm.ActivityTaskSupervisor.REMOVE_FROM_RECENTS;
import android.annotation.Nullable;
import android.app.ActivityManager;
@@ -220,7 +220,7 @@ class RecentTasks {
final RootWindowContainer rac = mService.mRootWindowContainer;
final DisplayContent dc = rac.getDisplayContent(displayId).mDisplayContent;
if (dc.pointWithinAppWindow(x, y)) {
- final Task stack = mService.getTopDisplayFocusedStack();
+ final Task stack = mService.getTopDisplayFocusedRootTask();
final Task topTask = stack != null ? stack.getTopMostTask() : null;
resetFreezeTaskListReordering(topTask);
}
@@ -328,7 +328,7 @@ class RecentTasks {
@VisibleForTesting
void resetFreezeTaskListReorderingOnTimeout() {
synchronized (mService.mGlobalLock) {
- final Task focusedStack = mService.getTopDisplayFocusedStack();
+ final Task focusedStack = mService.getTopDisplayFocusedRootTask();
final Task topTask = focusedStack != null ? focusedStack.getTopMostTask() : null;
resetFreezeTaskListReordering(topTask);
}
diff --git a/services/core/java/com/android/server/wm/RecentsAnimation.java b/services/core/java/com/android/server/wm/RecentsAnimation.java
index 823dc51e939f..067c772dad93 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimation.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimation.java
@@ -29,7 +29,7 @@ import static com.android.server.wm.ActivityTaskSupervisor.PRESERVE_WINDOWS;
import static com.android.server.wm.RecentsAnimationController.REORDER_KEEP_IN_PLACE;
import static com.android.server.wm.RecentsAnimationController.REORDER_MOVE_TO_ORIGINAL_POSITION;
import static com.android.server.wm.RecentsAnimationController.REORDER_MOVE_TO_TOP;
-import static com.android.server.wm.TaskDisplayArea.getStackAbove;
+import static com.android.server.wm.TaskDisplayArea.getRootTaskAbove;
import android.annotation.Nullable;
import android.app.ActivityOptions;
@@ -45,13 +45,13 @@ import com.android.internal.util.function.pooled.PooledLambda;
import com.android.internal.util.function.pooled.PooledPredicate;
import com.android.server.wm.ActivityMetricsLogger.LaunchingState;
import com.android.server.wm.RecentsAnimationController.RecentsAnimationCallbacks;
+import com.android.server.wm.TaskDisplayArea.OnRootTaskOrderChangedListener;
/**
* Manages the recents animation, including the reordering of the stacks for the transition and
* cleanup. See {@link com.android.server.wm.RecentsAnimationController}.
*/
-class RecentsAnimation implements RecentsAnimationCallbacks,
- TaskDisplayArea.OnStackOrderChangedListener {
+class RecentsAnimation implements RecentsAnimationCallbacks, OnRootTaskOrderChangedListener {
private static final String TAG = RecentsAnimation.class.getSimpleName();
private final ActivityTaskManagerService mService;
@@ -106,7 +106,7 @@ class RecentsAnimation implements RecentsAnimationCallbacks,
void preloadRecentsActivity() {
ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, "Preload recents with %s",
mTargetIntent);
- Task targetStack = mDefaultTaskDisplayArea.getStack(WINDOWING_MODE_UNDEFINED,
+ Task targetStack = mDefaultTaskDisplayArea.getRootTask(WINDOWING_MODE_UNDEFINED,
mTargetActivityType);
ActivityRecord targetActivity = getTargetActivity(targetStack);
if (targetActivity != null) {
@@ -127,7 +127,7 @@ class RecentsAnimation implements RecentsAnimationCallbacks,
// Create the activity record. Because the activity is invisible, this doesn't really
// start the client.
startRecentsActivityInBackground("preloadRecents");
- targetStack = mDefaultTaskDisplayArea.getStack(WINDOWING_MODE_UNDEFINED,
+ targetStack = mDefaultTaskDisplayArea.getRootTask(WINDOWING_MODE_UNDEFINED,
mTargetActivityType);
targetActivity = getTargetActivity(targetStack);
if (targetActivity == null) {
@@ -165,12 +165,12 @@ class RecentsAnimation implements RecentsAnimationCallbacks,
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "RecentsAnimation#startRecentsActivity");
// If the activity is associated with the recents stack, then try and get that first
- Task targetStack = mDefaultTaskDisplayArea.getStack(WINDOWING_MODE_UNDEFINED,
+ Task targetStack = mDefaultTaskDisplayArea.getRootTask(WINDOWING_MODE_UNDEFINED,
mTargetActivityType);
ActivityRecord targetActivity = getTargetActivity(targetStack);
final boolean hasExistingActivity = targetActivity != null;
if (hasExistingActivity) {
- mRestoreTargetBehindStack = getStackAbove(targetStack);
+ mRestoreTargetBehindStack = getRootTaskAbove(targetStack);
if (mRestoreTargetBehindStack == null) {
notifyAnimationCancelBeforeStart(recentsAnimationRunner);
ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS,
@@ -197,9 +197,9 @@ class RecentsAnimation implements RecentsAnimationCallbacks,
try {
if (hasExistingActivity) {
// Move the recents activity into place for the animation if it is not top most
- mDefaultTaskDisplayArea.moveStackBehindBottomMostVisibleStack(targetStack);
+ mDefaultTaskDisplayArea.moveRootTaskBehindBottomMostVisibleRootTask(targetStack);
ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, "Moved stack=%s behind stack=%s",
- targetStack, getStackAbove(targetStack));
+ targetStack, getRootTaskAbove(targetStack));
// If there are multiple tasks in the target stack (ie. the home stack, with 3p
// and default launchers coexisting), then move the task to the top as a part of
@@ -213,12 +213,12 @@ class RecentsAnimation implements RecentsAnimationCallbacks,
startRecentsActivityInBackground("startRecentsActivity_noTargetActivity");
// Move the recents activity into place for the animation
- targetStack = mDefaultTaskDisplayArea.getStack(WINDOWING_MODE_UNDEFINED,
+ targetStack = mDefaultTaskDisplayArea.getRootTask(WINDOWING_MODE_UNDEFINED,
mTargetActivityType);
targetActivity = getTargetActivity(targetStack);
- mDefaultTaskDisplayArea.moveStackBehindBottomMostVisibleStack(targetStack);
+ mDefaultTaskDisplayArea.moveRootTaskBehindBottomMostVisibleRootTask(targetStack);
ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, "Moved stack=%s behind stack=%s",
- targetStack, getStackAbove(targetStack));
+ targetStack, getRootTaskAbove(targetStack));
mWindowManager.prepareAppTransitionNone();
mWindowManager.executeAppTransition();
@@ -257,7 +257,7 @@ class RecentsAnimation implements RecentsAnimationCallbacks,
START_TASK_TO_FRONT, targetActivity, options);
// Register for stack order changes
- mDefaultTaskDisplayArea.registerStackOrderChangedListener(this);
+ mDefaultTaskDisplayArea.registerRootTaskOrderChangedListener(this);
} catch (Exception e) {
Slog.e(TAG, "Failed to start recents activity", e);
throw e;
@@ -275,7 +275,7 @@ class RecentsAnimation implements RecentsAnimationCallbacks,
mWindowManager.getRecentsAnimationController(), reorderMode);
// Unregister for stack order changes
- mDefaultTaskDisplayArea.unregisterStackOrderChangedListener(this);
+ mDefaultTaskDisplayArea.unregisterRootTaskOrderChangedListener(this);
final RecentsAnimationController controller =
mWindowManager.getRecentsAnimationController();
@@ -303,7 +303,7 @@ class RecentsAnimation implements RecentsAnimationCallbacks,
try {
mWindowManager.cleanupRecentsAnimation(reorderMode);
- final Task targetStack = mDefaultTaskDisplayArea.getStack(
+ final Task targetStack = mDefaultTaskDisplayArea.getRootTask(
WINDOWING_MODE_UNDEFINED, mTargetActivityType);
// Prefer to use the original target activity instead of top activity because
// we may have moved another task to top (starting 3p launcher).
@@ -348,10 +348,10 @@ class RecentsAnimation implements RecentsAnimationCallbacks,
} else if (reorderMode == REORDER_MOVE_TO_ORIGINAL_POSITION){
// Restore the target stack to its previous position
final TaskDisplayArea taskDisplayArea = targetActivity.getDisplayArea();
- taskDisplayArea.moveStackBehindStack(targetStack,
+ taskDisplayArea.moveRootTaskBehindRootTask(targetStack,
mRestoreTargetBehindStack);
if (WM_DEBUG_RECENTS_ANIMATIONS.isLogToAny()) {
- final Task aboveTargetStack = getStackAbove(targetStack);
+ final Task aboveTargetStack = getRootTaskAbove(targetStack);
if (mRestoreTargetBehindStack != null
&& aboveTargetStack != mRestoreTargetBehindStack) {
ProtoLog.w(WM_DEBUG_RECENTS_ANIMATIONS,
@@ -378,7 +378,7 @@ class RecentsAnimation implements RecentsAnimationCallbacks,
mWindowManager.prepareAppTransitionNone();
mService.mRootWindowContainer.ensureActivitiesVisible(null, 0, false);
- mService.mRootWindowContainer.resumeFocusedStacksTopActivities();
+ mService.mRootWindowContainer.resumeFocusedTasksTopActivities();
// No reason to wait for the pausing activity in this case, as the hiding of
// surfaces needs to be done immediately.
@@ -412,9 +412,9 @@ class RecentsAnimation implements RecentsAnimationCallbacks,
}
@Override
- public void onStackOrderChanged(Task stack) {
- ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, "onStackOrderChanged(): stack=%s", stack);
- if (mDefaultTaskDisplayArea.getIndexOf(stack) == -1 || !stack.shouldBeVisible(null)) {
+ public void onRootTaskOrderChanged(Task rootTask) {
+ ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, "onStackOrderChanged(): stack=%s", rootTask);
+ if (mDefaultTaskDisplayArea.getIndexOf(rootTask) == -1 || !rootTask.shouldBeVisible(null)) {
// The stack is not visible, so ignore this change
return;
}
@@ -428,8 +428,8 @@ class RecentsAnimation implements RecentsAnimationCallbacks,
// cases:
// 1) The next launching task is not being animated by the recents animation
// 2) The next task is home activity. (i.e. pressing home key to back home in recents).
- if ((!controller.isAnimatingTask(stack.getTopMostTask())
- || controller.isTargetApp(stack.getTopNonFinishingActivity()))
+ if ((!controller.isAnimatingTask(rootTask.getTopMostTask())
+ || controller.isTargetApp(rootTask.getTopNonFinishingActivity()))
&& controller.shouldDeferCancelUntilNextTransition()) {
// Always prepare an app transition since we rely on the transition callbacks to cleanup
mWindowManager.prepareAppTransitionNone();
@@ -468,8 +468,8 @@ class RecentsAnimation implements RecentsAnimationCallbacks,
* @return The top stack that is not always-on-top.
*/
private Task getTopNonAlwaysOnTopStack() {
- for (int i = mDefaultTaskDisplayArea.getStackCount() - 1; i >= 0; i--) {
- final Task s = mDefaultTaskDisplayArea.getStackAt(i);
+ for (int i = mDefaultTaskDisplayArea.getRootTaskCount() - 1; i >= 0; i--) {
+ final Task s = mDefaultTaskDisplayArea.getRootTaskAt(i);
if (s.getWindowConfiguration().isAlwaysOnTop()) {
continue;
}
diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index abee032d042a..5da668c8c361 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -398,7 +398,7 @@ public class RecentsAnimationController implements DeathRecipient {
final ArrayList<Task> visibleTasks = mDisplayContent.getDefaultTaskDisplayArea()
.getVisibleTasks();
final Task targetStack = mDisplayContent.getDefaultTaskDisplayArea()
- .getStack(WINDOWING_MODE_UNDEFINED, targetActivityType);
+ .getRootTask(WINDOWING_MODE_UNDEFINED, targetActivityType);
if (targetStack != null) {
final PooledConsumer c = PooledLambda.obtainConsumer((t, outList) ->
{ if (!outList.contains(t)) outList.add(t); }, PooledLambda.__(Task.class),
diff --git a/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java b/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java
index 7bd5d03f1bc1..17cb8905f260 100644
--- a/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java
+++ b/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java
@@ -237,7 +237,7 @@ class ResetTargetTaskHelper {
while (!mPendingReparentActivities.isEmpty()) {
final ActivityRecord r = mPendingReparentActivities.remove(0);
- final boolean alwaysCreateTask = DisplayContent.alwaysCreateStack(windowingMode,
+ final boolean alwaysCreateTask = DisplayContent.alwaysCreateRootTask(windowingMode,
activityType);
final Task task = alwaysCreateTask
? taskDisplayArea.getBottomMostTask() : mTargetStack.getBottomMostTask();
@@ -251,7 +251,7 @@ class ResetTargetTaskHelper {
}
if (targetTask == null) {
if (alwaysCreateTask) {
- targetTask = taskDisplayArea.getOrCreateStack(windowingMode,
+ targetTask = taskDisplayArea.getOrCreateRootTask(windowingMode,
activityType, false /* onTop */);
} else {
targetTask = mTargetStack.reuseOrCreateTask(r.info, null /*intent*/,
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 707354823817..497087a967f3 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -256,8 +256,8 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
/** The current user */
int mCurrentUser;
- /** Stack id of the front stack when user switched, indexed by userId. */
- SparseIntArray mUserStackInFront = new SparseIntArray(2);
+ /** Root task id of the front root task when user switched, indexed by userId. */
+ SparseIntArray mUserRootTaskInFront = new SparseIntArray(2);
/**
* A list of tokens that cause the top activity to be put to sleep.
@@ -296,7 +296,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
c.recycle();
} finally {
mTaskSupervisor.endDeferResume();
- resumeFocusedStacksTopActivities();
+ resumeFocusedTasksTopActivities();
}
}
}
@@ -1484,7 +1484,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
boolean fromHomeKey) {
// Fallback to top focused display or default display if the displayId is invalid.
if (displayId == INVALID_DISPLAY) {
- final Task stack = getTopDisplayFocusedStack();
+ final Task stack = getTopDisplayFocusedRootTask();
displayId = stack != null ? stack.getDisplayId() : DEFAULT_DISPLAY;
}
@@ -1510,7 +1510,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
boolean allowInstrumenting, boolean fromHomeKey) {
// Fallback to top focused display area if the provided one is invalid.
if (taskDisplayArea == null) {
- final Task stack = getTopDisplayFocusedStack();
+ final Task stack = getTopDisplayFocusedRootTask();
taskDisplayArea = stack != null ? stack.getDisplayArea()
: getDefaultTaskDisplayArea();
}
@@ -1677,7 +1677,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
// Only resume home activity if isn't finishing.
if (r != null && !r.finishing) {
r.moveFocusableActivityToTop(myReason);
- return resumeFocusedStacksTopActivities(r.getRootTask(), prev, null);
+ return resumeFocusedTasksTopActivities(r.getRootTask(), prev, null);
}
return startHomeOnTaskDisplayArea(mCurrentUser, myReason, taskDisplayArea,
false /* allowInstrumenting */, false /* fromHomeKey */);
@@ -1804,10 +1804,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
Configuration config = null;
if (displayContent != null) {
config = displayContent.updateOrientation(
- getDisplayOverrideConfiguration(displayId),
- starting != null && starting.mayFreezeScreenLocked()
- ? starting.appToken : null,
- true /* forceUpdate */);
+ getDisplayOverrideConfiguration(displayId), starting, true /* forceUpdate */);
}
// Visibilities may change so let the starting activity have a chance to report. Can't do it
// when visibility is changed in each AppWindowToken because it may trigger wrong
@@ -1834,12 +1831,12 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
*/
List<IBinder> getTopVisibleActivities() {
final ArrayList<IBinder> topActivityTokens = new ArrayList<>();
- final Task topFocusedStack = getTopDisplayFocusedStack();
+ final Task topFocusedStack = getTopDisplayFocusedRootTask();
// Traverse all displays.
forAllTaskDisplayAreas(taskDisplayArea -> {
// Traverse all stacks on a display area.
- for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {
- final Task stack = taskDisplayArea.getStackAt(sNdx);
+ for (int sNdx = taskDisplayArea.getRootTaskCount() - 1; sNdx >= 0; --sNdx) {
+ final Task stack = taskDisplayArea.getRootTaskAt(sNdx);
// Get top activity from a visible stack and add it to the list.
if (stack.shouldBeVisible(null /* starting */)) {
final ActivityRecord top = stack.getTopNonFinishingActivity();
@@ -1857,9 +1854,9 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
}
@Nullable
- Task getTopDisplayFocusedStack() {
+ Task getTopDisplayFocusedRootTask() {
for (int i = getChildCount() - 1; i >= 0; --i) {
- final Task focusedStack = getChildAt(i).getFocusedStack();
+ final Task focusedStack = getChildAt(i).getFocusedRootTask();
if (focusedStack != null) {
return focusedStack;
}
@@ -1869,7 +1866,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
@Nullable
ActivityRecord getTopResumedActivity() {
- final Task focusedStack = getTopDisplayFocusedStack();
+ final Task focusedStack = getTopDisplayFocusedRootTask();
if (focusedStack == null) {
return null;
}
@@ -1882,8 +1879,8 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
return getItemFromTaskDisplayAreas(TaskDisplayArea::getFocusedActivity);
}
- boolean isTopDisplayFocusedStack(Task stack) {
- return stack != null && stack == getTopDisplayFocusedStack();
+ boolean isTopDisplayFocusedRootTask(Task task) {
+ return task != null && task == getTopDisplayFocusedRootTask();
}
void updatePreviousProcess(ActivityRecord r) {
@@ -1894,9 +1891,9 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
// previous app if this activity is being hosted by the process that is actually still the
// foreground.
WindowProcessController fgApp = reduceOnAllTaskDisplayAreas((taskDisplayArea, app) -> {
- for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {
- final Task stack = taskDisplayArea.getStackAt(sNdx);
- if (isTopDisplayFocusedStack(stack)) {
+ for (int sNdx = taskDisplayArea.getRootTaskCount() - 1; sNdx >= 0; --sNdx) {
+ final Task stack = taskDisplayArea.getRootTaskAt(sNdx);
+ if (isTopDisplayFocusedRootTask(stack)) {
final ActivityRecord resumedActivity = stack.getResumedActivity();
if (resumedActivity != null) {
app = resumedActivity.app;
@@ -1929,8 +1926,8 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
return;
}
- for (int taskNdx = displayArea.getStackCount() - 1; taskNdx >= 0; --taskNdx) {
- final Task rootTask = displayArea.getStackAt(taskNdx);
+ for (int taskNdx = displayArea.getRootTaskCount() - 1; taskNdx >= 0; --taskNdx) {
+ final Task rootTask = displayArea.getRootTaskAt(taskNdx);
if (rootTask.getVisibility(null /*starting*/) == TASK_VISIBILITY_INVISIBLE) {
break;
}
@@ -2012,7 +2009,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
}
boolean switchUser(int userId, UserState uss) {
- final Task topFocusedStack = getTopDisplayFocusedStack();
+ final Task topFocusedStack = getTopDisplayFocusedRootTask();
final int focusStackId = topFocusedStack != null
? topFocusedStack.getRootTaskId() : INVALID_TASK_ID;
// We dismiss the docked stack whenever we switch users.
@@ -2024,19 +2021,19 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
// appropriate.
removeRootTasksInWindowingModes(WINDOWING_MODE_PINNED);
- mUserStackInFront.put(mCurrentUser, focusStackId);
+ mUserRootTaskInFront.put(mCurrentUser, focusStackId);
mCurrentUser = userId;
mTaskSupervisor.mStartingUsers.add(uss);
forAllTaskDisplayAreas(taskDisplayArea -> {
- for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {
- final Task stack = taskDisplayArea.getStackAt(sNdx);
+ for (int sNdx = taskDisplayArea.getRootTaskCount() - 1; sNdx >= 0; --sNdx) {
+ final Task stack = taskDisplayArea.getRootTaskAt(sNdx);
stack.switchUser(userId);
}
});
- final int restoreStackId = mUserStackInFront.get(userId);
- Task stack = getStack(restoreStackId);
+ final int restoreStackId = mUserRootTaskInFront.get(userId);
+ Task stack = getRootTask(restoreStackId);
if (stack == null) {
stack = getDefaultTaskDisplayArea().getOrCreateRootHomeTask();
}
@@ -2051,20 +2048,20 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
}
void removeUser(int userId) {
- mUserStackInFront.delete(userId);
+ mUserRootTaskInFront.delete(userId);
}
/**
- * Update the last used stack id for non-current user (current user's last
- * used stack is the focused stack)
+ * Update the last used root task id for non-current user (current user's last
+ * used root task is the focused root task)
*/
- void updateUserStack(int userId, Task stack) {
+ void updateUserRootTask(int userId, Task rootTask) {
if (userId != mCurrentUser) {
- if (stack == null) {
- stack = getDefaultTaskDisplayArea().getOrCreateRootHomeTask();
+ if (rootTask == null) {
+ rootTask = getDefaultTaskDisplayArea().getOrCreateRootHomeTask();
}
- mUserStackInFront.put(userId, stack.getRootTaskId());
+ mUserRootTaskInFront.put(userId, rootTask.getRootTaskId());
}
}
@@ -2075,8 +2072,9 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
* @param taskDisplayArea The task display area to move stack to.
* @param onTop Indicates whether container should be place on top or on bottom.
*/
- void moveStackToTaskDisplayArea(int stackId, TaskDisplayArea taskDisplayArea, boolean onTop) {
- final Task stack = getStack(stackId);
+ void moveRootTaskToTaskDisplayArea(int stackId, TaskDisplayArea taskDisplayArea,
+ boolean onTop) {
+ final Task stack = getRootTask(stackId);
if (stack == null) {
throw new IllegalArgumentException("moveStackToTaskDisplayArea: Unknown stackId="
+ stackId);
@@ -2104,22 +2102,23 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
/**
* Move stack with all its existing content to specified display.
*
- * @param stackId Id of stack to move.
+ * @param rootTaskId Id of stack to move.
* @param displayId Id of display to move stack to.
* @param onTop Indicates whether container should be place on top or on bottom.
*/
- void moveStackToDisplay(int stackId, int displayId, boolean onTop) {
+ void moveRootTaskToDisplay(int rootTaskId, int displayId, boolean onTop) {
final DisplayContent displayContent = getDisplayContentOrCreate(displayId);
if (displayContent == null) {
throw new IllegalArgumentException("moveStackToDisplay: Unknown displayId="
+ displayId);
}
- moveStackToTaskDisplayArea(stackId, displayContent.getDefaultTaskDisplayArea(), onTop);
+ moveRootTaskToTaskDisplayArea(rootTaskId, displayContent.getDefaultTaskDisplayArea(),
+ onTop);
}
- boolean moveTopStackActivityToPinnedRootTask(int rootTaskId) {
- final Task rootTask = getStack(rootTaskId);
+ boolean moveTopRootTaskActivityToPinnedRootTask(int rootTaskId) {
+ final Task rootTask = getRootTask(rootTaskId);
if (rootTask == null) {
throw new IllegalArgumentException(
"moveTopStackActivityToPinnedRootTask: Unknown rootTaskId=" + rootTaskId);
@@ -2138,11 +2137,11 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
return false;
}
- moveActivityToPinnedStack(r, "moveTopStackActivityToPinnedRootTask");
+ moveActivityToPinnedRootTask(r, "moveTopStackActivityToPinnedRootTask");
return true;
}
- void moveActivityToPinnedStack(ActivityRecord r, String reason) {
+ void moveActivityToPinnedRootTask(ActivityRecord r, String reason) {
mService.deferWindowLayout();
final TaskDisplayArea taskDisplayArea = r.getDisplayArea();
@@ -2162,25 +2161,26 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
r.getDisplayContent().prepareAppTransition(TRANSIT_NONE);
final boolean singleActivity = task.getChildCount() == 1;
- final Task stack;
+ final Task rootTask;
if (singleActivity) {
- stack = task;
+ rootTask = task;
} else {
// In the case of multiple activities, we will create a new task for it and then
// move the PIP activity into the task.
- stack = taskDisplayArea.createStack(WINDOWING_MODE_UNDEFINED, r.getActivityType(),
- ON_TOP, r.info, r.intent, false /* createdByOrganizer */);
+ rootTask = taskDisplayArea.createRootTask(WINDOWING_MODE_UNDEFINED,
+ r.getActivityType(), ON_TOP, r.info, r.intent,
+ false /* createdByOrganizer */);
// It's possible the task entering PIP is in freeform, so save the last
// non-fullscreen bounds. Then when this new PIP task exits PIP, it can restore
// to its previous freeform bounds.
- stack.setLastNonFullscreenBounds(task.mLastNonFullscreenBounds);
- stack.setBounds(task.getBounds());
+ rootTask.setLastNonFullscreenBounds(task.mLastNonFullscreenBounds);
+ rootTask.setBounds(task.getBounds());
// There are multiple activities in the task and moving the top activity should
// reveal/leave the other activities in their original task.
// On the other hand, ActivityRecord#onParentChanged takes care of setting the
// up-to-dated pinned stack information on this newly created stack.
- r.reparent(stack, MAX_VALUE, reason);
+ r.reparent(rootTask, MAX_VALUE, reason);
// In the case of this activity entering PIP due to it being moved to the back,
// the old activity would have a TRANSIT_TASK_TO_BACK transition that needs to be
@@ -2199,17 +2199,17 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
// The intermediate windowing mode to be set on the ActivityRecord later.
// This needs to happen before the re-parenting, otherwise we will always set the
// ActivityRecord to be fullscreen.
- final int intermediateWindowingMode = stack.getWindowingMode();
- if (stack.getParent() != taskDisplayArea) {
+ final int intermediateWindowingMode = rootTask.getWindowingMode();
+ if (rootTask.getParent() != taskDisplayArea) {
// stack is nested, but pinned tasks need to be direct children of their
// display area, so reparent.
- stack.reparent(taskDisplayArea, true /* onTop */);
+ rootTask.reparent(taskDisplayArea, true /* onTop */);
}
// Defer the windowing mode change until after the transition to prevent the activity
// from doing work and changing the activity visuals while animating
// TODO(task-org): Figure-out more structured way to do this long term.
r.setWindowingMode(intermediateWindowingMode);
- stack.setWindowingMode(WINDOWING_MODE_PINNED);
+ rootTask.setWindowingMode(WINDOWING_MODE_PINNED);
// Reset the state that indicates it can enter PiP while pausing after we've moved it
// to the pinned stack
@@ -2219,7 +2219,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
}
ensureActivitiesVisible(null, 0, false /* preserveWindows */);
- resumeFocusedStacksTopActivities();
+ resumeFocusedTasksTopActivities();
notifyActivityPipModeChanged(r);
}
@@ -2291,13 +2291,13 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
* @return The task id that was finished in this stack, or INVALID_TASK_ID if none was finished.
*/
int finishTopCrashedActivities(WindowProcessController app, String reason) {
- Task focusedStack = getTopDisplayFocusedStack();
+ Task focusedStack = getTopDisplayFocusedRootTask();
Task finishedTask = reduceOnAllTaskDisplayAreas((taskDisplayArea, task) -> {
// It is possible that request to finish activity might also remove its task and
// stack, so we need to be careful with indexes in the loop and check child count
// every time.
- for (int stackNdx = 0; stackNdx < taskDisplayArea.getStackCount(); ++stackNdx) {
- final Task stack = taskDisplayArea.getStackAt(stackNdx);
+ for (int stackNdx = 0; stackNdx < taskDisplayArea.getRootTaskCount(); ++stackNdx) {
+ final Task stack = taskDisplayArea.getRootTaskAt(stackNdx);
final Task t = stack.finishTopCrashedActivityLocked(app, reason);
if (stack == focusedStack || task == null) {
task = t;
@@ -2308,21 +2308,21 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
return finishedTask != null ? finishedTask.mTaskId : INVALID_TASK_ID;
}
- boolean resumeFocusedStacksTopActivities() {
- return resumeFocusedStacksTopActivities(null, null, null);
+ boolean resumeFocusedTasksTopActivities() {
+ return resumeFocusedTasksTopActivities(null, null, null);
}
- boolean resumeFocusedStacksTopActivities(
- Task targetStack, ActivityRecord target, ActivityOptions targetOptions) {
+ boolean resumeFocusedTasksTopActivities(
+ Task targetRootTask, ActivityRecord target, ActivityOptions targetOptions) {
if (!mTaskSupervisor.readyToResume()) {
return false;
}
boolean result = false;
- if (targetStack != null && (targetStack.isTopStackInDisplayArea()
- || getTopDisplayFocusedStack() == targetStack)) {
- result = targetStack.resumeTopActivityUncheckedLocked(target, targetOptions);
+ if (targetRootTask != null && (targetRootTask.isTopStackInDisplayArea()
+ || getTopDisplayFocusedRootTask() == targetRootTask)) {
+ result = targetRootTask.resumeTopActivityUncheckedLocked(target, targetOptions);
}
for (int displayNdx = getChildCount() - 1; displayNdx >= 0; --displayNdx) {
@@ -2330,13 +2330,13 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
final boolean curResult = result;
boolean resumedOnDisplay = display.reduceOnAllTaskDisplayAreas(
(taskDisplayArea, resumed) -> {
- for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {
- final Task stack = taskDisplayArea.getStackAt(sNdx);
- final ActivityRecord topRunningActivity = stack.topRunningActivity();
- if (!stack.isFocusableAndVisible() || topRunningActivity == null) {
+ for (int sNdx = taskDisplayArea.getRootTaskCount() - 1; sNdx >= 0; --sNdx) {
+ final Task rootTask = taskDisplayArea.getRootTaskAt(sNdx);
+ final ActivityRecord topRunningActivity = rootTask.topRunningActivity();
+ if (!rootTask.isFocusableAndVisible() || topRunningActivity == null) {
continue;
}
- if (stack == targetStack) {
+ if (rootTask == targetRootTask) {
// Simply update the result for targetStack because the targetStack
// had already resumed in above. We don't want to resume it again,
// especially in some cases, it would cause a second launch failure
@@ -2344,12 +2344,12 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
resumed |= curResult;
continue;
}
- if (taskDisplayArea.isTopStack(stack)
+ if (taskDisplayArea.isTopRootTask(rootTask)
&& topRunningActivity.isState(RESUMED)) {
// Kick off any lingering app transitions form the MoveTaskToFront
// operation, but only consider the top task and stack on that
// display.
- stack.executeAppTransition(targetOptions);
+ rootTask.executeAppTransition(targetOptions);
} else {
resumed |= topRunningActivity.makeActiveIfNeeded(target);
}
@@ -2362,10 +2362,10 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
// crashed) it's possible that nothing was resumed on a display. Requesting resume
// of top activity in focused stack explicitly will make sure that at least home
// activity is started and resumed, and no recursion occurs.
- final Task focusedStack = display.getFocusedStack();
- if (focusedStack != null) {
- result |= focusedStack.resumeTopActivityUncheckedLocked(target, targetOptions);
- } else if (targetStack == null) {
+ final Task focusedRoot = display.getFocusedRootTask();
+ if (focusedRoot != null) {
+ result |= focusedRoot.resumeTopActivityUncheckedLocked(target, targetOptions);
+ } else if (targetRootTask == null) {
result |= resumeHomeActivity(null /* prev */, "no-focusable-task",
display.getDefaultTaskDisplayArea());
}
@@ -2391,8 +2391,8 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
// Set the sleeping state of the stacks on the display.
display.forAllTaskDisplayAreas(taskDisplayArea -> {
- for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {
- final Task stack = taskDisplayArea.getStackAt(sNdx);
+ for (int sNdx = taskDisplayArea.getRootTaskCount() - 1; sNdx >= 0; --sNdx) {
+ final Task stack = taskDisplayArea.getRootTaskAt(sNdx);
if (displayShouldSleep) {
stack.goToSleepIfPossible(false /* shuttingDown */);
} else {
@@ -2419,34 +2419,34 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
}
}
- protected Task getStack(int stackId) {
+ protected Task getRootTask(int rooTaskId) {
for (int i = getChildCount() - 1; i >= 0; --i) {
- final Task stack = getChildAt(i).getStack(stackId);
- if (stack != null) {
- return stack;
+ final Task rootTask = getChildAt(i).getRootTask(rooTaskId);
+ if (rootTask != null) {
+ return rootTask;
}
}
return null;
}
- /** @see DisplayContent#getStack(int, int) */
- Task getStack(int windowingMode, int activityType) {
+ /** @see DisplayContent#getRootTask(int, int) */
+ Task getRootTask(int windowingMode, int activityType) {
for (int i = getChildCount() - 1; i >= 0; --i) {
- final Task stack = getChildAt(i).getStack(windowingMode, activityType);
- if (stack != null) {
- return stack;
+ final Task rootTask = getChildAt(i).getRootTask(windowingMode, activityType);
+ if (rootTask != null) {
+ return rootTask;
}
}
return null;
}
- private Task getStack(int windowingMode, int activityType,
+ private Task getRootTask(int windowingMode, int activityType,
int displayId) {
DisplayContent display = getDisplayContent(displayId);
if (display == null) {
return null;
}
- return display.getStack(windowingMode, activityType);
+ return display.getRootTask(windowingMode, activityType);
}
private RootTaskInfo getRootTaskInfo(Task task) {
@@ -2491,7 +2491,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
}
RootTaskInfo getRootTaskInfo(int taskId) {
- Task task = getStack(taskId);
+ Task task = getRootTask(taskId);
if (task != null) {
return getRootTaskInfo(task);
}
@@ -2499,12 +2499,12 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
}
RootTaskInfo getRootTaskInfo(int windowingMode, int activityType) {
- final Task stack = getStack(windowingMode, activityType);
+ final Task stack = getRootTask(windowingMode, activityType);
return (stack != null) ? getRootTaskInfo(stack) : null;
}
RootTaskInfo getRootTaskInfo(int windowingMode, int activityType, int displayId) {
- final Task stack = getStack(windowingMode, activityType, displayId);
+ final Task stack = getRootTask(windowingMode, activityType, displayId);
return (stack != null) ? getRootTaskInfo(stack) : null;
}
@@ -2513,8 +2513,8 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
ArrayList<RootTaskInfo> list = new ArrayList<>();
if (displayId == INVALID_DISPLAY) {
forAllTaskDisplayAreas(taskDisplayArea -> {
- for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {
- final Task stack = taskDisplayArea.getStackAt(sNdx);
+ for (int sNdx = taskDisplayArea.getRootTaskCount() - 1; sNdx >= 0; --sNdx) {
+ final Task stack = taskDisplayArea.getRootTaskAt(sNdx);
list.add(getRootTaskInfo(stack));
}
});
@@ -2525,8 +2525,8 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
return list;
}
display.forAllTaskDisplayAreas(taskDisplayArea -> {
- for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {
- final Task stack = taskDisplayArea.getStackAt(sNdx);
+ for (int sNdx = taskDisplayArea.getRootTaskCount() - 1; sNdx >= 0; --sNdx) {
+ final Task stack = taskDisplayArea.getRootTaskAt(sNdx);
list.add(getRootTaskInfo(stack));
}
});
@@ -2598,16 +2598,16 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
mDisplayManagerInternal.setDisplayAccessUIDs(mDisplayAccessUIDs);
}
- Task findStackBehind(Task stack) {
- final TaskDisplayArea taskDisplayArea = stack.getDisplayArea();
+ Task findRootTaskBehind(Task rootTask) {
+ final TaskDisplayArea taskDisplayArea = rootTask.getDisplayArea();
if (taskDisplayArea != null) {
- for (int i = taskDisplayArea.getStackCount() - 1; i >= 0; i--) {
- if (taskDisplayArea.getStackAt(i) == stack && i > 0) {
- return taskDisplayArea.getStackAt(i - 1);
+ for (int i = taskDisplayArea.getRootTaskCount() - 1; i >= 0; i--) {
+ if (taskDisplayArea.getRootTaskAt(i) == rootTask && i > 0) {
+ return taskDisplayArea.getRootTaskAt(i - 1);
}
}
}
- throw new IllegalStateException("Failed to find a stack behind stack=" + stack
+ throw new IllegalStateException("Failed to find a root task behind root task =" + rootTask
+ " in=" + taskDisplayArea);
}
@@ -2743,22 +2743,22 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
r.destroyImmediately(mDestroyAllActivitiesReason);
}
- // Tries to put all activity stacks to sleep. Returns true if all stacks were
+ // Tries to put all activity tasks to sleep. Returns true if all tasks were
// successfully put to sleep.
- boolean putStacksToSleep(boolean allowDelay, boolean shuttingDown) {
+ boolean putTasksToSleep(boolean allowDelay, boolean shuttingDown) {
return reduceOnAllTaskDisplayAreas((taskDisplayArea, result) -> {
- for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {
+ for (int sNdx = taskDisplayArea.getRootTaskCount() - 1; sNdx >= 0; --sNdx) {
// Stacks and activities could be removed while putting activities to sleep if
// the app process was gone. This prevents us getting exception by accessing an
// invalid stack index.
- if (sNdx >= taskDisplayArea.getStackCount()) {
+ if (sNdx >= taskDisplayArea.getRootTaskCount()) {
continue;
}
- final Task stack = taskDisplayArea.getStackAt(sNdx);
+ final Task task = taskDisplayArea.getRootTaskAt(sNdx);
if (allowDelay) {
- result &= stack.goToSleepIfPossible(shuttingDown);
+ result &= task.goToSleepIfPossible(shuttingDown);
} else {
- stack.ensureActivitiesVisible(null /* starting */, 0 /* configChanges */,
+ task.ensureActivitiesVisible(null /* starting */, 0 /* configChanges */,
!PRESERVE_WINDOWS);
}
}
@@ -2827,9 +2827,9 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
return false;
}
- Task getLaunchStack(@Nullable ActivityRecord r,
+ Task getLaunchRootTask(@Nullable ActivityRecord r,
@Nullable ActivityOptions options, @Nullable Task candidateTask, boolean onTop) {
- return getLaunchStack(r, options, candidateTask, onTop, null /* launchParams */,
+ return getLaunchRootTask(r, options, candidateTask, onTop, null /* launchParams */,
-1 /* no realCallingPid */, -1 /* no realCallingUid */);
}
@@ -2844,7 +2844,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
* @param realCallingUid The uid from {@link ActivityStarter#setRealCallingUid}
* @return The stack to use for the launch or INVALID_STACK_ID.
*/
- Task getLaunchStack(@Nullable ActivityRecord r,
+ Task getLaunchRootTask(@Nullable ActivityRecord r,
@Nullable ActivityOptions options, @Nullable Task candidateTask, boolean onTop,
@Nullable LaunchParamsController.LaunchParams launchParams, int realCallingPid,
int realCallingUid) {
@@ -2897,7 +2897,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
realCallingPid, realCallingUid, r.info);
if (canLaunchOnDisplayFromStartRequest || canLaunchOnDisplay(r, tdaDisplayId)) {
if (r != null) {
- final Task result = getValidLaunchStackInTaskDisplayArea(
+ final Task result = getValidLaunchRootTaskInTaskDisplayArea(
taskDisplayArea, r, candidateTask, options, launchParams);
if (result != null) {
return result;
@@ -2905,7 +2905,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
}
// Falling back to default task container
taskDisplayArea = taskDisplayArea.mDisplayContent.getDefaultTaskDisplayArea();
- stack = taskDisplayArea.getOrCreateStack(r, options, candidateTask, activityType,
+ stack = taskDisplayArea.getOrCreateRootTask(r, options, candidateTask, activityType,
onTop);
if (stack != null) {
return stack;
@@ -2959,7 +2959,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
}
}
- return container.getOrCreateStack(r, options, candidateTask, activityType, onTop);
+ return container.getOrCreateRootTask(r, options, candidateTask, activityType, onTop);
}
/** @return true if activity record is null or can be launched on provided display. */
@@ -2980,7 +2980,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
* @return Existing stack if there is a valid one, new dynamic stack if it is valid or null.
*/
@VisibleForTesting
- Task getValidLaunchStackInTaskDisplayArea(@NonNull TaskDisplayArea taskDisplayArea,
+ Task getValidLaunchRootTaskInTaskDisplayArea(@NonNull TaskDisplayArea taskDisplayArea,
@NonNull ActivityRecord r, @Nullable Task candidateTask,
@Nullable ActivityOptions options,
@Nullable LaunchParamsController.LaunchParams launchParams) {
@@ -3019,9 +3019,9 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
r.getActivityType());
// Return the topmost valid stack on the display.
- for (int i = taskDisplayArea.getStackCount() - 1; i >= 0; --i) {
- final Task stack = taskDisplayArea.getStackAt(i);
- if (isValidLaunchStack(stack, r, windowingMode)) {
+ for (int i = taskDisplayArea.getRootTaskCount() - 1; i >= 0; --i) {
+ final Task stack = taskDisplayArea.getRootTaskAt(i);
+ if (isValidLaunchRootTask(stack, r, windowingMode)) {
return stack;
}
}
@@ -3033,15 +3033,15 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
final int activityType =
options != null && options.getLaunchActivityType() != ACTIVITY_TYPE_UNDEFINED
? options.getLaunchActivityType() : r.getActivityType();
- return taskDisplayArea.createStack(windowingMode, activityType, true /*onTop*/);
+ return taskDisplayArea.createRootTask(windowingMode, activityType, true /*onTop*/);
}
return null;
}
// TODO: Can probably be consolidated into getLaunchStack()...
- private boolean isValidLaunchStack(Task stack, ActivityRecord r, int windowingMode) {
- switch (stack.getActivityType()) {
+ private boolean isValidLaunchRootTask(Task task, ActivityRecord r, int windowingMode) {
+ switch (task.getActivityType()) {
case ACTIVITY_TYPE_HOME:
return r.isActivityTypeHome();
case ACTIVITY_TYPE_RECENTS:
@@ -3051,13 +3051,13 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
case ACTIVITY_TYPE_DREAM:
return r.isActivityTypeDream();
}
- if (stack.mCreatedByOrganizer) {
+ if (task.mCreatedByOrganizer) {
// Don't launch directly into task created by organizer...but why can't we?
return false;
}
// There is a 1-to-1 relationship between stack and task when not in
// primary split-windowing mode.
- if (stack.getWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
+ if (task.getWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
&& r.supportsSplitScreenWindowingMode()
&& (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
|| windowingMode == WINDOWING_MODE_UNDEFINED)) {
@@ -3094,8 +3094,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
* candidate.
* @return Next focusable {@link Task}, {@code null} if not found.
*/
- Task getNextFocusableStack(@NonNull Task currentFocus,
- boolean ignoreCurrent) {
+ Task getNextFocusableRootTask(@NonNull Task currentFocus, boolean ignoreCurrent) {
// First look for next focusable stack on the same display
TaskDisplayArea preferredDisplayArea = currentFocus.getDisplayArea();
if (preferredDisplayArea == null) {
@@ -3104,7 +3103,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
preferredDisplayArea = getDisplayContent(currentFocus.mPrevDisplayId)
.getDefaultTaskDisplayArea();
}
- final Task preferredFocusableStack = preferredDisplayArea.getNextFocusableStack(
+ final Task preferredFocusableStack = preferredDisplayArea.getNextFocusableRootTask(
currentFocus, ignoreCurrent);
if (preferredFocusableStack != null) {
return preferredFocusableStack;
@@ -3124,7 +3123,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
continue;
}
final Task nextFocusableStack = display.getDefaultTaskDisplayArea()
- .getNextFocusableStack(currentFocus, ignoreCurrent);
+ .getNextFocusableRootTask(currentFocus, ignoreCurrent);
if (nextFocusableStack != null) {
return nextFocusableStack;
}
@@ -3260,9 +3259,9 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
void finishVoiceTask(IVoiceInteractionSession session) {
forAllTaskDisplayAreas(taskDisplayArea -> {
- final int numStacks = taskDisplayArea.getStackCount();
+ final int numStacks = taskDisplayArea.getRootTaskCount();
for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
- final Task stack = taskDisplayArea.getStackAt(stackNdx);
+ final Task stack = taskDisplayArea.getRootTaskAt(stackNdx);
stack.finishVoiceTask(session);
}
});
@@ -3305,7 +3304,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
// If the focused stack is not null or not empty, there should have some activities
// resuming or resumed. Make sure these activities are idle.
- final Task stack = display.getFocusedStack();
+ final Task stack = display.getFocusedRootTask();
if (stack == null || !stack.hasActivity()) {
continue;
}
@@ -3325,8 +3324,8 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
boolean[] foundResumed = {false};
final boolean foundInvisibleResumedActivity = forAllTaskDisplayAreas(
taskDisplayArea -> {
- for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {
- final Task stack = taskDisplayArea.getStackAt(sNdx);
+ for (int sNdx = taskDisplayArea.getRootTaskCount() - 1; sNdx >= 0; --sNdx) {
+ final Task stack = taskDisplayArea.getRootTaskAt(sNdx);
final ActivityRecord r = stack.getResumedActivity();
if (r != null) {
if (!r.nowVisible) {
@@ -3347,8 +3346,8 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
boolean[] pausing = {true};
final boolean hasActivityNotCompleted = forAllTaskDisplayAreas(
taskDisplayArea -> {
- for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {
- final Task stack = taskDisplayArea.getStackAt(sNdx);
+ for (int sNdx = taskDisplayArea.getRootTaskCount() - 1; sNdx >= 0; --sNdx) {
+ final Task stack = taskDisplayArea.getRootTaskAt(sNdx);
final ActivityRecord r = stack.mPausingActivity;
if (r != null && !r.isState(PAUSED, STOPPED, STOPPING, FINISHING)) {
ProtoLog.d(WM_DEBUG_STATES, "allPausedActivitiesComplete: "
@@ -3413,10 +3412,10 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
void cancelInitializingActivities() {
forAllTaskDisplayAreas(taskDisplayArea -> {
- for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {
+ for (int sNdx = taskDisplayArea.getRootTaskCount() - 1; sNdx >= 0; --sNdx) {
// We don't want to clear starting window for activities that aren't occluded
// as we need to display their starting window until they are done initializing.
- taskDisplayArea.getStackAt(sNdx).forAllOccludedActivities(
+ taskDisplayArea.getRootTaskAt(sNdx).forAllOccludedActivities(
ActivityRecord::cancelInitializing);
}
});
@@ -3456,7 +3455,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
// Resolve the stack the task should be placed in now based on options
// and reparent if needed.
final Task launchStack =
- getLaunchStack(null, aOptions, task, onTop);
+ getLaunchRootTask(null, aOptions, task, onTop);
if (launchStack != null && task.getRootTask() != launchStack) {
final int reparentMode = onTop
? REPARENT_MOVE_ROOT_TASK_TO_FRONT : REPARENT_LEAVE_ROOT_TASK_IN_PLACE;
@@ -3501,7 +3500,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
return task;
}
- ActivityRecord isInAnyStack(IBinder token) {
+ ActivityRecord isInAnyTask(IBinder token) {
final ActivityRecord r = ActivityRecord.forTokenLocked(token);
return (r != null && r.isDescendantOf(this)) ? r : null;
}
@@ -3571,7 +3570,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
ArrayList<ActivityRecord> getDumpActivities(String name, boolean dumpVisibleStacksOnly,
boolean dumpFocusedStackOnly) {
if (dumpFocusedStackOnly) {
- final Task topFocusedStack = getTopDisplayFocusedStack();
+ final Task topFocusedStack = getTopDisplayFocusedRootTask();
if (topFocusedStack != null) {
return topFocusedStack.getDumpActivitiesLocked(name);
} else {
@@ -3580,8 +3579,8 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
} else {
ArrayList<ActivityRecord> activities = new ArrayList<>();
forAllTaskDisplayAreas(taskDisplayArea -> {
- for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {
- final Task stack = taskDisplayArea.getStackAt(sNdx);
+ for (int sNdx = taskDisplayArea.getRootTaskCount() - 1; sNdx >= 0; --sNdx) {
+ final Task stack = taskDisplayArea.getRootTaskAt(sNdx);
if (!dumpVisibleStacksOnly || stack.shouldBeVisible(null)) {
activities.addAll(stack.getDumpActivitiesLocked(name));
}
@@ -3595,7 +3594,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
public void dump(PrintWriter pw, String prefix, boolean dumpAll) {
super.dump(pw, prefix, dumpAll);
pw.print(prefix);
- pw.println("topDisplayFocusedStack=" + getTopDisplayFocusedStack());
+ pw.println("topDisplayFocusedStack=" + getTopDisplayFocusedRootTask());
for (int i = getChildCount() - 1; i >= 0; --i) {
final DisplayContent display = getChildAt(i);
display.dump(pw, prefix, dumpAll);
@@ -3635,8 +3634,8 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
pw.print(displayContent.mDisplayId);
pw.println(" (activities from top to bottom):");
displayContent.forAllTaskDisplayAreas(taskDisplayArea -> {
- for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {
- final Task stack = taskDisplayArea.getStackAt(sNdx);
+ for (int sNdx = taskDisplayArea.getRootTaskCount() - 1; sNdx >= 0; --sNdx) {
+ final Task stack = taskDisplayArea.getRootTaskAt(sNdx);
if (needSep[0]) {
pw.println();
}
diff --git a/services/core/java/com/android/server/wm/RunningTasks.java b/services/core/java/com/android/server/wm/RunningTasks.java
index 7b5b0ad870dd..6ef5d4da63cb 100644
--- a/services/core/java/com/android/server/wm/RunningTasks.java
+++ b/services/core/java/com/android/server/wm/RunningTasks.java
@@ -67,7 +67,7 @@ class RunningTasks {
mProfileIds = profileIds;
mAllowed = allowed;
mFilterOnlyVisibleRecents = filterOnlyVisibleRecents;
- mTopDisplayFocusStack = root.getTopDisplayFocusedStack();
+ mTopDisplayFocusStack = root.getTopDisplayFocusedRootTask();
mRecentTasks = root.mService.getRecentTasks();
final PooledConsumer c = PooledLambda.obtainConsumer(RunningTasks::processTask, this,
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index b46e796698e4..c414c6421dc8 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -38,7 +38,6 @@ import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_POSITION
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import android.annotation.Nullable;
-import android.app.ActivityManagerInternal;
import android.app.PendingIntent;
import android.content.ClipData;
import android.content.ClipDescription;
@@ -56,6 +55,7 @@ import android.os.Process;
import android.os.RemoteException;
import android.os.Trace;
import android.os.UserHandle;
+import android.service.attestation.ImpressionToken;
import android.text.TextUtils;
import android.util.ArraySet;
import android.util.MergedConfiguration;
@@ -848,4 +848,15 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {
Binder.restoreCallingIdentity(identity);
}
}
+
+ @Override
+ public ImpressionToken generateImpressionToken(IWindow window, Rect boundsInWindow,
+ String hashAlgorithm) {
+ final long origId = Binder.clearCallingIdentity();
+ try {
+ return mService.generateImpressionToken(this, window, boundsInWindow, hashAlgorithm);
+ } finally {
+ Binder.restoreCallingIdentity(origId);
+ }
+ }
}
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index ebf5989d6b55..4b65ce0f7088 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -101,7 +101,7 @@ import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_USER_
import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_VISIBILITY;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
-import static com.android.server.wm.ActivityTaskManagerService.H.FIRST_ACTIVITY_STACK_MSG;
+import static com.android.server.wm.ActivityTaskManagerService.H.FIRST_ACTIVITY_TASK_MSG;
import static com.android.server.wm.ActivityTaskSupervisor.DEFER_RESUME;
import static com.android.server.wm.ActivityTaskSupervisor.ON_TOP;
import static com.android.server.wm.ActivityTaskSupervisor.PRESERVE_WINDOWS;
@@ -196,6 +196,8 @@ import android.util.ArraySet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.Slog;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
import android.util.proto.ProtoOutputStream;
import android.view.DisplayInfo;
import android.view.RemoteAnimationAdapter;
@@ -597,7 +599,7 @@ class Task extends WindowContainer<WindowContainer> {
private final AnimatingActivityRegistry mAnimatingActivityRegistry =
new AnimatingActivityRegistry();
- private static final int TRANSLUCENT_TIMEOUT_MSG = FIRST_ACTIVITY_STACK_MSG + 1;
+ private static final int TRANSLUCENT_TIMEOUT_MSG = FIRST_ACTIVITY_TASK_MSG + 1;
private final Handler mHandler;
@@ -650,7 +652,7 @@ class Task extends WindowContainer<WindowContainer> {
if (mUpdateConfig) {
// Ensure the resumed state of the focus activity if we updated the configuration of
// any activity.
- mRootWindowContainer.resumeFocusedStacksTopActivities();
+ mRootWindowContainer.resumeFocusedTasksTopActivities();
}
}
@@ -973,7 +975,7 @@ class Task extends WindowContainer<WindowContainer> {
}
mResizeMode = resizeMode;
mRootWindowContainer.ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS);
- mRootWindowContainer.resumeFocusedStacksTopActivities();
+ mRootWindowContainer.resumeFocusedTasksTopActivities();
updateTaskDescription();
}
@@ -1028,7 +1030,7 @@ class Task extends WindowContainer<WindowContainer> {
// activities stay the same.
mRootWindowContainer.ensureActivitiesVisible(r, 0, preserveWindow);
if (!kept) {
- mRootWindowContainer.resumeFocusedStacksTopActivities();
+ mRootWindowContainer.resumeFocusedTasksTopActivities();
}
}
}
@@ -1096,7 +1098,7 @@ class Task extends WindowContainer<WindowContainer> {
final RootWindowContainer root = mRootWindowContainer;
final WindowManagerService windowManager = mAtmService.mWindowManager;
final Task sourceStack = getRootTask();
- final Task toStack = supervisor.getReparentTargetStack(this, preferredStack,
+ final Task toStack = supervisor.getReparentTargetRootTask(this, preferredStack,
position == MAX_VALUE);
if (toStack == sourceStack) {
return false;
@@ -1134,7 +1136,7 @@ class Task extends WindowContainer<WindowContainer> {
boolean kept = true;
try {
final ActivityRecord r = topRunningActivityLocked();
- final boolean wasFocused = r != null && root.isTopDisplayFocusedStack(sourceStack)
+ final boolean wasFocused = r != null && root.isTopDisplayFocusedRootTask(sourceStack)
&& (topRunningActivityLocked() == r);
final boolean wasResumed = r != null && sourceStack.getResumedActivity() == r;
final boolean wasPaused = r != null && sourceStack.mPausingActivity == r;
@@ -1174,7 +1176,7 @@ class Task extends WindowContainer<WindowContainer> {
&& moveStackMode == REPARENT_KEEP_ROOT_TASK_AT_FRONT) {
// Move recents to front so it is not behind home stack when going into docked
// mode
- mTaskSupervisor.moveRecentsStackToFront(reason);
+ mTaskSupervisor.moveRecentsRootTaskToFront(reason);
}
} finally {
mAtmService.continueWindowLayout();
@@ -1191,7 +1193,7 @@ class Task extends WindowContainer<WindowContainer> {
// The task might have already been running and its visibility needs to be synchronized
// with the visibility of the stack / windows.
root.ensureActivitiesVisible(null, 0, !mightReplaceWindow);
- root.resumeFocusedStacksTopActivities();
+ root.resumeFocusedTasksTopActivities();
}
// TODO: Handle incorrect request to move before the actual move, not after.
@@ -1694,7 +1696,7 @@ class Task extends WindowContainer<WindowContainer> {
// A rootable task that is now being added to be the child of an organized task. Making
// sure the stack references is keep updated.
if (mTaskOrganizer != null && mCreatedByOrganizer && child.asTask() != null) {
- getDisplayArea().addStackReferenceIfNeeded((Task) child);
+ getDisplayArea().addRootTaskReferenceIfNeeded((Task) child);
}
// Make sure the list of display UID allowlists is updated
@@ -1744,7 +1746,7 @@ class Task extends WindowContainer<WindowContainer> {
// A rootable child task that is now being removed from an organized task. Making sure
// the stack references is keep updated.
if (mCreatedByOrganizer && r.asTask() != null) {
- getDisplayArea().removeStackReferenceIfNeeded((Task) r);
+ getDisplayArea().removeRootTaskReferenceIfNeeded((Task) r);
}
if (!mChildren.contains(r)) {
Slog.e(TAG, "removeChild: r=" + r + " not found in t=" + this);
@@ -2249,7 +2251,7 @@ class Task extends WindowContainer<WindowContainer> {
// the rotation animation needs to capture snapshot earlier to avoid animating from
// an intermediate state.
if (oldOrientation != getOrientation()) {
- onDescendantOrientationChanged(null, this);
+ onDescendantOrientationChanged(this);
}
} finally {
if (pipChanging) {
@@ -2301,7 +2303,7 @@ class Task extends WindowContainer<WindowContainer> {
}
if (prevWindowingMode != getWindowingMode()) {
- taskDisplayArea.onStackWindowingModeChanged(this);
+ taskDisplayArea.onRootTaskWindowingModeChanged(this);
}
if (mDisplayContent == null) {
@@ -2328,7 +2330,7 @@ class Task extends WindowContainer<WindowContainer> {
}
if (windowingModeChanged) {
- taskDisplayArea.onStackWindowingModeChanged(this);
+ taskDisplayArea.onRootTaskWindowingModeChanged(this);
}
if (hasNewOverrideBounds) {
if (inSplitScreenWindowingMode()) {
@@ -3095,7 +3097,7 @@ class Task extends WindowContainer<WindowContainer> {
boolean moveDisplayToTop) {
Task focusableTask = getNextFocusableTask(allowFocusSelf);
if (focusableTask == null) {
- focusableTask = mRootWindowContainer.getNextFocusableStack(this, !allowFocusSelf);
+ focusableTask = mRootWindowContainer.getNextFocusableRootTask(this, !allowFocusSelf);
}
if (focusableTask == null) {
return null;
@@ -3305,9 +3307,8 @@ class Task extends WindowContainer<WindowContainer> {
}
@Override
- public boolean onDescendantOrientationChanged(IBinder freezeDisplayToken,
- WindowContainer requestingContainer) {
- if (super.onDescendantOrientationChanged(freezeDisplayToken, requestingContainer)) {
+ public boolean onDescendantOrientationChanged(WindowContainer requestingContainer) {
+ if (super.onDescendantOrientationChanged(requestingContainer)) {
return true;
}
@@ -4099,6 +4100,7 @@ class Task extends WindowContainer<WindowContainer> {
? rootTask.mTaskId
: INVALID_TASK_ID;
info.isFocused = isFocused();
+ info.isVisible = hasVisibleChildren();
}
@Nullable PictureInPictureParams getPictureInPictureParams() {
@@ -4483,14 +4485,14 @@ class Task extends WindowContainer<WindowContainer> {
/**
* Saves this {@link Task} to XML using given serializer.
*/
- void saveToXml(XmlSerializer out) throws Exception {
+ void saveToXml(TypedXmlSerializer out) throws Exception {
if (DEBUG_RECENTS) Slog.i(TAG_RECENTS, "Saving task=" + this);
- out.attribute(null, ATTR_TASKID, String.valueOf(mTaskId));
+ out.attributeInt(null, ATTR_TASKID, mTaskId);
if (realActivity != null) {
out.attribute(null, ATTR_REALACTIVITY, realActivity.flattenToShortString());
}
- out.attribute(null, ATTR_REALACTIVITY_SUSPENDED, String.valueOf(realActivitySuspended));
+ out.attributeBoolean(null, ATTR_REALACTIVITY_SUSPENDED, realActivitySuspended);
if (origActivity != null) {
out.attribute(null, ATTR_ORIGACTIVITY, origActivity.flattenToShortString());
}
@@ -4509,37 +4511,36 @@ class Task extends WindowContainer<WindowContainer> {
if (mWindowLayoutAffinity != null) {
out.attribute(null, ATTR_WINDOW_LAYOUT_AFFINITY, mWindowLayoutAffinity);
}
- out.attribute(null, ATTR_ROOTHASRESET, String.valueOf(rootWasReset));
- out.attribute(null, ATTR_AUTOREMOVERECENTS, String.valueOf(autoRemoveRecents));
- out.attribute(null, ATTR_ASKEDCOMPATMODE, String.valueOf(askedCompatMode));
- out.attribute(null, ATTR_USERID, String.valueOf(mUserId));
- out.attribute(null, ATTR_USER_SETUP_COMPLETE, String.valueOf(mUserSetupComplete));
- out.attribute(null, ATTR_EFFECTIVE_UID, String.valueOf(effectiveUid));
- out.attribute(null, ATTR_LASTTIMEMOVED, String.valueOf(mLastTimeMoved));
- out.attribute(null, ATTR_NEVERRELINQUISH, String.valueOf(mNeverRelinquishIdentity));
+ out.attributeBoolean(null, ATTR_ROOTHASRESET, rootWasReset);
+ out.attributeBoolean(null, ATTR_AUTOREMOVERECENTS, autoRemoveRecents);
+ out.attributeBoolean(null, ATTR_ASKEDCOMPATMODE, askedCompatMode);
+ out.attributeInt(null, ATTR_USERID, mUserId);
+ out.attributeBoolean(null, ATTR_USER_SETUP_COMPLETE, mUserSetupComplete);
+ out.attributeInt(null, ATTR_EFFECTIVE_UID, effectiveUid);
+ out.attributeLong(null, ATTR_LASTTIMEMOVED, mLastTimeMoved);
+ out.attributeBoolean(null, ATTR_NEVERRELINQUISH, mNeverRelinquishIdentity);
if (lastDescription != null) {
out.attribute(null, ATTR_LASTDESCRIPTION, lastDescription.toString());
}
if (getTaskDescription() != null) {
getTaskDescription().saveToXml(out);
}
- out.attribute(null, ATTR_TASK_AFFILIATION, String.valueOf(mAffiliatedTaskId));
- out.attribute(null, ATTR_PREV_AFFILIATION, String.valueOf(mPrevAffiliateTaskId));
- out.attribute(null, ATTR_NEXT_AFFILIATION, String.valueOf(mNextAffiliateTaskId));
- out.attribute(null, ATTR_CALLING_UID, String.valueOf(mCallingUid));
+ out.attributeInt(null, ATTR_TASK_AFFILIATION, mAffiliatedTaskId);
+ out.attributeInt(null, ATTR_PREV_AFFILIATION, mPrevAffiliateTaskId);
+ out.attributeInt(null, ATTR_NEXT_AFFILIATION, mNextAffiliateTaskId);
+ out.attributeInt(null, ATTR_CALLING_UID, mCallingUid);
out.attribute(null, ATTR_CALLING_PACKAGE, mCallingPackage == null ? "" : mCallingPackage);
out.attribute(null, ATTR_CALLING_FEATURE_ID,
mCallingFeatureId == null ? "" : mCallingFeatureId);
- out.attribute(null, ATTR_RESIZE_MODE, String.valueOf(mResizeMode));
- out.attribute(null, ATTR_SUPPORTS_PICTURE_IN_PICTURE,
- String.valueOf(mSupportsPictureInPicture));
+ out.attributeInt(null, ATTR_RESIZE_MODE, mResizeMode);
+ out.attributeBoolean(null, ATTR_SUPPORTS_PICTURE_IN_PICTURE, mSupportsPictureInPicture);
if (mLastNonFullscreenBounds != null) {
out.attribute(
null, ATTR_NON_FULLSCREEN_BOUNDS, mLastNonFullscreenBounds.flattenToString());
}
- out.attribute(null, ATTR_MIN_WIDTH, String.valueOf(mMinWidth));
- out.attribute(null, ATTR_MIN_HEIGHT, String.valueOf(mMinHeight));
- out.attribute(null, ATTR_PERSIST_TASK_VERSION, String.valueOf(PERSIST_TASK_VERSION));
+ out.attributeInt(null, ATTR_MIN_WIDTH, mMinWidth);
+ out.attributeInt(null, ATTR_MIN_HEIGHT, mMinHeight);
+ out.attributeInt(null, ATTR_PERSIST_TASK_VERSION, PERSIST_TASK_VERSION);
if (affinityIntent != null) {
out.startTag(null, TAG_AFFINITYINTENT);
@@ -4564,7 +4565,7 @@ class Task extends WindowContainer<WindowContainer> {
}
private static boolean saveActivityToXml(
- ActivityRecord r, ActivityRecord first, XmlSerializer out) {
+ ActivityRecord r, ActivityRecord first, TypedXmlSerializer out) {
if (r.info.persistableMode == ActivityInfo.PERSIST_ROOT_ONLY || !r.isPersistable()
|| ((r.intent.getFlags() & FLAG_ACTIVITY_NEW_DOCUMENT
| FLAG_ACTIVITY_RETAIN_IN_RECENTS) == FLAG_ACTIVITY_NEW_DOCUMENT)
@@ -4583,7 +4584,7 @@ class Task extends WindowContainer<WindowContainer> {
}
}
- static Task restoreFromXml(XmlPullParser in, ActivityTaskSupervisor taskSupervisor)
+ static Task restoreFromXml(TypedXmlPullParser in, ActivityTaskSupervisor taskSupervisor)
throws IOException, XmlPullParserException {
Intent intent = null;
Intent affinityIntent = null;
@@ -5132,7 +5133,7 @@ class Task extends WindowContainer<WindowContainer> {
// The change in force-hidden state will change visibility without triggering a stack
// order change, so we should reset the preferred top focusable stack to ensure it's not
// used if a new activity is started from this task.
- getDisplayArea().resetPreferredTopFocusableStackIfBelow(this);
+ getDisplayArea().resetPreferredTopFocusableRootTaskIfBelow(this);
}
return true;
}
@@ -5275,14 +5276,14 @@ class Task extends WindowContainer<WindowContainer> {
}
mRootWindowContainer.ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS);
- mRootWindowContainer.resumeFocusedStacksTopActivities();
+ mRootWindowContainer.resumeFocusedTasksTopActivities();
}
/** Resume next focusable stack after reparenting to another display. */
void postReparent() {
adjustFocusToNextFocusableTask("reparent", true /* allowFocusSelf */,
true /* moveDisplayToTop */);
- mRootWindowContainer.resumeFocusedStacksTopActivities();
+ mRootWindowContainer.resumeFocusedTasksTopActivities();
// Update visibility of activities before notifying WM. This way it won't try to resize
// windows that are no longer visible.
mRootWindowContainer.ensureActivitiesVisible(null /* starting */, 0 /* configChanges */,
@@ -5319,7 +5320,7 @@ class Task extends WindowContainer<WindowContainer> {
// cutting between them.
// TODO(b/70677280): This is a workaround until we can fix as part of b/70677280.
final Task topFullScreenStack =
- taskDisplayArea.getTopStackInWindowingMode(WINDOWING_MODE_FULLSCREEN);
+ taskDisplayArea.getTopRootTaskInWindowingMode(WINDOWING_MODE_FULLSCREEN);
if (topFullScreenStack != null) {
final Task primarySplitScreenStack =
taskDisplayArea.getRootSplitScreenPrimaryTask();
@@ -5334,10 +5335,10 @@ class Task extends WindowContainer<WindowContainer> {
if (!isActivityTypeHome() && returnsToHomeStack()) {
// Make sure the home stack is behind this stack since that is where we should return to
// when this stack is no longer visible.
- taskDisplayArea.moveHomeStackToFront(reason + " returnToHome");
+ taskDisplayArea.moveHomeRootTaskToFront(reason + " returnToHome");
}
- final Task lastFocusedTask = isRootTask() ? taskDisplayArea.getFocusedStack() : null;
+ final Task lastFocusedTask = isRootTask() ? taskDisplayArea.getFocusedRootTask() : null;
if (task == null) {
task = this;
}
@@ -5365,7 +5366,7 @@ class Task extends WindowContainer<WindowContainer> {
if (parentTask != null) {
parentTask.moveToBack(reason, this);
} else {
- final Task lastFocusedTask = displayArea.getFocusedStack();
+ final Task lastFocusedTask = displayArea.getFocusedRootTask();
displayArea.positionChildAt(POSITION_BOTTOM, this, false /*includingParents*/);
displayArea.updateLastFocusedRootTask(lastFocusedTask, reason);
}
@@ -5514,7 +5515,7 @@ class Task extends WindowContainer<WindowContainer> {
if (prev == null) {
if (resuming == null) {
Slog.wtf(TAG, "Trying to pause when nothing is resumed");
- mRootWindowContainer.resumeFocusedStacksTopActivities();
+ mRootWindowContainer.resumeFocusedTasksTopActivities();
}
return false;
}
@@ -5621,7 +5622,7 @@ class Task extends WindowContainer<WindowContainer> {
// pause, so just treat it as being paused now.
ProtoLog.v(WM_DEBUG_STATES, "Activity not running, resuming next.");
if (resuming == null) {
- mRootWindowContainer.resumeFocusedStacksTopActivities();
+ mRootWindowContainer.resumeFocusedTasksTopActivities();
}
return false;
}
@@ -5674,9 +5675,9 @@ class Task extends WindowContainer<WindowContainer> {
}
if (resumeNext) {
- final Task topStack = mRootWindowContainer.getTopDisplayFocusedStack();
+ final Task topStack = mRootWindowContainer.getTopDisplayFocusedRootTask();
if (topStack != null && !topStack.shouldSleepOrShutDownActivities()) {
- mRootWindowContainer.resumeFocusedStacksTopActivities(topStack, prev, null);
+ mRootWindowContainer.resumeFocusedTasksTopActivities(topStack, prev, null);
} else {
checkReadyForSleep();
final ActivityRecord top = topStack != null ? topStack.topRunningActivity() : null;
@@ -5685,7 +5686,7 @@ class Task extends WindowContainer<WindowContainer> {
// something. Also if the top activity on the stack is not the just paused
// activity, we need to go ahead and resume it to ensure we complete an
// in-flight app switch.
- mRootWindowContainer.resumeFocusedStacksTopActivities();
+ mRootWindowContainer.resumeFocusedTasksTopActivities();
}
}
}
@@ -5708,7 +5709,7 @@ class Task extends WindowContainer<WindowContainer> {
boolean isTopStackInDisplayArea() {
final TaskDisplayArea taskDisplayArea = getDisplayArea();
- return taskDisplayArea != null && taskDisplayArea.isTopStack(this);
+ return taskDisplayArea != null && taskDisplayArea.isTopRootTask(this);
}
/**
@@ -5716,7 +5717,7 @@ class Task extends WindowContainer<WindowContainer> {
* otherwise.
*/
boolean isFocusedStackOnDisplay() {
- return mDisplayContent != null && this == mDisplayContent.getFocusedStack();
+ return mDisplayContent != null && this == mDisplayContent.getFocusedRootTask();
}
/**
@@ -5764,6 +5765,10 @@ class Task extends WindowContainer<WindowContainer> {
starting, configChanges, preserveWindows, notifyClients, userLeaving),
true /* traverseTopToBottom */);
+ // Notify WM shell that task visibilities may have changed
+ forAllTasks(task -> task.dispatchTaskInfoChangedIfNeeded(/* force */ false),
+ true /* traverseTopToBottom */);
+
if (mTranslucentActivityWaiting != null &&
mUndrawnActivitiesBelowTopTranslucent.isEmpty()) {
// Nothing is getting drawn or everything was already visible, don't wait for
@@ -5790,7 +5795,7 @@ class Task extends WindowContainer<WindowContainer> {
*/
boolean isTopSplitScreenStack() {
return inSplitScreenWindowingMode()
- && this == getDisplayArea().getTopStackInWindowingMode(getWindowingMode());
+ && this == getDisplayArea().getTopRootTaskInWindowingMode(getWindowingMode());
}
void checkTranslucentActivityWaiting(ActivityRecord top) {
@@ -5874,7 +5879,7 @@ class Task extends WindowContainer<WindowContainer> {
*
* NOTE: It is not safe to call this method directly as it can cause an activity in a
* non-focused stack to be resumed.
- * Use {@link RootWindowContainer#resumeFocusedStacksTopActivities} to resume the
+ * Use {@link RootWindowContainer#resumeFocusedTasksTopActivities} to resume the
* right activity for the current system state.
*/
@GuardedBy("mService")
@@ -6028,7 +6033,7 @@ class Task extends WindowContainer<WindowContainer> {
mTaskSupervisor.setLaunchSource(next.info.applicationInfo.uid);
ActivityRecord lastResumed = null;
- final Task lastFocusedStack = taskDisplayArea.getLastFocusedStack();
+ final Task lastFocusedStack = taskDisplayArea.getLastFocusedRootTask();
if (lastFocusedStack != null && lastFocusedStack != this) {
// So, why aren't we using prev here??? See the param comment on the method. prev
// doesn't represent the last resumed activity. However, the last focus stack does if
@@ -6043,7 +6048,7 @@ class Task extends WindowContainer<WindowContainer> {
}
}
- boolean pausing = taskDisplayArea.pauseBackStacks(userLeaving, next);
+ boolean pausing = taskDisplayArea.pauseBackTasks(userLeaving, next);
if (mResumedActivity != null) {
ProtoLog.d(WM_DEBUG_STATES, "resumeTopActivityLocked: Pausing %s", mResumedActivity);
pausing |= startPausingLocked(userLeaving, false /* uiSleeping */, next,
@@ -6064,7 +6069,7 @@ class Task extends WindowContainer<WindowContainer> {
// Since the start-process is asynchronous, if we already know the process of next
// activity isn't running, we can start the process earlier to save the time to wait
// for the current activity to be paused.
- final boolean isTop = this == taskDisplayArea.getFocusedStack();
+ final boolean isTop = this == taskDisplayArea.getFocusedRootTask();
mAtmService.startProcessAsync(next, false /* knownToBeDead */, isTop,
isTop ? "pre-top-activity" : "pre-activity");
}
@@ -6354,7 +6359,7 @@ class Task extends WindowContainer<WindowContainer> {
// Try to move focus to the next visible stack with a running activity if this
// stack is not covering the entire screen or is on a secondary display with no home
// stack.
- return mRootWindowContainer.resumeFocusedStacksTopActivities(nextFocusedStack,
+ return mRootWindowContainer.resumeFocusedTasksTopActivities(nextFocusedStack,
prev, null /* targetOptions */);
}
}
@@ -6834,7 +6839,7 @@ class Task extends WindowContainer<WindowContainer> {
AppTimeTracker timeTracker, boolean deferResume, String reason) {
if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "moveTaskToFront: " + tr);
- final Task topStack = getDisplayArea().getTopStack();
+ final Task topStack = getDisplayArea().getTopRootTask();
final ActivityRecord topActivity = topStack != null
? topStack.getTopNonFinishingActivity() : null;
@@ -6897,7 +6902,7 @@ class Task extends WindowContainer<WindowContainer> {
}
if (!deferResume) {
- mRootWindowContainer.resumeFocusedStacksTopActivities();
+ mRootWindowContainer.resumeFocusedTasksTopActivities();
}
} finally {
mDisplayContent.continueUpdateImeTarget();
@@ -6970,7 +6975,7 @@ class Task extends WindowContainer<WindowContainer> {
// resumed in this case, so we need to execute it explicitly.
mDisplayContent.executeAppTransition();
} else {
- mRootWindowContainer.resumeFocusedStacksTopActivities();
+ mRootWindowContainer.resumeFocusedTasksTopActivities();
}
return true;
}
@@ -7275,7 +7280,7 @@ class Task extends WindowContainer<WindowContainer> {
final boolean wasResumed = topRunningActivity == task.getRootTask().mResumedActivity;
boolean toTop = position >= getChildCount();
- boolean includingParents = toTop || getDisplayArea().getNextFocusableStack(this,
+ boolean includingParents = toTop || getDisplayArea().getNextFocusableRootTask(this,
true /* ignoreCurrent */) == null;
if (WindowManagerDebugConfig.DEBUG_ROOT_TASK) {
Slog.i(TAG_WM, "positionChildAt: positioning task=" + task + " at " + position);
@@ -7304,7 +7309,7 @@ class Task extends WindowContainer<WindowContainer> {
// The task might have already been running and its visibility needs to be synchronized with
// the visibility of the stack / windows.
ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS);
- mRootWindowContainer.resumeFocusedStacksTopActivities();
+ mRootWindowContainer.resumeFocusedTasksTopActivities();
}
public void setAlwaysOnTop(boolean alwaysOnTop) {
@@ -7426,7 +7431,7 @@ class Task extends WindowContainer<WindowContainer> {
// If there are other focusable stacks on the display, the z-order of the display should not
// be changed just because a task was placed at the bottom. E.g. if it is moving the topmost
// task to bottom, the next focusable stack on the same display should be focused.
- final Task nextFocusableStack = getDisplayArea().getNextFocusableStack(
+ final Task nextFocusableStack = getDisplayArea().getNextFocusableRootTask(
child.getRootTask(), true /* ignoreCurrent */);
positionChildAtBottom(child, nextFocusableStack == null /* includingParents */);
}
diff --git a/services/core/java/com/android/server/wm/TaskChangeNotificationController.java b/services/core/java/com/android/server/wm/TaskChangeNotificationController.java
index 4682ba836426..b4d069c0edc1 100644
--- a/services/core/java/com/android/server/wm/TaskChangeNotificationController.java
+++ b/services/core/java/com/android/server/wm/TaskChangeNotificationController.java
@@ -193,7 +193,7 @@ class TaskChangeNotificationController {
switch (msg.what) {
case LOG_STACK_STATE_MSG: {
synchronized (mServiceLock) {
- mTaskSupervisor.logStackState();
+ mTaskSupervisor.logRootTaskState();
}
break;
}
diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java
index 81b8200aa2b4..4498a8c82583 100644
--- a/services/core/java/com/android/server/wm/TaskDisplayArea.java
+++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java
@@ -38,7 +38,7 @@ import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ORIENTATION;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_STATES;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_TASKS;
import static com.android.server.wm.ActivityTaskManagerService.TAG_ROOT_TASK;
-import static com.android.server.wm.DisplayContent.alwaysCreateStack;
+import static com.android.server.wm.DisplayContent.alwaysCreateRootTask;
import static com.android.server.wm.Task.ActivityState.RESUMED;
import static com.android.server.wm.Task.TASK_VISIBILITY_VISIBLE;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ROOT_TASK;
@@ -107,9 +107,9 @@ final class TaskDisplayArea extends DisplayArea<Task> {
// TODO(b/159029784): Remove when getStack() behavior is cleaned-up
private Task mRootRecentsTask;
- private final ArrayList<Task> mTmpAlwaysOnTopStacks = new ArrayList<>();
- private final ArrayList<Task> mTmpNormalStacks = new ArrayList<>();
- private final ArrayList<Task> mTmpHomeStacks = new ArrayList<>();
+ private final ArrayList<Task> mTmpAlwaysOnTopRootTasks = new ArrayList<>();
+ private final ArrayList<Task> mTmpNormalRootTasks = new ArrayList<>();
+ private final ArrayList<Task> mTmpHomeRootTasks = new ArrayList<>();
private final IntArray mTmpNeedsZBoostIndexes = new IntArray();
private int mTmpLayerForSplitScreenDividerAnchor;
private int mTmpLayerForAnimationLayer;
@@ -128,23 +128,25 @@ final class TaskDisplayArea extends DisplayArea<Task> {
* have the topmost index, it is used as a preferred candidate to prevent being unable to resume
* target stack properly when there are other focusable always-on-top stacks.
*/
- Task mPreferredTopFocusableStack;
+ Task mPreferredTopFocusableRootTask;
private final RootWindowContainer.FindTaskResult
mTmpFindTaskResult = new RootWindowContainer.FindTaskResult();
/**
- * If this is the same as {@link #getFocusedStack} then the activity on the top of the focused
- * stack has been resumed. If stacks are changing position this will hold the old stack until
- * the new stack becomes resumed after which it will be set to current focused stack.
+ * If this is the same as {@link #getFocusedRootTask} then the activity on the top of the
+ * focused root task has been resumed. If root tasks are changing position this will hold the
+ * old root task until the new root task becomes resumed after which it will be set to
+ * current focused root task.
*/
- Task mLastFocusedStack;
+ Task mLastFocusedRootTask;
/**
* All of the stacks on this display. Order matters, topmost stack is in front of all other
* stacks, bottommost behind. Accessed directly by ActivityManager package classes. Any calls
- * changing the list should also call {@link #onStackOrderChanged()}.
+ * changing the list should also call {@link #onRootTaskOrderChanged(Task)}.
*/
- private ArrayList<OnStackOrderChangedListener> mStackOrderChangedCallbacks = new ArrayList<>();
+ private ArrayList<OnRootTaskOrderChangedListener> mRootTaskOrderChangedCallbacks =
+ new ArrayList<>();
/**
* The task display area is removed from the system and we are just waiting for all activities
@@ -181,7 +183,7 @@ final class TaskDisplayArea extends DisplayArea<Task> {
* Returns the topmost stack on the display that is compatible with the input windowing mode
* and activity type. Null is no compatible stack on the display.
*/
- Task getStack(int windowingMode, int activityType) {
+ Task getRootTask(int windowingMode, int activityType) {
if (activityType == ACTIVITY_TYPE_HOME) {
return mRootHomeTask;
} else if (activityType == ACTIVITY_TYPE_RECENTS) {
@@ -208,7 +210,7 @@ final class TaskDisplayArea extends DisplayArea<Task> {
}
@VisibleForTesting
- Task getTopStack() {
+ Task getTopRootTask() {
final int count = getChildCount();
return count > 0 ? getChildAt(count - 1) : null;
}
@@ -255,68 +257,68 @@ final class TaskDisplayArea extends DisplayArea<Task> {
return visibleTasks;
}
- void onStackWindowingModeChanged(Task stack) {
- removeStackReferenceIfNeeded(stack);
- addStackReferenceIfNeeded(stack);
- if (stack == mRootPinnedTask && getTopStack() != stack) {
+ void onRootTaskWindowingModeChanged(Task rootTask) {
+ removeRootTaskReferenceIfNeeded(rootTask);
+ addRootTaskReferenceIfNeeded(rootTask);
+ if (rootTask == mRootPinnedTask && getTopRootTask() != rootTask) {
// Looks like this stack changed windowing mode to pinned. Move it to the top.
- positionChildAt(POSITION_TOP, stack, false /* includingParents */);
+ positionChildAt(POSITION_TOP, rootTask, false /* includingParents */);
}
}
- void addStackReferenceIfNeeded(Task stack) {
- if (stack.isActivityTypeHome()) {
+ void addRootTaskReferenceIfNeeded(Task rootTask) {
+ if (rootTask.isActivityTypeHome()) {
if (mRootHomeTask != null) {
- if (!stack.isDescendantOf(mRootHomeTask)) {
+ if (!rootTask.isDescendantOf(mRootHomeTask)) {
throw new IllegalArgumentException("addStackReferenceIfNeeded: home stack="
+ mRootHomeTask + " already exist on display=" + this
- + " stack=" + stack);
+ + " stack=" + rootTask);
}
} else {
- mRootHomeTask = stack;
+ mRootHomeTask = rootTask;
}
- } else if (stack.isActivityTypeRecents()) {
+ } else if (rootTask.isActivityTypeRecents()) {
if (mRootRecentsTask != null) {
- if (!stack.isDescendantOf(mRootRecentsTask)) {
+ if (!rootTask.isDescendantOf(mRootRecentsTask)) {
throw new IllegalArgumentException("addStackReferenceIfNeeded: recents stack="
+ mRootRecentsTask + " already exist on display=" + this
- + " stack=" + stack);
+ + " stack=" + rootTask);
}
} else {
- mRootRecentsTask = stack;
+ mRootRecentsTask = rootTask;
}
}
- if (!stack.isRootTask()) {
+ if (!rootTask.isRootTask()) {
return;
}
- final int windowingMode = stack.getWindowingMode();
+ final int windowingMode = rootTask.getWindowingMode();
if (windowingMode == WINDOWING_MODE_PINNED) {
if (mRootPinnedTask != null) {
throw new IllegalArgumentException(
"addStackReferenceIfNeeded: pinned stack=" + mRootPinnedTask
- + " already exist on display=" + this + " stack=" + stack);
+ + " already exist on display=" + this + " stack=" + rootTask);
}
- mRootPinnedTask = stack;
+ mRootPinnedTask = rootTask;
} else if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
if (mRootSplitScreenPrimaryTask != null) {
throw new IllegalArgumentException(
"addStackReferenceIfNeeded: split screen primary stack="
+ mRootSplitScreenPrimaryTask
- + " already exist on display=" + this + " stack=" + stack);
+ + " already exist on display=" + this + " stack=" + rootTask);
}
- mRootSplitScreenPrimaryTask = stack;
+ mRootSplitScreenPrimaryTask = rootTask;
}
}
- void removeStackReferenceIfNeeded(Task stack) {
- if (stack == mRootHomeTask) {
+ void removeRootTaskReferenceIfNeeded(Task rootTask) {
+ if (rootTask == mRootHomeTask) {
mRootHomeTask = null;
- } else if (stack == mRootRecentsTask) {
+ } else if (rootTask == mRootRecentsTask) {
mRootRecentsTask = null;
- } else if (stack == mRootPinnedTask) {
+ } else if (rootTask == mRootPinnedTask) {
mRootPinnedTask = null;
- } else if (stack == mRootSplitScreenPrimaryTask) {
+ } else if (rootTask == mRootSplitScreenPrimaryTask) {
mRootSplitScreenPrimaryTask = null;
}
}
@@ -325,20 +327,20 @@ final class TaskDisplayArea extends DisplayArea<Task> {
void addChild(Task task, int position) {
if (DEBUG_ROOT_TASK) Slog.d(TAG_WM, "Set task=" + task + " on taskDisplayArea=" + this);
- addStackReferenceIfNeeded(task);
- position = findPositionForStack(position, task, true /* adding */);
+ addRootTaskReferenceIfNeeded(task);
+ position = findPositionForRootTask(position, task, true /* adding */);
super.addChild(task, position);
mAtmService.updateSleepIfNeededLocked();
- onStackOrderChanged(task);
+ onRootTaskOrderChanged(task);
}
@Override
protected void removeChild(Task stack) {
super.removeChild(stack);
- onStackRemoved(stack);
+ onRootTaskRemoved(stack);
mAtmService.updateSleepIfNeededLocked();
- removeStackReferenceIfNeeded(stack);
+ removeRootTaskReferenceIfNeeded(stack);
}
@Override
@@ -367,7 +369,7 @@ final class TaskDisplayArea extends DisplayArea<Task> {
if (!mDisplayContent.isTrusted() && !getParent().isOnTop()) {
includingParents = false;
}
- final int targetPosition = findPositionForStack(position, child, false /* adding */);
+ final int targetPosition = findPositionForRootTask(position, child, false /* adding */);
super.positionChildAt(targetPosition, child, false /* includingParents */);
if (includingParents && getParent() != null && (moveToTop || moveToBottom)) {
@@ -385,16 +387,16 @@ final class TaskDisplayArea extends DisplayArea<Task> {
// preferred stack is set only when moving an existing stack to top instead of adding a new
// stack that may be too early (e.g. in the middle of launching or reparenting).
if (moveToTop && child.isFocusableAndVisible()) {
- mPreferredTopFocusableStack = child;
- } else if (mPreferredTopFocusableStack == child) {
- mPreferredTopFocusableStack = null;
+ mPreferredTopFocusableRootTask = child;
+ } else if (mPreferredTopFocusableRootTask == child) {
+ mPreferredTopFocusableRootTask = null;
}
// Update the top resumed activity because the preferred top focusable task may be changed.
mAtmService.mTaskSupervisor.updateTopResumedActivityIfNeeded();
if (mChildren.indexOf(child) != oldPosition) {
- onStackOrderChanged(child);
+ onRootTaskOrderChanged(child);
}
}
@@ -469,21 +471,21 @@ final class TaskDisplayArea extends DisplayArea<Task> {
return 0;
}
- private int findMinPositionForStack(Task stack) {
+ private int findMinPositionForRootTask(Task rootTask) {
int minPosition = POSITION_BOTTOM;
for (int i = 0; i < mChildren.size(); ++i) {
- if (getPriority(getStackAt(i)) < getPriority(stack)) {
+ if (getPriority(getRootTaskAt(i)) < getPriority(rootTask)) {
minPosition = i;
} else {
break;
}
}
- if (stack.isAlwaysOnTop()) {
+ if (rootTask.isAlwaysOnTop()) {
// Since a stack could be repositioned while still being one of the children, we check
// if this always-on-top stack already exists and if so, set the minPosition to its
// previous position.
- final int currentIndex = getIndexOf(stack);
+ final int currentIndex = getIndexOf(rootTask);
if (currentIndex > minPosition) {
minPosition = currentIndex;
}
@@ -491,13 +493,13 @@ final class TaskDisplayArea extends DisplayArea<Task> {
return minPosition;
}
- private int findMaxPositionForStack(Task stack) {
+ private int findMaxPositionForRootTask(Task rootTask) {
for (int i = mChildren.size() - 1; i >= 0; --i) {
- final Task curr = getStackAt(i);
+ final Task curr = getRootTaskAt(i);
// Since a stack could be repositioned while still being one of the children, we check
// if 'curr' is the same stack and skip it if so
- final boolean sameStack = curr == stack;
- if (getPriority(curr) <= getPriority(stack) && !sameStack) {
+ final boolean sameRootTask = curr == rootTask;
+ if (getPriority(curr) <= getPriority(rootTask) && !sameRootTask) {
return i;
}
}
@@ -519,16 +521,16 @@ final class TaskDisplayArea extends DisplayArea<Task> {
* (including the Dream); otherwise, it is a normal non-always-on-top stack
*
* @param requestedPosition Position requested by caller.
- * @param stack Stack to be added or positioned.
+ * @param rootTask Root task to be added or positioned.
* @param adding Flag indicates whether we're adding a new stack or positioning an
* existing.
* @return The proper position for the stack.
*/
- private int findPositionForStack(int requestedPosition, Task stack, boolean adding) {
+ private int findPositionForRootTask(int requestedPosition, Task rootTask, boolean adding) {
// The max possible position we can insert the stack at.
- int maxPosition = findMaxPositionForStack(stack);
+ int maxPosition = findMaxPositionForRootTask(rootTask);
// The min possible position we can insert the stack at.
- int minPosition = findMinPositionForStack(stack);
+ int minPosition = findMinPositionForRootTask(rootTask);
// Cap the requested position to something reasonable for the previous position check
// below.
@@ -542,7 +544,7 @@ final class TaskDisplayArea extends DisplayArea<Task> {
targetPosition = Math.min(targetPosition, maxPosition);
targetPosition = Math.max(targetPosition, minPosition);
- int prevPosition = mChildren.indexOf(stack);
+ int prevPosition = mChildren.indexOf(rootTask);
// The positions we calculated above (maxPosition, minPosition) do not take into
// consideration the following edge cases.
// 1) We need to adjust the position depending on the value "adding".
@@ -645,7 +647,7 @@ final class TaskDisplayArea extends DisplayArea<Task> {
return SCREEN_ORIENTATION_UNSET;
}
- if (isStackVisible(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY)) {
+ if (isRootTaskVisible(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY)) {
// Apps and their containers are not allowed to specify an orientation while using
// root tasks...except for the home stack if it is not resizable and currently
// visible (top of) its root task.
@@ -672,7 +674,7 @@ final class TaskDisplayArea extends DisplayArea<Task> {
} else {
// Apps and their containers are not allowed to specify an orientation of full screen
// tasks created by organizer. The organizer handles the orientation instead.
- final Task task = getTopStackInWindowingMode(WINDOWING_MODE_FULLSCREEN);
+ final Task task = getTopRootTaskInWindowingMode(WINDOWING_MODE_FULLSCREEN);
if (task != null && task.isVisible() && task.mCreatedByOrganizer) {
return SCREEN_ORIENTATION_UNSPECIFIED;
}
@@ -697,7 +699,7 @@ final class TaskDisplayArea extends DisplayArea<Task> {
@Override
void assignChildLayers(SurfaceControl.Transaction t) {
- assignStackOrdering(t);
+ assignRootTaskOrdering(t);
for (int i = 0; i < mChildren.size(); i++) {
final Task s = mChildren.get(i);
@@ -705,37 +707,37 @@ final class TaskDisplayArea extends DisplayArea<Task> {
}
}
- void assignStackOrdering(SurfaceControl.Transaction t) {
+ void assignRootTaskOrdering(SurfaceControl.Transaction t) {
if (getParent() == null) {
return;
}
- mTmpAlwaysOnTopStacks.clear();
- mTmpHomeStacks.clear();
- mTmpNormalStacks.clear();
+ mTmpAlwaysOnTopRootTasks.clear();
+ mTmpHomeRootTasks.clear();
+ mTmpNormalRootTasks.clear();
for (int i = 0; i < mChildren.size(); ++i) {
final Task s = mChildren.get(i);
if (s.isAlwaysOnTop()) {
- mTmpAlwaysOnTopStacks.add(s);
+ mTmpAlwaysOnTopRootTasks.add(s);
} else if (s.isActivityTypeHome()) {
- mTmpHomeStacks.add(s);
+ mTmpHomeRootTasks.add(s);
} else {
- mTmpNormalStacks.add(s);
+ mTmpNormalRootTasks.add(s);
}
}
int layer = 0;
// Place home stacks to the bottom.
- layer = adjustRootTaskLayer(t, mTmpHomeStacks, layer, false /* normalStacks */);
+ layer = adjustRootTaskLayer(t, mTmpHomeRootTasks, layer, false /* normalStacks */);
// The home animation layer is between the home stacks and the normal stacks.
final int layerForHomeAnimationLayer = layer++;
mTmpLayerForSplitScreenDividerAnchor = layer++;
mTmpLayerForAnimationLayer = layer++;
- layer = adjustRootTaskLayer(t, mTmpNormalStacks, layer, true /* normalStacks */);
+ layer = adjustRootTaskLayer(t, mTmpNormalRootTasks, layer, true /* normalStacks */);
// The boosted animation layer is between the normal stacks and the always on top
// stacks.
final int layerForBoostedAnimationLayer = layer++;
- adjustRootTaskLayer(t, mTmpAlwaysOnTopStacks, layer, false /* normalStacks */);
+ adjustRootTaskLayer(t, mTmpAlwaysOnTopRootTasks, layer, false /* normalStacks */);
t.setLayer(mHomeAppAnimationLayer, layerForHomeAnimationLayer);
t.setLayer(mAppAnimationLayer, mTmpLayerForAnimationLayer);
@@ -743,7 +745,7 @@ final class TaskDisplayArea extends DisplayArea<Task> {
t.setLayer(mBoostedAppAnimationLayer, layerForBoostedAnimationLayer);
}
- private int adjustNormalStackLayer(Task s, int layer) {
+ private int adjustNormalRootTaskLayer(Task s, int layer) {
if (s.inSplitScreenWindowingMode()) {
// The split screen divider anchor is located above the split screen window.
mTmpLayerForSplitScreenDividerAnchor = layer++;
@@ -773,7 +775,7 @@ final class TaskDisplayArea extends DisplayArea<Task> {
if (!stack.needsZBoost()) {
stack.assignLayer(t, startLayer++);
if (normalStacks) {
- startLayer = adjustNormalStackLayer(stack, startLayer);
+ startLayer = adjustNormalRootTaskLayer(stack, startLayer);
}
} else {
mTmpNeedsZBoostIndexes.add(i);
@@ -785,7 +787,7 @@ final class TaskDisplayArea extends DisplayArea<Task> {
final Task stack = stacks.get(mTmpNeedsZBoostIndexes.get(i));
stack.assignLayer(t, startLayer++);
if (normalStacks) {
- startLayer = adjustNormalStackLayer(stack, startLayer);
+ startLayer = adjustNormalRootTaskLayer(stack, startLayer);
}
}
return startLayer;
@@ -849,22 +851,22 @@ final class TaskDisplayArea extends DisplayArea<Task> {
}
}
- void onStackRemoved(Task stack) {
+ void onRootTaskRemoved(Task rootTask) {
if (ActivityTaskManagerDebugConfig.DEBUG_ROOT_TASK) {
- Slog.v(TAG_ROOT_TASK, "removeStack: detaching " + stack + " from displayId="
+ Slog.v(TAG_ROOT_TASK, "removeStack: detaching " + rootTask + " from displayId="
+ mDisplayContent.mDisplayId);
}
- if (mPreferredTopFocusableStack == stack) {
- mPreferredTopFocusableStack = null;
+ if (mPreferredTopFocusableRootTask == rootTask) {
+ mPreferredTopFocusableRootTask = null;
}
mDisplayContent.releaseSelfIfNeeded();
- onStackOrderChanged(stack);
+ onRootTaskOrderChanged(rootTask);
}
- void resetPreferredTopFocusableStackIfBelow(Task task) {
- if (mPreferredTopFocusableStack != null
- && mPreferredTopFocusableStack.compareTo(task) < 0) {
- mPreferredTopFocusableStack = null;
+ void resetPreferredTopFocusableRootTaskIfBelow(Task task) {
+ if (mPreferredTopFocusableRootTask != null
+ && mPreferredTopFocusableRootTask.compareTo(task) < 0) {
+ mPreferredTopFocusableRootTask = null;
}
}
@@ -894,9 +896,9 @@ final class TaskDisplayArea extends DisplayArea<Task> {
}
}
- Task getStack(int rootTaskId) {
- for (int i = getStackCount() - 1; i >= 0; --i) {
- final Task stack = getStackAt(i);
+ Task getRootTask(int rootTaskId) {
+ for (int i = getRootTaskCount() - 1; i >= 0; --i) {
+ final Task stack = getRootTaskAt(i);
if (stack.getRootTaskId() == rootTaskId) {
return stack;
}
@@ -908,10 +910,10 @@ final class TaskDisplayArea extends DisplayArea<Task> {
* Returns an existing stack compatible with the windowing mode and activity type or creates one
* if a compatible stack doesn't exist.
*
- * @see #getOrCreateStack(int, int, boolean, Intent, Task)
+ * @see #getOrCreateRootTask(int, int, boolean, Intent, Task)
*/
- Task getOrCreateStack(int windowingMode, int activityType, boolean onTop) {
- return getOrCreateStack(windowingMode, activityType, onTop, null /* intent */,
+ Task getOrCreateRootTask(int windowingMode, int activityType, boolean onTop) {
+ return getOrCreateRootTask(windowingMode, activityType, onTop, null /* intent */,
null /* candidateTask */);
}
@@ -921,17 +923,17 @@ final class TaskDisplayArea extends DisplayArea<Task> {
* For one level task, the candidate task would be reused to also be the root task or create
* a new root task if no candidate task.
*
- * @see #getStack(int, int)
- * @see #createStack(int, int, boolean)
+ * @see #getRootTask(int, int)
+ * @see #createRootTask(int, int, boolean)
*/
- Task getOrCreateStack(int windowingMode, int activityType, boolean onTop,
+ Task getOrCreateRootTask(int windowingMode, int activityType, boolean onTop,
Intent intent, Task candidateTask) {
// Need to pass in a determined windowing mode to see if a new stack should be created,
// so use its parent's windowing mode if it is undefined.
- if (!alwaysCreateStack(
+ if (!alwaysCreateRootTask(
windowingMode != WINDOWING_MODE_UNDEFINED ? windowingMode : getWindowingMode(),
activityType)) {
- Task stack = getStack(windowingMode, activityType);
+ Task stack = getRootTask(windowingMode, activityType);
if (stack != null) {
return stack;
}
@@ -959,7 +961,7 @@ final class TaskDisplayArea extends DisplayArea<Task> {
}
return stack;
}
- return createStack(windowingMode, activityType, onTop, null /*info*/, intent,
+ return createRootTask(windowingMode, activityType, onTop, null /*info*/, intent,
false /* createdByOrganizer */);
}
@@ -967,9 +969,9 @@ final class TaskDisplayArea extends DisplayArea<Task> {
* Returns an existing stack compatible with the input params or creates one
* if a compatible stack doesn't exist.
*
- * @see #getOrCreateStack(int, int, boolean)
+ * @see #getOrCreateRootTask(int, int, boolean)
*/
- Task getOrCreateStack(@Nullable ActivityRecord r,
+ Task getOrCreateRootTask(@Nullable ActivityRecord r,
@Nullable ActivityOptions options, @Nullable Task candidateTask, int activityType,
boolean onTop) {
// First preference is the windowing mode in the activity options if set.
@@ -979,24 +981,24 @@ final class TaskDisplayArea extends DisplayArea<Task> {
// UNDEFINED windowing mode is a valid result and means that the new stack will inherit
// it's display's windowing mode.
windowingMode = validateWindowingMode(windowingMode, r, candidateTask, activityType);
- return getOrCreateStack(windowingMode, activityType, onTop, null /* intent */,
+ return getOrCreateRootTask(windowingMode, activityType, onTop, null /* intent */,
candidateTask);
}
@VisibleForTesting
- int getNextStackId() {
+ int getNextRootTaskId() {
return mAtmService.mTaskSupervisor.getNextTaskIdForUser();
}
- Task createStack(int windowingMode, int activityType, boolean onTop) {
- return createStack(windowingMode, activityType, onTop, null /* info */, null /* intent */,
- false /* createdByOrganizer */);
+ Task createRootTask(int windowingMode, int activityType, boolean onTop) {
+ return createRootTask(windowingMode, activityType, onTop, null /* info */,
+ null /* intent */, false /* createdByOrganizer */);
}
- Task createStack(int windowingMode, int activityType, boolean onTop, ActivityInfo info,
+ Task createRootTask(int windowingMode, int activityType, boolean onTop, ActivityInfo info,
Intent intent, boolean createdByOrganizer) {
- return createStack(windowingMode, activityType, onTop, null /* info */, null /* intent */,
- false /* createdByOrganizer */ , false /* deferTaskAppear */,
+ return createRootTask(windowingMode, activityType, onTop, null /* info */,
+ null /* intent */, false /* createdByOrganizer */, false /* deferTaskAppear */,
null /* launchCookie */);
}
@@ -1022,7 +1024,7 @@ final class TaskDisplayArea extends DisplayArea<Task> {
* creating.
* @return The newly created stack.
*/
- Task createStack(int windowingMode, int activityType, boolean onTop, ActivityInfo info,
+ Task createRootTask(int windowingMode, int activityType, boolean onTop, ActivityInfo info,
Intent intent, boolean createdByOrganizer, boolean deferTaskAppear,
IBinder launchCookie) {
if (activityType == ACTIVITY_TYPE_UNDEFINED && !createdByOrganizer) {
@@ -1034,7 +1036,7 @@ final class TaskDisplayArea extends DisplayArea<Task> {
if (activityType != ACTIVITY_TYPE_STANDARD && activityType != ACTIVITY_TYPE_UNDEFINED) {
// For now there can be only one stack of a particular non-standard activity type on a
// display. So, get that ignoring whatever windowing mode it is currently in.
- Task stack = getStack(WINDOWING_MODE_UNDEFINED, activityType);
+ Task stack = getRootTask(WINDOWING_MODE_UNDEFINED, activityType);
if (stack != null) {
throw new IllegalArgumentException("Stack=" + stack + " of activityType="
+ activityType + " already on display=" + this + ". Can't have multiple.");
@@ -1054,8 +1056,8 @@ final class TaskDisplayArea extends DisplayArea<Task> {
getRootPinnedTask().dismissPip();
}
- final int stackId = getNextStackId();
- return createStackUnchecked(windowingMode, activityType, stackId, onTop, info, intent,
+ final int stackId = getNextRootTaskId();
+ return createRootTaskUnchecked(windowingMode, activityType, stackId, onTop, info, intent,
createdByOrganizer, deferTaskAppear, launchCookie);
}
@@ -1065,15 +1067,15 @@ final class TaskDisplayArea extends DisplayArea<Task> {
// Only split-screen windowing modes can do this currently...
return null;
}
- for (int i = getStackCount() - 1; i >= 0; --i) {
- final Task t = getStackAt(i);
+ for (int i = getRootTaskCount() - 1; i >= 0; --i) {
+ final Task t = getRootTaskAt(i);
if (!t.mCreatedByOrganizer || t.getRequestedOverrideWindowingMode() != windowingMode) {
continue;
}
// If not already set, pick a launch root which is not the one we are launching into.
if (mLaunchRootTask == null) {
- for (int j = 0, n = getStackCount(); j < n; ++j) {
- final Task tt = getStackAt(j);
+ for (int j = 0, n = getRootTaskCount(); j < n; ++j) {
+ final Task tt = getRootTaskAt(j);
if (tt.mCreatedByOrganizer && tt != t) {
mLaunchRootTask = tt;
break;
@@ -1086,7 +1088,7 @@ final class TaskDisplayArea extends DisplayArea<Task> {
}
@VisibleForTesting
- Task createStackUnchecked(int windowingMode, int activityType, int stackId, boolean onTop,
+ Task createRootTaskUnchecked(int windowingMode, int activityType, int stackId, boolean onTop,
ActivityInfo info, Intent intent, boolean createdByOrganizer, boolean deferTaskAppear,
IBinder launchCookie) {
if (windowingMode == WINDOWING_MODE_PINNED && activityType != ACTIVITY_TYPE_STANDARD) {
@@ -1123,13 +1125,13 @@ final class TaskDisplayArea extends DisplayArea<Task> {
* Get the preferred focusable stack in priority. If the preferred stack does not exist, find a
* focusable and visible stack from the top of stacks in this display.
*/
- Task getFocusedStack() {
- if (mPreferredTopFocusableStack != null) {
- return mPreferredTopFocusableStack;
+ Task getFocusedRootTask() {
+ if (mPreferredTopFocusableRootTask != null) {
+ return mPreferredTopFocusableRootTask;
}
- for (int i = getStackCount() - 1; i >= 0; --i) {
- final Task stack = getStackAt(i);
+ for (int i = getRootTaskCount() - 1; i >= 0; --i) {
+ final Task stack = getRootTaskAt(i);
if (stack.isFocusableAndVisible()) {
return stack;
}
@@ -1138,22 +1140,22 @@ final class TaskDisplayArea extends DisplayArea<Task> {
return null;
}
- Task getNextFocusableStack(Task currentFocus, boolean ignoreCurrent) {
+ Task getNextFocusableRootTask(Task currentFocus, boolean ignoreCurrent) {
final int currentWindowingMode = currentFocus != null
? currentFocus.getWindowingMode() : WINDOWING_MODE_UNDEFINED;
Task candidate = null;
- for (int i = getStackCount() - 1; i >= 0; --i) {
- final Task stack = getStackAt(i);
- if (ignoreCurrent && stack == currentFocus) {
+ for (int i = getRootTaskCount() - 1; i >= 0; --i) {
+ final Task rootTask = getRootTaskAt(i);
+ if (ignoreCurrent && rootTask == currentFocus) {
continue;
}
- if (!stack.isFocusableAndVisible()) {
+ if (!rootTask.isFocusableAndVisible()) {
continue;
}
if (currentWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY
- && candidate == null && stack.inSplitScreenPrimaryWindowingMode()) {
+ && candidate == null && rootTask.inSplitScreenPrimaryWindowingMode()) {
// If the currently focused stack is in split-screen secondary we save off the
// top primary split-screen stack as a candidate for focus because we might
// prefer focus to move to an other stack to avoid primary split-screen stack
@@ -1161,20 +1163,20 @@ final class TaskDisplayArea extends DisplayArea<Task> {
// than the next split-screen stack. Assistant stack, I am looking at you...
// We only move the focus to the primary-split screen stack if there isn't a
// better alternative.
- candidate = stack;
+ candidate = rootTask;
continue;
}
- if (candidate != null && stack.inSplitScreenSecondaryWindowingMode()) {
+ if (candidate != null && rootTask.inSplitScreenSecondaryWindowingMode()) {
// Use the candidate stack since we are now at the secondary split-screen.
return candidate;
}
- return stack;
+ return rootTask;
}
return candidate;
}
ActivityRecord getFocusedActivity() {
- final Task focusedStack = getFocusedStack();
+ final Task focusedStack = getFocusedRootTask();
if (focusedStack == null) {
return null;
}
@@ -1194,8 +1196,8 @@ final class TaskDisplayArea extends DisplayArea<Task> {
return resumedActivity;
}
- Task getLastFocusedStack() {
- return mLastFocusedStack;
+ Task getLastFocusedRootTask() {
+ return mLastFocusedRootTask;
}
void updateLastFocusedRootTask(Task prevFocusedTask, String updateLastFocusedTaskReason) {
@@ -1203,7 +1205,7 @@ final class TaskDisplayArea extends DisplayArea<Task> {
return;
}
- final Task currentFocusedTask = getFocusedStack();
+ final Task currentFocusedTask = getFocusedRootTask();
if (currentFocusedTask == prevFocusedTask) {
return;
}
@@ -1214,27 +1216,27 @@ final class TaskDisplayArea extends DisplayArea<Task> {
currentFocusedTask.mLastPausedActivity = null;
}
- mLastFocusedStack = prevFocusedTask;
+ mLastFocusedRootTask = prevFocusedTask;
EventLogTags.writeWmFocusedStack(mRootWindowContainer.mCurrentUser,
mDisplayContent.mDisplayId,
currentFocusedTask == null ? -1 : currentFocusedTask.getRootTaskId(),
- mLastFocusedStack == null ? -1 : mLastFocusedStack.getRootTaskId(),
+ mLastFocusedRootTask == null ? -1 : mLastFocusedRootTask.getRootTaskId(),
updateLastFocusedTaskReason);
}
boolean allResumedActivitiesComplete() {
- for (int stackNdx = getStackCount() - 1; stackNdx >= 0; --stackNdx) {
- final ActivityRecord r = getStackAt(stackNdx).getResumedActivity();
+ for (int stackNdx = getRootTaskCount() - 1; stackNdx >= 0; --stackNdx) {
+ final ActivityRecord r = getRootTaskAt(stackNdx).getResumedActivity();
if (r != null && !r.isState(RESUMED)) {
return false;
}
}
- final Task currentFocusedStack = getFocusedStack();
+ final Task currentFocusedStack = getFocusedRootTask();
if (ActivityTaskManagerDebugConfig.DEBUG_ROOT_TASK) {
Slog.d(TAG_ROOT_TASK, "allResumedActivitiesComplete: mLastFocusedStack changing from="
- + mLastFocusedStack + " to=" + currentFocusedStack);
+ + mLastFocusedRootTask + " to=" + currentFocusedStack);
}
- mLastFocusedStack = currentFocusedStack;
+ mLastFocusedRootTask = currentFocusedStack;
return true;
}
@@ -1249,10 +1251,10 @@ final class TaskDisplayArea extends DisplayArea<Task> {
* @param resuming The resuming activity.
* @return {@code true} if any activity was paused as a result of this call.
*/
- boolean pauseBackStacks(boolean userLeaving, ActivityRecord resuming) {
+ boolean pauseBackTasks(boolean userLeaving, ActivityRecord resuming) {
boolean someActivityPaused = false;
- for (int stackNdx = getStackCount() - 1; stackNdx >= 0; --stackNdx) {
- final Task stack = getStackAt(stackNdx);
+ for (int stackNdx = getRootTaskCount() - 1; stackNdx >= 0; --stackNdx) {
+ final Task stack = getRootTaskAt(stackNdx);
final ActivityRecord resumedActivity = stack.getResumedActivity();
if (resumedActivity != null
&& (stack.getVisibility(resuming) != TASK_VISIBILITY_VISIBLE
@@ -1272,8 +1274,8 @@ final class TaskDisplayArea extends DisplayArea<Task> {
void findTaskLocked(final ActivityRecord r, final boolean isPreferredDisplayArea,
RootWindowContainer.FindTaskResult result) {
mTmpFindTaskResult.clear();
- for (int stackNdx = getStackCount() - 1; stackNdx >= 0; --stackNdx) {
- final Task stack = getStackAt(stackNdx);
+ for (int stackNdx = getRootTaskCount() - 1; stackNdx >= 0; --stackNdx) {
+ final Task stack = getRootTaskAt(stackNdx);
if (!r.hasCompatibleActivityType(stack) && stack.isLeafTask()) {
ProtoLog.d(WM_DEBUG_TASKS, "Skipping stack: (mismatch activity/stack) "
+ "%s", stack);
@@ -1367,7 +1369,7 @@ final class TaskDisplayArea extends DisplayArea<Task> {
// The focused task could be a non-resizeable fullscreen root task that is on top of the
// other split-screen tasks, therefore had to dismiss split-screen, make sure the current
// focused root task can still be on top after dismissal
- final Task rootTask = getFocusedStack();
+ final Task rootTask = getFocusedRootTask();
final Task toTop =
rootTask != null && !rootTask.inSplitScreenWindowingMode() ? rootTask : null;
onSplitScreenModeDismissed(toTop);
@@ -1380,9 +1382,9 @@ final class TaskDisplayArea extends DisplayArea<Task> {
moveSplitScreenTasksToFullScreen();
} finally {
final Task topFullscreenStack = toTop != null
- ? toTop : getTopStackInWindowingMode(WINDOWING_MODE_FULLSCREEN);
+ ? toTop : getTopRootTaskInWindowingMode(WINDOWING_MODE_FULLSCREEN);
final Task homeStack = getOrCreateRootHomeTask();
- if (homeStack != null && ((topFullscreenStack != null && !isTopStack(homeStack))
+ if (homeStack != null && ((topFullscreenStack != null && !isTopRootTask(homeStack))
|| toTop != null)) {
// Whenever split-screen is dismissed we want the home stack directly behind the
// current top fullscreen stack so it shows up when the top stack is finished.
@@ -1556,8 +1558,8 @@ final class TaskDisplayArea extends DisplayArea<Task> {
return windowingMode;
}
- boolean isTopStack(Task stack) {
- return stack == getTopStack();
+ boolean isTopRootTask(Task stack) {
+ return stack == getTopRootTask();
}
ActivityRecord topRunningActivity() {
@@ -1575,15 +1577,15 @@ final class TaskDisplayArea extends DisplayArea<Task> {
*/
ActivityRecord topRunningActivity(boolean considerKeyguardState) {
ActivityRecord topRunning = null;
- final Task focusedStack = getFocusedStack();
+ final Task focusedStack = getFocusedRootTask();
if (focusedStack != null) {
topRunning = focusedStack.topRunningActivity();
}
// Look in other focusable stacks.
if (topRunning == null) {
- for (int i = getStackCount() - 1; i >= 0; --i) {
- final Task stack = getStackAt(i);
+ for (int i = getRootTaskCount() - 1; i >= 0; --i) {
+ final Task stack = getRootTaskAt(i);
// Only consider focusable stacks other than the current focused one.
if (stack == focusedStack || !stack.isTopActivityFocusable()) {
continue;
@@ -1607,13 +1609,11 @@ final class TaskDisplayArea extends DisplayArea<Task> {
return topRunning;
}
- // TODO (b/157876447): switch to Task related name
- protected int getStackCount() {
+ protected int getRootTaskCount() {
return mChildren.size();
}
- // TODO (b/157876447): switch to Task related name
- protected Task getStackAt(int index) {
+ protected Task getRootTaskAt(int index) {
return mChildren.get(index);
}
@@ -1633,7 +1633,7 @@ final class TaskDisplayArea extends DisplayArea<Task> {
Task getOrCreateRootHomeTask(boolean onTop) {
Task homeTask = getRootHomeTask();
if (homeTask == null && mDisplayContent.supportsSystemDecorations()) {
- homeTask = createStack(WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_HOME, onTop);
+ homeTask = createRootTask(WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_HOME, onTop);
}
return homeTask;
}
@@ -1647,14 +1647,14 @@ final class TaskDisplayArea extends DisplayArea<Task> {
* Returns the topmost stack on the display that is compatible with the input windowing mode.
* Null is no compatible stack on the display.
*/
- Task getTopStackInWindowingMode(int windowingMode) {
- return getStack(windowingMode, ACTIVITY_TYPE_UNDEFINED);
+ Task getTopRootTaskInWindowingMode(int windowingMode) {
+ return getRootTask(windowingMode, ACTIVITY_TYPE_UNDEFINED);
}
- void moveHomeStackToFront(String reason) {
- final Task homeStack = getOrCreateRootHomeTask();
- if (homeStack != null) {
- homeStack.moveToFront(reason);
+ void moveHomeRootTaskToFront(String reason) {
+ final Task homeRootTask = getOrCreateRootHomeTask();
+ if (homeRootTask != null) {
+ homeRootTask.moveToFront(reason);
}
}
@@ -1665,7 +1665,7 @@ final class TaskDisplayArea extends DisplayArea<Task> {
void moveHomeActivityToTop(String reason) {
final ActivityRecord top = getHomeActivity();
if (top == null) {
- moveHomeStackToFront(reason);
+ moveHomeRootTaskToFront(reason);
return;
}
top.moveFocusableActivityToTop(reason);
@@ -1697,25 +1697,27 @@ final class TaskDisplayArea extends DisplayArea<Task> {
/**
* Adjusts the {@param stack} behind the last visible stack in the display if necessary.
- * Generally used in conjunction with {@link #moveStackBehindStack}.
+ * Generally used in conjunction with {@link #moveRootTaskBehindRootTask}.
*/
// TODO(b/151575894): Remove special stack movement methods.
- void moveStackBehindBottomMostVisibleStack(Task stack) {
- if (stack.shouldBeVisible(null)) {
+ void moveRootTaskBehindBottomMostVisibleRootTask(Task rootTask) {
+ if (rootTask.shouldBeVisible(null)) {
// Skip if the stack is already visible
return;
}
// Move the stack to the bottom to not affect the following visibility checks
- stack.getParent().positionChildAt(POSITION_BOTTOM, stack, false /* includingParents */);
+ rootTask.getParent().positionChildAt(POSITION_BOTTOM, rootTask,
+ false /* includingParents */);
// Find the next position where the stack should be placed
- final boolean isRootTask = stack.isRootTask();
- final int numStacks = isRootTask ? getStackCount() : stack.getParent().getChildCount();
- for (int stackNdx = 0; stackNdx < numStacks; stackNdx++) {
- final Task s = isRootTask ? getStackAt(stackNdx)
- : (Task) stack.getParent().getChildAt(stackNdx);
- if (s == stack) {
+ final boolean isRootTask = rootTask.isRootTask();
+ final int numRootTasks =
+ isRootTask ? getRootTaskCount() : rootTask.getParent().getChildCount();
+ for (int rootTaskNdx = 0; rootTaskNdx < numRootTasks; rootTaskNdx++) {
+ final Task s = isRootTask ? getRootTaskAt(rootTaskNdx)
+ : (Task) rootTask.getParent().getChildAt(rootTaskNdx);
+ if (s == rootTask) {
continue;
}
final int winMode = s.getWindowingMode();
@@ -1723,8 +1725,9 @@ final class TaskDisplayArea extends DisplayArea<Task> {
|| winMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
if (s.shouldBeVisible(null) && isValidWindowingMode) {
// Move the provided stack to behind this stack
- final int position = Math.max(0, stackNdx - 1);
- stack.getParent().positionChildAt(position, stack, false /*includingParents */);
+ final int position = Math.max(0, rootTaskNdx - 1);
+ rootTask.getParent().positionChildAt(position, rootTask,
+ false /*includingParents */);
break;
}
}
@@ -1733,15 +1736,16 @@ final class TaskDisplayArea extends DisplayArea<Task> {
/**
* Moves the {@param stack} behind the given {@param behindStack} if possible. If
* {@param behindStack} is not currently in the display, then then the stack is moved to the
- * back. Generally used in conjunction with {@link #moveStackBehindBottomMostVisibleStack}.
+ * back. Generally used in conjunction with
+ * {@link #moveRootTaskBehindBottomMostVisibleRootTask}.
*/
- void moveStackBehindStack(Task stack, Task behindStack) {
- if (behindStack == null || behindStack == stack) {
+ void moveRootTaskBehindRootTask(Task rootTask, Task behindRootTask) {
+ if (behindRootTask == null || behindRootTask == rootTask) {
return;
}
- final WindowContainer parent = stack.getParent();
- if (parent == null || parent != behindStack.getParent()) {
+ final WindowContainer parent = rootTask.getParent();
+ if (parent == null || parent != behindRootTask.getParent()) {
return;
}
@@ -1749,12 +1753,12 @@ final class TaskDisplayArea extends DisplayArea<Task> {
// list, so we need to adjust the insertion index to account for the removed index
// TODO: Remove this logic when WindowContainer.positionChildAt() is updated to adjust the
// position internally
- final int stackIndex = parent.mChildren.indexOf(stack);
- final int behindStackIndex = parent.mChildren.indexOf(behindStack);
+ final int stackIndex = parent.mChildren.indexOf(rootTask);
+ final int behindStackIndex = parent.mChildren.indexOf(behindRootTask);
final int insertIndex = stackIndex <= behindStackIndex
? behindStackIndex - 1 : behindStackIndex;
final int position = Math.max(0, insertIndex);
- parent.positionChildAt(position, stack, false /* includingParents */);
+ parent.positionChildAt(position, rootTask, false /* includingParents */);
}
boolean hasPinnedTask() {
@@ -1765,20 +1769,20 @@ final class TaskDisplayArea extends DisplayArea<Task> {
* @return the stack currently above the {@param stack}. Can be null if the {@param stack} is
* already top-most.
*/
- static Task getStackAbove(Task stack) {
- final WindowContainer wc = stack.getParent();
- final int index = wc.mChildren.indexOf(stack) + 1;
+ static Task getRootTaskAbove(Task rootTask) {
+ final WindowContainer wc = rootTask.getParent();
+ final int index = wc.mChildren.indexOf(rootTask) + 1;
return (index < wc.mChildren.size()) ? (Task) wc.mChildren.get(index) : null;
}
/** Returns true if the stack in the windowing mode is visible. */
- boolean isStackVisible(int windowingMode) {
- final Task stack = getTopStackInWindowingMode(windowingMode);
- return stack != null && stack.isVisible();
+ boolean isRootTaskVisible(int windowingMode) {
+ final Task rootTask = getTopRootTaskInWindowingMode(windowingMode);
+ return rootTask != null && rootTask.isVisible();
}
- void removeStack(Task stack) {
- removeChild(stack);
+ void removeRootTask(Task rootTask) {
+ removeChild(rootTask);
}
int getDisplayId() {
@@ -1794,27 +1798,27 @@ final class TaskDisplayArea extends DisplayArea<Task> {
* only used by the {@link RecentsAnimation} to determine whether to interrupt and cancel the
* current animation when the system state changes.
*/
- void registerStackOrderChangedListener(OnStackOrderChangedListener listener) {
- if (!mStackOrderChangedCallbacks.contains(listener)) {
- mStackOrderChangedCallbacks.add(listener);
+ void registerRootTaskOrderChangedListener(OnRootTaskOrderChangedListener listener) {
+ if (!mRootTaskOrderChangedCallbacks.contains(listener)) {
+ mRootTaskOrderChangedCallbacks.add(listener);
}
}
/**
* Removes a previously registered stack order change listener.
*/
- void unregisterStackOrderChangedListener(OnStackOrderChangedListener listener) {
- mStackOrderChangedCallbacks.remove(listener);
+ void unregisterRootTaskOrderChangedListener(OnRootTaskOrderChangedListener listener) {
+ mRootTaskOrderChangedCallbacks.remove(listener);
}
/**
- * Notifies of a stack order change
+ * Notifies of a root task order change
*
- * @param stack The stack which triggered the order change
+ * @param rootTask The root task which triggered the order change
*/
- void onStackOrderChanged(Task stack) {
- for (int i = mStackOrderChangedCallbacks.size() - 1; i >= 0; i--) {
- mStackOrderChangedCallbacks.get(i).onStackOrderChanged(stack);
+ void onRootTaskOrderChanged(Task rootTask) {
+ for (int i = mRootTaskOrderChangedCallbacks.size() - 1; i >= 0; i--) {
+ mRootTaskOrderChangedCallbacks.get(i).onRootTaskOrderChanged(rootTask);
}
}
@@ -1826,16 +1830,16 @@ final class TaskDisplayArea extends DisplayArea<Task> {
/**
* Callback for when the order of the stacks in the display changes.
*/
- interface OnStackOrderChangedListener {
- void onStackOrderChanged(Task stack);
+ interface OnRootTaskOrderChangedListener {
+ void onRootTaskOrderChanged(Task rootTask);
}
void ensureActivitiesVisible(ActivityRecord starting, int configChanges,
boolean preserveWindows, boolean notifyClients, boolean userLeaving) {
mAtmService.mTaskSupervisor.beginActivityVisibilityUpdate();
try {
- for (int stackNdx = getStackCount() - 1; stackNdx >= 0; --stackNdx) {
- final Task stack = getStackAt(stackNdx);
+ for (int stackNdx = getRootTaskCount() - 1; stackNdx >= 0; --stackNdx) {
+ final Task stack = getRootTaskAt(stackNdx);
stack.ensureActivitiesVisible(starting, configChanges, preserveWindows,
notifyClients, userLeaving);
}
@@ -1857,7 +1861,7 @@ final class TaskDisplayArea extends DisplayArea<Task> {
* @return last reparented stack, or {@code null} if the stacks had to be destroyed.
*/
Task remove() {
- mPreferredTopFocusableStack = null;
+ mPreferredTopFocusableRootTask = null;
// TODO(b/153090332): Allow setting content removal mode per task display area
final boolean destroyContentOnRemoval = mDisplayContent.shouldDestroyContentOnRemove();
final TaskDisplayArea toDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea();
@@ -1869,13 +1873,13 @@ final class TaskDisplayArea extends DisplayArea<Task> {
// related WindowContainer will also be removed. So, we set display area as removed after
// reparenting stack finished.
// Keep the order from bottom to top.
- int numStacks = getStackCount();
+ int numStacks = getRootTaskCount();
final boolean splitScreenActivated = toDisplayArea.isSplitScreenModeActivated();
final Task rootStack = splitScreenActivated ? toDisplayArea
- .getTopStackInWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY) : null;
+ .getTopRootTaskInWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY) : null;
for (int stackNdx = 0; stackNdx < numStacks; stackNdx++) {
- final Task stack = getStackAt(stackNdx);
+ final Task stack = getRootTaskAt(stackNdx);
// Always finish non-standard type stacks and stacks created by a organizer.
// TODO: For stacks created by organizer, consider reparenting children tasks if the use
// case arises in the future.
@@ -1895,8 +1899,8 @@ final class TaskDisplayArea extends DisplayArea<Task> {
}
// Stacks may be removed from this display. Ensure each stack will be processed
// and the loop will end.
- stackNdx -= numStacks - getStackCount();
- numStacks = getStackCount();
+ stackNdx -= numStacks - getRootTaskCount();
+ numStacks = getRootTaskCount();
}
if (lastReparentedStack != null && splitScreenActivated) {
if (!lastReparentedStack.supportsSplitScreenWindowingMode()) {
@@ -1935,18 +1939,19 @@ final class TaskDisplayArea extends DisplayArea<Task> {
pw.println(prefix + "TaskDisplayArea " + getName());
final String doublePrefix = prefix + " ";
super.dump(pw, doublePrefix, dumpAll);
- if (mPreferredTopFocusableStack != null) {
- pw.println(doublePrefix + "mPreferredTopFocusableStack=" + mPreferredTopFocusableStack);
+ if (mPreferredTopFocusableRootTask != null) {
+ pw.println(doublePrefix + "mPreferredTopFocusableRootTask="
+ + mPreferredTopFocusableRootTask);
}
- if (mLastFocusedStack != null) {
- pw.println(doublePrefix + "mLastFocusedStack=" + mLastFocusedStack);
+ if (mLastFocusedRootTask != null) {
+ pw.println(doublePrefix + "mLastFocusedRootTask=" + mLastFocusedRootTask);
}
final String triplePrefix = doublePrefix + " ";
pw.println(doublePrefix + "Application tokens in top down Z order:");
- for (int stackNdx = getChildCount() - 1; stackNdx >= 0; --stackNdx) {
- final Task stack = getChildAt(stackNdx);
- pw.println(doublePrefix + "* " + stack);
- stack.dump(pw, triplePrefix, dumpAll);
+ for (int rootTaskNdx = getChildCount() - 1; rootTaskNdx >= 0; --rootTaskNdx) {
+ final Task rootTask = getChildAt(rootTaskNdx);
+ pw.println(doublePrefix + "* " + rootTask);
+ rootTask.dump(pw, triplePrefix, dumpAll);
}
}
}
diff --git a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
index 8b2fa52afd22..9d36b84431f3 100644
--- a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
+++ b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
@@ -796,9 +796,9 @@ class TaskLaunchParamsModifier implements LaunchParamsModifier {
@NonNull Rect inOutBounds) {
final List<Rect> taskBoundsToCheck = new ArrayList<>();
display.forAllTaskDisplayAreas(taskDisplayArea -> {
- int numStacks = taskDisplayArea.getStackCount();
+ int numStacks = taskDisplayArea.getRootTaskCount();
for (int sNdx = 0; sNdx < numStacks; ++sNdx) {
- final Task task = taskDisplayArea.getStackAt(sNdx);
+ final Task task = taskDisplayArea.getRootTaskAt(sNdx);
if (!task.inFreeformWindowingMode()) {
continue;
}
diff --git a/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java
index 009a7ef9e4f2..e635219bc6e5 100644
--- a/services/core/java/com/android/server/wm/TaskOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java
@@ -478,7 +478,7 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
// We want to defer the task appear signal until the task is fully created and attached to
// to the hierarchy so that the complete starting configuration is in the task info we send
// over to the organizer.
- final Task task = display.getDefaultTaskDisplayArea().createStack(windowingMode,
+ final Task task = display.getDefaultTaskDisplayArea().createRootTask(windowingMode,
ACTIVITY_TYPE_UNDEFINED, false /* onTop */, null /* info */, new Intent(),
true /* createdByOrganizer */, true /* deferTaskAppear */, launchCookie);
task.setDeferTaskAppear(false /* deferTaskAppear */);
@@ -688,8 +688,8 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
}
ArrayList<RunningTaskInfo> out = new ArrayList<>();
dc.forAllTaskDisplayAreas(taskDisplayArea -> {
- for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {
- final Task task = taskDisplayArea.getStackAt(sNdx);
+ for (int sNdx = taskDisplayArea.getRootTaskCount() - 1; sNdx >= 0; --sNdx) {
+ final Task task = taskDisplayArea.getRootTaskAt(sNdx);
if (activityTypes != null
&& !ArrayUtils.contains(activityTypes, task.getActivityType())) {
continue;
diff --git a/services/core/java/com/android/server/wm/TaskPersister.java b/services/core/java/com/android/server/wm/TaskPersister.java
index c976bc207061..855dd7e416b7 100644
--- a/services/core/java/com/android/server/wm/TaskPersister.java
+++ b/services/core/java/com/android/server/wm/TaskPersister.java
@@ -30,26 +30,28 @@ import android.util.AtomicFile;
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
import android.util.Xml;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.XmlUtils;
import libcore.io.IoUtils;
import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlSerializer;
import java.io.BufferedReader;
import java.io.BufferedWriter;
+import java.io.ByteArrayOutputStream;
import java.io.File;
+import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
-import java.io.StringWriter;
+import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
@@ -305,12 +307,9 @@ public class TaskPersister implements PersisterQueue.Listener {
continue;
}
- BufferedReader reader = null;
boolean deleteFile = false;
- try {
- reader = new BufferedReader(new FileReader(taskFile));
- final XmlPullParser in = Xml.newPullParser();
- in.setInput(reader);
+ try (InputStream is = new FileInputStream(taskFile)) {
+ final TypedXmlPullParser in = Xml.resolvePullParser(is);
int event;
while (((event = in.next()) != XmlPullParser.END_DOCUMENT) &&
@@ -360,7 +359,6 @@ public class TaskPersister implements PersisterQueue.Listener {
Slog.e(TAG, "Failing file: " + fileToString(taskFile));
deleteFile = true;
} finally {
- IoUtils.closeQuietly(reader);
if (deleteFile) {
if (DEBUG) Slog.d(TAG, "Deleting file=" + taskFile.getName());
taskFile.delete();
@@ -513,11 +511,10 @@ public class TaskPersister implements PersisterQueue.Listener {
mService = service;
}
- private StringWriter saveToXml(Task task) throws Exception {
+ private byte[] saveToXml(Task task) throws Exception {
if (DEBUG) Slog.d(TAG, "saveToXml: task=" + task);
- final XmlSerializer xmlSerializer = new FastXmlSerializer();
- StringWriter stringWriter = new StringWriter();
- xmlSerializer.setOutput(stringWriter);
+ final ByteArrayOutputStream os = new ByteArrayOutputStream();
+ final TypedXmlSerializer xmlSerializer = Xml.resolveSerializer(os);
if (DEBUG) {
xmlSerializer.setFeature(
@@ -534,13 +531,13 @@ public class TaskPersister implements PersisterQueue.Listener {
xmlSerializer.endDocument();
xmlSerializer.flush();
- return stringWriter;
+ return os.toByteArray();
}
@Override
public void process() {
// Write out one task.
- StringWriter stringWriter = null;
+ byte[] data = null;
Task task = mTask;
if (DEBUG) Slog.d(TAG, "Writing task=" + task);
synchronized (mService.mGlobalLock) {
@@ -548,12 +545,12 @@ public class TaskPersister implements PersisterQueue.Listener {
// Still there.
try {
if (DEBUG) Slog.d(TAG, "Saving task=" + task);
- stringWriter = saveToXml(task);
+ data = saveToXml(task);
} catch (Exception e) {
}
}
}
- if (stringWriter != null) {
+ if (data != null) {
// Write out xml file while not holding mService lock.
FileOutputStream file = null;
AtomicFile atomicFile = null;
@@ -567,8 +564,7 @@ public class TaskPersister implements PersisterQueue.Listener {
atomicFile = new AtomicFile(new File(userTasksDir,
String.valueOf(task.mTaskId) + TASK_FILENAME_SUFFIX));
file = atomicFile.startWrite();
- file.write(stringWriter.toString().getBytes());
- file.write('\n');
+ file.write(data);
atomicFile.finishWrite(file);
} catch (IOException e) {
if (file != null) {
diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java
index 7d61c1973a2a..7809cbc2a167 100644
--- a/services/core/java/com/android/server/wm/WallpaperController.java
+++ b/services/core/java/com/android/server/wm/WallpaperController.java
@@ -502,7 +502,8 @@ class WallpaperController {
private void findWallpaperTarget() {
mFindResults.reset();
- if (mDisplayContent.getDefaultTaskDisplayArea().isStackVisible(WINDOWING_MODE_FREEFORM)) {
+ if (mDisplayContent.getDefaultTaskDisplayArea()
+ .isRootTaskVisible(WINDOWING_MODE_FREEFORM)) {
// In freeform mode we set the wallpaper as its own target, so we don't need an
// additional window to make it visible.
mFindResults.setUseTopWallpaperAsTarget(true);
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index a1bb89d26f2f..cf6468d66b57 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -1139,18 +1139,15 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
* Called when this container or one of its descendants changed its requested orientation, and
* wants this container to handle it or pass it to its parent.
*
- * @param freezeDisplayToken freeze this app window token if display needs to freeze
* @param requestingContainer the container which orientation request has changed
* @return {@code true} if handled; {@code false} otherwise.
*/
- boolean onDescendantOrientationChanged(@Nullable IBinder freezeDisplayToken,
- @Nullable WindowContainer requestingContainer) {
+ boolean onDescendantOrientationChanged(@Nullable WindowContainer requestingContainer) {
final WindowContainer parent = getParent();
if (parent == null) {
return false;
}
- return parent.onDescendantOrientationChanged(freezeDisplayToken,
- requestingContainer);
+ return parent.onDescendantOrientationChanged(requestingContainer);
}
/**
@@ -1224,14 +1221,13 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
}
/**
- * Calls {@link #setOrientation(int, IBinder, ActivityRecord)} with {@code null} to the last 2
+ * Calls {@link #setOrientation(int, IBinder, WindowContainer)} with {@code null} to the last 2
* parameters.
*
* @param orientation the specified orientation.
*/
void setOrientation(int orientation) {
- setOrientation(orientation, null /* freezeDisplayToken */,
- null /* ActivityRecord */);
+ setOrientation(orientation, null /* requestingContainer */);
}
/**
@@ -1240,14 +1236,10 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
*
* @param orientation the specified orientation. Needs to be one of {@link
* android.content.pm.ActivityInfo.ScreenOrientation}.
- * @param freezeDisplayToken uses this token to freeze display if orientation change is not
- * done. Display will not be frozen if this is {@code null}, which
- * should only happen in tests.
* @param requestingContainer the container which orientation request has changed. Mostly used
* to ensure it gets correct configuration.
*/
- void setOrientation(int orientation, @Nullable IBinder freezeDisplayToken,
- @Nullable WindowContainer requestingContainer) {
+ void setOrientation(int orientation, @Nullable WindowContainer requestingContainer) {
if (mOrientation == orientation) {
return;
}
@@ -1259,7 +1251,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
// Resolve the requested orientation.
onConfigurationChanged(parent.getConfiguration());
}
- onDescendantOrientationChanged(freezeDisplayToken, requestingContainer);
+ onDescendantOrientationChanged(requestingContainer);
}
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerConstants.java b/services/core/java/com/android/server/wm/WindowManagerConstants.java
index b0c5dbc6cca3..a5ebf9ac74b9 100644
--- a/services/core/java/com/android/server/wm/WindowManagerConstants.java
+++ b/services/core/java/com/android/server/wm/WindowManagerConstants.java
@@ -23,7 +23,7 @@ import android.provider.AndroidDeviceConfig;
import android.provider.DeviceConfig;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.server.wm.utils.DeviceConfigInterface;
+import com.android.server.utils.DeviceConfigInterface;
import java.io.PrintWriter;
import java.util.Objects;
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 80b021650c83..d4efa8a7ab91 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -44,10 +44,11 @@ import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDO
import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_SIZECOMPAT_FREEFORM;
import static android.provider.Settings.Global.DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS;
import static android.provider.Settings.Global.DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES;
-import static android.provider.Settings.Global.DEVELOPMENT_IGNORE_VENDOR_DISPLAY_SETTINGS;
import static android.provider.Settings.Global.DEVELOPMENT_RENDER_SHADOWS_IN_COMPOSITOR;
+import static android.provider.Settings.Global.DEVELOPMENT_WM_DISPLAY_SETTINGS_PATH;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.INVALID_DISPLAY;
+import static android.view.WindowManager.DISPLAY_IME_POLICY_FALLBACK_DISPLAY;
import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
@@ -78,7 +79,6 @@ import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION;
import static android.view.WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
import static android.view.WindowManager.REMOVE_CONTENT_MODE_UNDEFINED;
-import static android.view.WindowManager.DISPLAY_IME_POLICY_FALLBACK_DISPLAY;
import static android.view.WindowManager.TRANSIT_NONE;
import static android.view.WindowManager.TRANSIT_RELAUNCH;
import static android.view.WindowManagerGlobal.ADD_OKAY;
@@ -199,6 +199,7 @@ import android.os.Trace;
import android.os.UserHandle;
import android.os.WorkSource;
import android.provider.Settings;
+import android.service.attestation.ImpressionToken;
import android.service.vr.IVrManager;
import android.service.vr.IVrStateCallbacks;
import android.sysprop.SurfaceFlingerProperties;
@@ -256,9 +257,9 @@ import android.view.View;
import android.view.WindowContentFrameStats;
import android.view.WindowInsets;
import android.view.WindowManager;
+import android.view.WindowManager.DisplayImePolicy;
import android.view.WindowManager.LayoutParams;
import android.view.WindowManager.RemoveContentMode;
-import android.view.WindowManager.DisplayImePolicy;
import android.view.WindowManagerGlobal;
import android.view.WindowManagerPolicyConstants.PointerEventListener;
import android.window.ClientWindowFrames;
@@ -288,8 +289,8 @@ import com.android.server.input.InputManagerService;
import com.android.server.policy.WindowManagerPolicy;
import com.android.server.policy.WindowManagerPolicy.ScreenOffListener;
import com.android.server.power.ShutdownThread;
+import com.android.server.utils.DeviceConfigInterface;
import com.android.server.utils.PriorityDump;
-import com.android.server.wm.utils.DeviceConfigInterface;
import java.io.BufferedWriter;
import java.io.DataInputStream;
@@ -767,6 +768,8 @@ public class WindowManagerService extends IWindowManager.Stub
final EmbeddedWindowController mEmbeddedWindowController;
final AnrController mAnrController;
+ private final ImpressionAttestationController mImpressionAttestationController;
+
@VisibleForTesting
final class SettingsObserver extends ContentObserver {
private final Uri mDisplayInversionEnabledUri =
@@ -793,8 +796,8 @@ public class WindowManagerService extends IWindowManager.Stub
DEVELOPMENT_ENABLE_SIZECOMPAT_FREEFORM);
private final Uri mRenderShadowsInCompositorUri = Settings.Global.getUriFor(
DEVELOPMENT_RENDER_SHADOWS_IN_COMPOSITOR);
- private final Uri mIgnoreVendorDisplaySettingsUri = Settings.Global.getUriFor(
- DEVELOPMENT_IGNORE_VENDOR_DISPLAY_SETTINGS);
+ private final Uri mDisplaySettingsPathUri = Settings.Global.getUriFor(
+ DEVELOPMENT_WM_DISPLAY_SETTINGS_PATH);
public SettingsObserver() {
super(new Handler());
@@ -819,7 +822,7 @@ public class WindowManagerService extends IWindowManager.Stub
UserHandle.USER_ALL);
resolver.registerContentObserver(mRenderShadowsInCompositorUri, false, this,
UserHandle.USER_ALL);
- resolver.registerContentObserver(mIgnoreVendorDisplaySettingsUri, false, this,
+ resolver.registerContentObserver(mDisplaySettingsPathUri, false, this,
UserHandle.USER_ALL);
}
@@ -864,8 +867,8 @@ public class WindowManagerService extends IWindowManager.Stub
return;
}
- if (mIgnoreVendorDisplaySettingsUri.equals(uri)) {
- updateIgnoreVendorDisplaySettings();
+ if (mDisplaySettingsPathUri.equals(uri)) {
+ updateDisplaySettingsLocation();
return;
}
@@ -959,12 +962,12 @@ public class WindowManagerService extends IWindowManager.Stub
mAtmService.mSizeCompatFreeform = sizeCompatFreeform;
}
- void updateIgnoreVendorDisplaySettings() {
+ void updateDisplaySettingsLocation() {
final ContentResolver resolver = mContext.getContentResolver();
- final boolean ignoreVendorSettings = Settings.Global.getInt(resolver,
- DEVELOPMENT_IGNORE_VENDOR_DISPLAY_SETTINGS, 0) != 0;
+ final String filePath = Settings.Global.getString(resolver,
+ DEVELOPMENT_WM_DISPLAY_SETTINGS_PATH);
synchronized (mGlobalLock) {
- mDisplayWindowSettingsProvider.setVendorSettingsIgnored(ignoreVendorSettings);
+ mDisplayWindowSettingsProvider.setBaseSettingsFilePath(filePath);
mRoot.forAllDisplays(display -> {
mDisplayWindowSettings.applySettingsToDisplayLocked(display);
display.reconfigureDisplayLocked();
@@ -1327,10 +1330,12 @@ public class WindowManagerService extends IWindowManager.Stub
mForceDesktopModeOnExternalDisplays = Settings.Global.getInt(resolver,
DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS, 0) != 0;
- final boolean ignoreVendorDisplaySettings = Settings.Global.getInt(resolver,
- DEVELOPMENT_IGNORE_VENDOR_DISPLAY_SETTINGS, 0) != 0;
+ final String displaySettingsPath = Settings.Global.getString(resolver,
+ DEVELOPMENT_WM_DISPLAY_SETTINGS_PATH);
mDisplayWindowSettingsProvider = new DisplayWindowSettingsProvider();
- mDisplayWindowSettingsProvider.setVendorSettingsIgnored(ignoreVendorDisplaySettings);
+ if (displaySettingsPath != null) {
+ mDisplayWindowSettingsProvider.setBaseSettingsFilePath(displaySettingsPath);
+ }
mDisplayWindowSettings = new DisplayWindowSettings(this, mDisplayWindowSettingsProvider);
IntentFilter filter = new IntentFilter();
@@ -1367,6 +1372,7 @@ public class WindowManagerService extends IWindowManager.Stub
mDisplayAreaPolicyProvider = DisplayAreaPolicy.Provider.fromResources(
mContext.getResources());
+ mImpressionAttestationController = new ImpressionAttestationController(mContext);
setGlobalShadowSettings();
mAnrController = new AnrController(this);
mStartingSurfaceController = new StartingSurfaceController(this);
@@ -1627,7 +1633,7 @@ public class WindowManagerService extends IWindowManager.Stub
}
final DisplayPolicy displayPolicy = displayContent.getDisplayPolicy();
- displayPolicy.adjustWindowParamsLw(win, win.mAttrs, callingPid, callingUid);
+ displayPolicy.adjustWindowParamsLw(win, win.mAttrs);
win.updateRequestedVisibility(requestedVisibility);
res = displayPolicy.validateAddingWindowLw(attrs, callingPid, callingUid);
@@ -2197,7 +2203,7 @@ public class WindowManagerService extends IWindowManager.Stub
int flagChanges = 0;
int privateFlagChanges = 0;
if (attrs != null) {
- displayPolicy.adjustWindowParamsLw(win, attrs, pid, uid);
+ displayPolicy.adjustWindowParamsLw(win, attrs);
win.mToken.adjustWindowParams(win, attrs);
int disableFlags =
(attrs.systemUiVisibility | attrs.subtreeSystemUiVisibility) & DISABLE_MASK;
@@ -2918,7 +2924,7 @@ public class WindowManagerService extends IWindowManager.Stub
}
void getStackBounds(int windowingMode, int activityType, Rect bounds) {
- final Task stack = mRoot.getStack(windowingMode, activityType);
+ final Task stack = mRoot.getRootTask(windowingMode, activityType);
if (stack != null) {
stack.getBounds(bounds);
return;
@@ -8428,4 +8434,64 @@ public class WindowManagerService extends IWindowManager.Stub
SystemClock.sleep(durationMs);
}
}
+
+ @Override
+ public String[] getSupportedImpressionAlgorithms() {
+ return mImpressionAttestationController.getSupportedImpressionAlgorithms();
+ }
+
+ @Override
+ public boolean verifyImpressionToken(ImpressionToken impressionToken) {
+ return mImpressionAttestationController.verifyImpressionToken(impressionToken);
+ }
+
+ ImpressionToken generateImpressionToken(Session session, IWindow window,
+ Rect boundsInWindow, String hashAlgorithm) {
+ final SurfaceControl displaySurfaceControl;
+ final Rect boundsInDisplay = new Rect(boundsInWindow);
+ synchronized (mGlobalLock) {
+ final WindowState win = windowForClientLocked(session, window, false);
+ if (win == null) {
+ Slog.w(TAG, "Failed to generate impression token. Invalid window");
+ return null;
+ }
+
+ DisplayContent displayContent = win.getDisplayContent();
+ if (displayContent == null) {
+ Slog.w(TAG, "Failed to generate impression token. Window is not on a display");
+ return null;
+ }
+
+ displaySurfaceControl = displayContent.getSurfaceControl();
+ mImpressionAttestationController.calculateImpressionTokenBoundsLocked(win,
+ boundsInWindow, boundsInDisplay);
+
+ if (boundsInDisplay.isEmpty()) {
+ Slog.w(TAG, "Failed to generate impression token. Bounds are not on screen");
+ return null;
+ }
+ }
+
+ // A screenshot of the entire display is taken rather than just the window. This is
+ // because if we take a screenshot of the window, it will not include content that might
+ // be covering it with the same uid. We want to make sure we include content that's
+ // covering to ensure we get as close as possible to what the user sees
+ final int uid = session.mUid;
+ SurfaceControl.LayerCaptureArgs args =
+ new SurfaceControl.LayerCaptureArgs.Builder(displaySurfaceControl)
+ .setUid(uid)
+ .setSourceCrop(boundsInDisplay)
+ .build();
+
+ SurfaceControl.ScreenshotHardwareBuffer screenshotHardwareBuffer =
+ SurfaceControl.captureLayers(args);
+ if (screenshotHardwareBuffer == null
+ || screenshotHardwareBuffer.getHardwareBuffer() == null) {
+ Slog.w(TAG, "Failed to generate impression token. Failed to take screenshot");
+ return null;
+ }
+
+ return mImpressionAttestationController.generateImpressionToken(
+ screenshotHardwareBuffer.getHardwareBuffer(), boundsInWindow, hashAlgorithm);
+ }
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java b/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
index d29534e8080e..1a147b9f73e4 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
@@ -98,6 +98,8 @@ class ActiveAdmin {
private static final String TAG_PASSWORD_HISTORY_LENGTH = "password-history-length";
private static final String TAG_MIN_PASSWORD_LENGTH = "min-password-length";
private static final String TAG_PASSWORD_QUALITY = "password-quality";
+ private static final String TAG_PASSWORD_QUALITY_APPLIES_TO_PARENT =
+ "password-quality-applies-parent";
private static final String TAG_POLICIES = "policies";
private static final String TAG_CROSS_PROFILE_WIDGET_PROVIDERS =
"cross-profile-widget-providers";
@@ -143,6 +145,7 @@ class ActiveAdmin {
@NonNull
PasswordPolicy mPasswordPolicy = new PasswordPolicy();
+ boolean mPasswordPolicyAppliesToParent = true;
@DevicePolicyManager.PasswordComplexity
int mPasswordComplexity = PASSWORD_COMPLEXITY_NONE;
@@ -333,6 +336,9 @@ class ActiveAdmin {
writeAttributeValueToXml(
out, TAG_MIN_PASSWORD_NONLETTER, mPasswordPolicy.nonLetter);
}
+
+ writeAttributeValueToXml(out, TAG_PASSWORD_QUALITY_APPLIES_TO_PARENT,
+ mPasswordPolicyAppliesToParent);
}
if (passwordHistoryLength != DEF_PASSWORD_HISTORY_LENGTH) {
writeAttributeValueToXml(
@@ -626,6 +632,9 @@ class ActiveAdmin {
} else if (TAG_MIN_PASSWORD_NONLETTER.equals(tag)) {
mPasswordPolicy.nonLetter = Integer.parseInt(
parser.getAttributeValue(null, ATTR_VALUE));
+ } else if (TAG_PASSWORD_QUALITY_APPLIES_TO_PARENT.equals(tag)) {
+ mPasswordPolicyAppliesToParent = Boolean.parseBoolean(
+ parser.getAttributeValue(null, ATTR_VALUE));
} else if (TAG_MAX_TIME_TO_UNLOCK.equals(tag)) {
maximumTimeToUnlock = Long.parseLong(
parser.getAttributeValue(null, ATTR_VALUE));
@@ -995,6 +1004,9 @@ class ActiveAdmin {
pw.print("minimumPasswordNonLetter=");
pw.println(mPasswordPolicy.nonLetter);
+ pw.print("passwordPolicyAppliesToParent=");
+ pw.println(mPasswordPolicyAppliesToParent);
+
pw.print("maximumTimeToUnlock=");
pw.println(maximumTimeToUnlock);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 6ca27b597987..02894b16c079 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -155,10 +155,12 @@ import android.app.admin.SystemUpdateInfo;
import android.app.admin.SystemUpdatePolicy;
import android.app.admin.UnsafeStateException;
import android.app.backup.IBackupManager;
+import android.app.compat.CompatChanges;
import android.app.trust.TrustManager;
import android.app.usage.UsageStatsManagerInternal;
import android.compat.annotation.ChangeId;
import android.compat.annotation.EnabledAfter;
+import android.compat.annotation.EnabledSince;
import android.content.ActivityNotFoundException;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
@@ -231,6 +233,7 @@ import android.provider.ContactsInternal;
import android.provider.Settings;
import android.provider.Settings.Global;
import android.provider.Telephony;
+import android.security.AppUriAuthenticationPolicy;
import android.security.IKeyChainAliasCallback;
import android.security.IKeyChainService;
import android.security.KeyChain;
@@ -264,7 +267,6 @@ import android.view.inputmethod.InputMethodInfo;
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.compat.IPlatformCompat;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
import com.android.internal.notification.SystemNotificationChannels;
@@ -527,6 +529,19 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
@EnabledAfter(targetSdkVersion = Build.VERSION_CODES.Q)
private static final long USE_SET_LOCATION_ENABLED = 117835097L;
+ /**
+ * Admin apps targeting Android S+ may not use
+ * {@link android.app.admin.DevicePolicyManager#setPasswordQuality} to set password quality
+ * on the {@code DevicePolicyManager} instance obtained by calling
+ * {@link android.app.admin.DevicePolicyManager#getParentProfileInstance}.
+ * Instead, they should use
+ * {@link android.app.admin.DevicePolicyManager#setRequiredPasswordComplexity} to set
+ * coarse-grained password requirements device-wide.
+ */
+ @ChangeId
+ @EnabledSince(targetSdkVersion = Build.VERSION_CODES.S)
+ private static final long PREVENT_SETTING_PASSWORD_QUALITY_ON_PARENT = 165573442L;
+
final Context mContext;
final Injector mInjector;
final IPackageManager mIPackageManager;
@@ -539,7 +554,6 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
private final LockSettingsInternal mLockSettingsInternal;
private final DeviceAdminServiceController mDeviceAdminServiceController;
private final OverlayPackagesProvider mOverlayPackagesProvider;
- private final IPlatformCompat mIPlatformCompat;
private final DevicePolicyCacheImpl mPolicyCache = new DevicePolicyCacheImpl();
private final DeviceStateCacheImpl mStateCache = new DeviceStateCacheImpl();
@@ -972,29 +986,21 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
/**
- * Checks if the feature is supported and it's safe to execute the given {@code operation}.
- *
- * <p>Typically called at the beginning of each API method as:
- *
- * <pre><code>
- *
- * if (!canExecute(operation, permission)) return;
- *
- * </code></pre>
- *
- * @return {@code true} when it's safe to execute, {@code false} when the feature is not
- * supported or the caller does not have the given {@code requiredPermission}.
+ * Checks if it's safe to execute the given {@code operation}.
*
* @throws UnsafeStateException if it's not safe to execute the operation.
*/
- boolean canExecute(@DevicePolicyOperation int operation, @NonNull String requiredPermission) {
- if (!mHasFeature && !hasCallingPermission(requiredPermission)) {
- return false;
+ private void checkCanExecuteOrThrowUnsafe(@DevicePolicyOperation int operation) {
+ if (!canExecute(operation)) {
+ throw mSafetyChecker.newUnsafeStateException(operation);
}
- if (mSafetyChecker == null || mSafetyChecker.isDevicePolicyOperationSafe(operation)) {
- return true;
- }
- throw mSafetyChecker.newUnsafeStateException(operation);
+ }
+
+ /**
+ * Returns whether it's safe to execute the given {@code operation}.
+ */
+ boolean canExecute(@DevicePolicyOperation int operation) {
+ return mSafetyChecker == null || mSafetyChecker.isDevicePolicyOperationSafe(operation);
}
/**
@@ -1147,13 +1153,12 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return LocalServices.getService(PersistentDataBlockManagerInternal.class);
}
- LockSettingsInternal getLockSettingsInternal() {
- return LocalServices.getService(LockSettingsInternal.class);
+ AppOpsManager getAppOpsManager() {
+ return mContext.getSystemService(AppOpsManager.class);
}
- IPlatformCompat getIPlatformCompat() {
- return IPlatformCompat.Stub.asInterface(
- ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE));
+ LockSettingsInternal getLockSettingsInternal() {
+ return LocalServices.getService(LockSettingsInternal.class);
}
boolean hasUserSetupCompleted(DevicePolicyData userData) {
@@ -1396,6 +1401,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
public long systemCurrentTimeMillis() {
return System.currentTimeMillis();
}
+
+ public boolean isChangeEnabled(long changeId, String packageName, int userId) {
+ return CompatChanges.isChangeEnabled(changeId, packageName, UserHandle.of(userId));
+ }
}
/**
@@ -1422,7 +1431,6 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
mUsageStatsManagerInternal = Objects.requireNonNull(
injector.getUsageStatsManagerInternal());
mIPackageManager = Objects.requireNonNull(injector.getIPackageManager());
- mIPlatformCompat = Objects.requireNonNull(injector.getIPlatformCompat());
mIPermissionManager = Objects.requireNonNull(injector.getIPermissionManager());
mTelephonyManager = Objects.requireNonNull(injector.getTelephonyManager());
@@ -3315,6 +3323,11 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
getTargetSdk(profileOwner.getPackageName(), userHandle) > Build.VERSION_CODES.M;
}
+ private boolean canSetPasswordQualityOnParent(String packageName, int userId) {
+ return !mInjector.isChangeEnabled(
+ PREVENT_SETTING_PASSWORD_QUALITY_ON_PARENT, packageName, userId);
+ }
+
@Override
public void setPasswordQuality(ComponentName who, int quality, boolean parent) {
if (!mHasFeature) {
@@ -3323,7 +3336,18 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
Objects.requireNonNull(who, "ComponentName is null");
validateQualityConstant(quality);
- final int userId = mInjector.userHandleGetCallingUserId();
+ final CallerIdentity caller = getCallerIdentity(who);
+ Preconditions.checkCallAuthorization(
+ isProfileOwner(caller) || isDeviceOwner(caller) || isSystemUid(caller));
+
+ final boolean qualityMayApplyToParent =
+ canSetPasswordQualityOnParent(who.getPackageName(), caller.getUserId());
+ if (!qualityMayApplyToParent) {
+ Preconditions.checkArgument(!parent,
+ "Profile Owner may not apply password quality requirements device-wide");
+ }
+
+ final int userId = caller.getUserId();
synchronized (getLockObject()) {
ActiveAdmin ap = getActiveAdminForCallerLocked(
who, DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, parent);
@@ -3332,6 +3356,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
if (passwordPolicy.quality != quality) {
passwordPolicy.quality = quality;
ap.mPasswordComplexity = PASSWORD_COMPLEXITY_NONE;
+ ap.mPasswordPolicyAppliesToParent = qualityMayApplyToParent;
resetInactivePasswordRequirementsIfRPlus(userId, ap);
updatePasswordValidityCheckpointLocked(userId, parent);
updatePasswordQualityCacheForUserGroup(userId);
@@ -3349,13 +3374,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
private boolean passwordQualityInvocationOrderCheckEnabled(String packageName, int userId) {
- try {
- return mIPlatformCompat.isChangeEnabledByPackageName(ADMIN_APP_PASSWORD_COMPLEXITY,
- packageName, userId);
- } catch (RemoteException e) {
- Log.e(LOG_TAG, "Failed to get a response from PLATFORM_COMPAT_SERVICE", e);
- }
- return getTargetSdk(packageName, userId) > Build.VERSION_CODES.Q;
+ return mInjector.isChangeEnabled(ADMIN_APP_PASSWORD_COMPLEXITY, packageName, userId);
}
/**
@@ -4063,7 +4082,16 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
synchronized (getLockObject()) {
List<ActiveAdmin> admins = getActiveAdminsForLockscreenPoliciesLocked(userId);
for (ActiveAdmin admin : admins) {
- adminMetrics.add(admin.mPasswordPolicy.getMinMetrics());
+ final boolean isAdminOfUser = userId == admin.getUserHandle().getIdentifier();
+ // Use the password metrics from the admin in one of three cases:
+ // (1) The admin is of the user we're getting the minimum metrics for. The admin
+ // always affects the user it's managing. This applies also to the parent
+ // ActiveAdmin instance: It'd have the same user handle.
+ // (2) The mPasswordPolicyAppliesToParent field is true: That indicates the
+ // call to setPasswordQuality was made by an admin that may affect the parent.
+ if (isAdminOfUser || admin.mPasswordPolicyAppliesToParent) {
+ adminMetrics.add(admin.mPasswordPolicy.getMinMetrics());
+ }
}
}
return PasswordMetrics.merge(adminMetrics);
@@ -4155,13 +4183,13 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
/* shouldIncludeProfileAdmins */ (user) -> user.id == profileUser
|| !mLockPatternUtils.isSeparateProfileChallengeEnabled(user.id));
ArrayList<PasswordMetrics> adminMetrics = new ArrayList<>(admins.size());
+ int maxRequiredComplexity = PASSWORD_COMPLEXITY_NONE;
for (ActiveAdmin admin : admins) {
adminMetrics.add(admin.mPasswordPolicy.getMinMetrics());
+ maxRequiredComplexity = Math.max(maxRequiredComplexity, admin.mPasswordComplexity);
}
- //TODO: Take complexity into account, would need to take complexity from all admins
- //in the admins list.
return PasswordMetrics.validatePasswordMetrics(PasswordMetrics.merge(adminMetrics),
- PASSWORD_COMPLEXITY_NONE, false, metrics).isEmpty();
+ maxRequiredComplexity, false, metrics).isEmpty();
}
}
@@ -4255,28 +4283,33 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
admin.mPasswordComplexity = passwordComplexity;
// Reset the password policy.
admin.mPasswordPolicy = new PasswordPolicy();
+ admin.mPasswordPolicyAppliesToParent = true;
updatePasswordValidityCheckpointLocked(caller.getUserId(), calledOnParent);
updatePasswordQualityCacheForUserGroup(caller.getUserId());
saveSettingsLocked(caller.getUserId());
- //TODO: Log password complexity change if security logging is enabled.
});
}
+ logPasswordComplexityRequiredIfSecurityLogEnabled(admin.info.getComponent(),
+ caller.getUserId(), calledOnParent, passwordComplexity);
}
//TODO: Log metrics.
}
+ private void logPasswordComplexityRequiredIfSecurityLogEnabled(ComponentName who, int userId,
+ boolean parent, int complexity) {
+ if (SecurityLog.isLoggingEnabled()) {
+ final int affectedUserId = parent ? getProfileParentId(userId) : userId;
+ SecurityLog.writeEvent(SecurityLog.TAG_PASSWORD_COMPLEXITY_REQUIRED,
+ who.getPackageName(), userId, affectedUserId, complexity);
+ }
+ }
+
private int getEffectivePasswordComplexityRequirementLocked(@UserIdInt int userHandle) {
ensureLocked();
List<ActiveAdmin> admins = getActiveAdminsForLockscreenPoliciesLocked(userHandle);
int maxRequiredComplexity = PASSWORD_COMPLEXITY_NONE;
for (ActiveAdmin admin : admins) {
- final ComponentName adminComponent = admin.info.getComponent();
- final int adminUser = admin.getUserHandle().getIdentifier();
- // Password complexity is only taken into account from DO/PO
- if (isDeviceOwner(adminComponent, adminUser)
- || isProfileOwnerUncheckedLocked(adminComponent, adminUser)) {
- maxRequiredComplexity = Math.max(maxRequiredComplexity, admin.mPasswordComplexity);
- }
+ maxRequiredComplexity = Math.max(maxRequiredComplexity, admin.mPasswordComplexity);
}
return maxRequiredComplexity;
}
@@ -4301,6 +4334,21 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
@Override
+ public int getAggregatedPasswordComplexityForUser(int userId) {
+ if (!mHasFeature) {
+ return PASSWORD_COMPLEXITY_NONE;
+ }
+
+ final CallerIdentity caller = getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(caller, userId));
+
+ synchronized (getLockObject()) {
+ return getEffectivePasswordComplexityRequirementLocked(userId);
+ }
+ }
+
+
+ @Override
public int getCurrentFailedPasswordAttempts(int userHandle, boolean parent) {
if (!mLockPatternUtils.hasSecureLockScreen()) {
return 0;
@@ -4780,10 +4828,6 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
@Override
public void lockNow(int flags, boolean parent) {
- if (!canExecute(DevicePolicyManager.OPERATION_LOCK_NOW, permission.LOCK_DEVICE)) {
- return;
- }
-
final CallerIdentity caller = getCallerIdentity();
final int callingUserId = caller.getUserId();
@@ -4796,6 +4840,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
DeviceAdminInfo.USES_POLICY_FORCE_LOCK,
parent,
android.Manifest.permission.LOCK_DEVICE);
+ checkCanExecuteOrThrowUnsafe(DevicePolicyManager.OPERATION_LOCK_NOW);
final long ident = mInjector.binderClearCallingIdentity();
try {
adminComponent = admin == null ? null : admin.info.getComponent();
@@ -4977,7 +5022,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
final CallerIdentity caller = getCallerIdentity(who, callerPackage);
Preconditions.checkCallAuthorization((caller.hasAdminComponent()
&& (isProfileOwner(caller) || isDeviceOwner(caller)))
- || (caller.hasPackage() && isCallerDelegate(caller, DELEGATION_CERT_INSTALL)));
+ || (caller.hasPackage() && (isCallerDelegate(caller, DELEGATION_CERT_INSTALL)
+ || isCredentialManagementApp(caller, alias, isUserSelectable))));
final long id = mInjector.binderClearCallingIdentity();
try {
@@ -5017,7 +5063,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
final CallerIdentity caller = getCallerIdentity(who, callerPackage);
Preconditions.checkCallAuthorization((caller.hasAdminComponent()
&& (isProfileOwner(caller) || isDeviceOwner(caller)))
- || (caller.hasPackage() && isCallerDelegate(caller, DELEGATION_CERT_INSTALL)));
+ || (caller.hasPackage() && (isCallerDelegate(caller, DELEGATION_CERT_INSTALL)
+ || isCredentialManagementApp(caller, alias))));
final long id = Binder.clearCallingIdentity();
try {
@@ -5046,6 +5093,30 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
@Override
+ public boolean hasKeyPair(String callerPackage, String alias) {
+ final CallerIdentity caller = getCallerIdentity(callerPackage);
+ Preconditions.checkCallAuthorization(canManageCertificates(caller));
+
+ return mInjector.binderWithCleanCallingIdentity(() -> {
+ try (KeyChainConnection keyChainConnection =
+ KeyChain.bindAsUser(mContext, caller.getUserHandle())) {
+ return keyChainConnection.getService().containsKeyPair(alias);
+ } catch (RemoteException e) {
+ Log.e(LOG_TAG, "Querying keypair", e);
+ } catch (InterruptedException e) {
+ Log.w(LOG_TAG, "Interrupted while querying keypair", e);
+ Thread.currentThread().interrupt();
+ }
+ return false;
+ });
+ }
+
+ private boolean canManageCertificates(CallerIdentity caller) {
+ return isProfileOwner(caller) || isDeviceOwner(caller)
+ || isCallerDelegate(caller, DELEGATION_CERT_INSTALL);
+ }
+
+ @Override
public boolean setKeyGrantForApp(ComponentName who, String callerPackage, String alias,
String packageName, boolean hasGrant) {
Preconditions.checkStringNotEmpty(alias, "Alias to grant cannot be empty");
@@ -5123,9 +5194,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
*/
if (hasProfileOwner(caller.getUserId())) {
// Make sure that the caller is the profile owner or delegate.
- Preconditions.checkCallAuthorization(
- isDeviceOwner(caller) || isProfileOwner(caller) || isCallerDelegate(
- caller, DELEGATION_CERT_INSTALL));
+ Preconditions.checkCallAuthorization(canManageCertificates(caller));
// Verify that the managed profile is on an organization-owned device and as such
// the profile owner can access Device IDs.
if (isProfileOwnerOfOrganizationOwnedDevice(caller.getUserId())) {
@@ -5199,7 +5268,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
} else {
Preconditions.checkCallAuthorization((caller.hasAdminComponent()
&& (isProfileOwner(caller) || isDeviceOwner(caller)))
- || (caller.hasPackage() && isCallerDelegate(caller, DELEGATION_CERT_INSTALL)));
+ || (caller.hasPackage() && (isCallerDelegate(caller, DELEGATION_CERT_INSTALL)
+ || isCredentialManagementApp(caller, alias))));
}
// As the caller will be granted access to the key, ensure no UID was specified, as
@@ -5295,7 +5365,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
final CallerIdentity caller = getCallerIdentity(who, callerPackage);
Preconditions.checkCallAuthorization((caller.hasAdminComponent()
&& (isProfileOwner(caller) || isDeviceOwner(caller)))
- || (caller.hasPackage() && isCallerDelegate(caller, DELEGATION_CERT_INSTALL)));
+ || (caller.hasPackage() && (isCallerDelegate(caller, DELEGATION_CERT_INSTALL)
+ || isCredentialManagementApp(caller, alias))));
final long id = mInjector.binderClearCallingIdentity();
try (final KeyChainConnection keyChainConnection =
@@ -5730,6 +5801,70 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
}
+ /**
+ * Check whether a caller application is the credential management app, which can access
+ * privileged APIs.
+ * <p>
+ * This is done by checking that the calling package is authorized to perform the app operation
+ * {@link android.app.AppOpsManager#OP_MANAGE_CREDENTIALS}. The alias provided must be contained
+ * in the aliases specified in the credential management app's authentication policy. The
+ * key pair to install must not be user selectable.
+ *
+ * @param caller the calling identity
+ * @return {@code true} if the calling process is the credential management app.
+ */
+ private boolean isCredentialManagementApp(CallerIdentity caller, String alias,
+ boolean isUserSelectable) {
+ // Should not be user selectable
+ if (isUserSelectable) {
+ Log.e(LOG_TAG, "The credential management app is not allowed to install a "
+ + "user selectable key pair");
+ return false;
+ }
+ return isCredentialManagementApp(caller, alias);
+ }
+
+ /**
+ * Check whether a caller application is the credential mangement app, which can access
+ * privileged APIs.
+ * <p>
+ * This is done by checking that the calling package is authorized to perform the app operation
+ * {@link android.app.AppOpsManager#OP_MANAGE_CREDENTIALS}. The alias provided must be contained
+ * in the aliases specified in the credential management app's authentication policy.
+ *
+ * @param caller the calling identity
+ * @return {@code true} if the calling process is the credential management app.
+ */
+ private boolean isCredentialManagementApp(CallerIdentity caller, String alias) {
+ // Should include alias in authentication policy
+ try (KeyChainConnection connection = KeyChain.bindAsUser(mContext,
+ caller.getUserHandle())) {
+ if (!containsAlias(connection.getService().getCredentialManagementAppPolicy(), alias)) {
+ return false;
+ }
+ } catch (RemoteException | InterruptedException e) {
+ return false;
+ }
+
+ AppOpsManager appOpsManager = mInjector.getAppOpsManager();
+ return appOpsManager != null
+ ? appOpsManager.noteOpNoThrow(AppOpsManager.OP_MANAGE_CREDENTIALS, caller.getUid(),
+ caller.getPackageName(), null, null) == AppOpsManager.MODE_ALLOWED
+ : false;
+ }
+
+ private static boolean containsAlias(AppUriAuthenticationPolicy policy, String alias) {
+ for (Map.Entry<String, Map<Uri, String>> appsToUris :
+ policy.getAppAndUriMappings().entrySet()) {
+ for (Map.Entry<Uri, String> urisToAliases : appsToUris.getValue().entrySet()) {
+ if (urisToAliases.getValue().equals(alias)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
@Override
public void setCertInstallerPackage(ComponentName who, String installerPackage)
throws SecurityException {
@@ -7339,6 +7474,12 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
admin.getPackageName(), userId, "set-device-owner");
Slog.i(LOG_TAG, "Device owner set: " + admin + " on user " + userId);
+
+ if (mInjector.userManagerIsHeadlessSystemUserMode()) {
+ Slog.i(LOG_TAG, "manageUser: " + admin + " on user " + userId);
+
+ manageUser(admin, admin, caller.getUserId(), null);
+ }
return true;
}
}
@@ -9311,6 +9452,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
Preconditions.checkCallAuthorization(caller.getUserHandle().isSystem(),
"createAndManageUser was called from non-system user");
Preconditions.checkCallAuthorization(isDeviceOwner(caller));
+ checkCanExecuteOrThrowUnsafe(DevicePolicyManager.OPERATION_CREATE_AND_MANAGE_USER);
+
final boolean ephemeral = (flags & DevicePolicyManager.MAKE_USER_EPHEMERAL) != 0;
final boolean demo = (flags & DevicePolicyManager.MAKE_USER_DEMO) != 0
&& UserManager.isDeviceInDemoMode(mContext);
@@ -9390,29 +9533,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
final long id = mInjector.binderClearCallingIdentity();
try {
- final String adminPkg = admin.getPackageName();
- try {
- // Install the profile owner if not present.
- if (!mIPackageManager.isPackageAvailable(adminPkg, userHandle)) {
- mIPackageManager.installExistingPackageAsUser(adminPkg, userHandle,
- PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS,
- PackageManager.INSTALL_REASON_POLICY, null);
- }
- } catch (RemoteException e) {
- // Does not happen, same process
- }
-
- // Set admin.
- setActiveAdmin(profileOwner, true, userHandle);
- final String ownerName = getProfileOwnerName(Process.myUserHandle().getIdentifier());
- setProfileOwner(profileOwner, ownerName, userHandle);
-
- synchronized (getLockObject()) {
- DevicePolicyData policyData = getUserData(userHandle);
- policyData.mInitBundle = adminExtras;
- policyData.mAdminBroadcastPending = true;
- saveSettingsLocked(userHandle);
- }
+ manageUser(admin, profileOwner, userHandle, adminExtras);
if ((flags & DevicePolicyManager.SKIP_SETUP_WIZARD) != 0) {
Settings.Secure.putIntForUser(mContext.getContentResolver(),
@@ -9433,12 +9554,53 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
}
+ private void manageUser(ComponentName admin, ComponentName profileOwner,
+ @UserIdInt int userId, PersistableBundle adminExtras) {
+ // Check for permission
+ final CallerIdentity caller = getCallerIdentity();
+ Preconditions.checkCallAuthorization(canManageUsers(caller));
+ Preconditions.checkCallAuthorization(
+ hasCallingOrSelfPermission(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS));
+ mInjector.binderWithCleanCallingIdentity(() ->
+ manageUserNoCheck(admin, profileOwner, userId, adminExtras));
+ }
+
+ private void manageUserNoCheck(ComponentName admin, ComponentName profileOwner,
+ int user, PersistableBundle adminExtras) {
+
+ final String adminPkg = admin.getPackageName();
+ try {
+ // Install the profile owner if not present.
+ if (!mIPackageManager.isPackageAvailable(adminPkg, user)) {
+ mIPackageManager.installExistingPackageAsUser(adminPkg, user,
+ PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS,
+ PackageManager.INSTALL_REASON_POLICY, null);
+ }
+ } catch (RemoteException e) {
+ // Does not happen, same process
+ }
+
+ // Set admin.
+ setActiveAdmin(profileOwner, true, user);
+ final String ownerName = getProfileOwnerName(Process.myUserHandle().getIdentifier());
+ setProfileOwner(profileOwner, ownerName, user);
+
+ synchronized (getLockObject()) {
+ DevicePolicyData policyData = getUserData(user);
+ policyData.mInitBundle = adminExtras;
+ policyData.mAdminBroadcastPending = true;
+
+ saveSettingsLocked(user);
+ }
+ }
+
@Override
public boolean removeUser(ComponentName who, UserHandle userHandle) {
Objects.requireNonNull(who, "ComponentName is null");
Objects.requireNonNull(userHandle, "UserHandle is null");
final CallerIdentity caller = getCallerIdentity(who);
Preconditions.checkCallAuthorization(isDeviceOwner(caller));
+ checkCanExecuteOrThrowUnsafe(DevicePolicyManager.OPERATION_REMOVE_USER);
return mInjector.binderWithCleanCallingIdentity(() -> {
String restriction = isManagedProfile(userHandle.getIdentifier())
@@ -9472,6 +9634,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
Objects.requireNonNull(who, "ComponentName is null");
final CallerIdentity caller = getCallerIdentity(who);
Preconditions.checkCallAuthorization(isDeviceOwner(caller));
+ checkCanExecuteOrThrowUnsafe(DevicePolicyManager.OPERATION_SWITCH_USER);
synchronized (getLockObject()) {
long id = mInjector.binderClearCallingIdentity();
@@ -9496,6 +9659,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
Objects.requireNonNull(userHandle, "UserHandle is null");
final CallerIdentity caller = getCallerIdentity(who);
Preconditions.checkCallAuthorization(isDeviceOwner(caller));
+ checkCanExecuteOrThrowUnsafe(DevicePolicyManager.OPERATION_START_USER_IN_BACKGROUND);
final int userId = userHandle.getIdentifier();
if (isManagedProfile(userId)) {
@@ -9529,6 +9693,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
Objects.requireNonNull(userHandle, "UserHandle is null");
final CallerIdentity caller = getCallerIdentity(who);
Preconditions.checkCallAuthorization(isDeviceOwner(caller));
+ checkCanExecuteOrThrowUnsafe(DevicePolicyManager.OPERATION_STOP_USER);
final int userId = userHandle.getIdentifier();
if (isManagedProfile(userId)) {
@@ -10869,16 +11034,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
private boolean isSetSecureSettingLocationModeCheckEnabled(String packageName, int userId) {
- long ident = mInjector.binderClearCallingIdentity();
- try {
- return mIPlatformCompat.isChangeEnabledByPackageName(USE_SET_LOCATION_ENABLED,
- packageName, userId);
- } catch (RemoteException e) {
- Log.e(LOG_TAG, "Failed to get a response from PLATFORM_COMPAT_SERVICE", e);
- return getTargetSdk(packageName, userId) > Build.VERSION_CODES.Q;
- } finally {
- mInjector.binderRestoreCallingIdentity(ident);
- }
+ return mInjector.isChangeEnabled(USE_SET_LOCATION_ENABLED, packageName, userId);
}
@Override
@@ -11524,6 +11680,27 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
public ComponentName getProfileOwnerAsUser(int userHandle) {
return DevicePolicyManagerService.this.getProfileOwnerAsUser(userHandle);
}
+
+ @Override
+ public boolean isDeviceOrProfileOwnerInCallingUser(String packageName) {
+ return isDeviceOwnerInCallingUser(packageName)
+ || isProfileOwnerInCallingUser(packageName);
+ }
+
+ private boolean isDeviceOwnerInCallingUser(String packageName) {
+ final ComponentName deviceOwnerInCallingUser =
+ DevicePolicyManagerService.this.getDeviceOwnerComponent(
+ /* callingUserOnly= */ true);
+ return deviceOwnerInCallingUser != null
+ && packageName.equals(deviceOwnerInCallingUser.getPackageName());
+ }
+
+ private boolean isProfileOwnerInCallingUser(String packageName) {
+ final ComponentName profileOwnerInCallingUser =
+ getProfileOwnerAsUser(UserHandle.getCallingUserId());
+ return profileOwnerInCallingUser != null
+ && packageName.equals(profileOwnerInCallingUser.getPackageName());
+ }
}
private Intent createShowAdminSupportIntent(ComponentName admin, int userId) {
@@ -12085,8 +12262,6 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
if (hasUserSetupCompleted(UserHandle.USER_SYSTEM)) {
return CODE_USER_SETUP_COMPLETED;
}
- } else {
- // STOPSHIP Do proper check in split user mode
}
return CODE_OK;
}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 10b3265cd081..6525e1126478 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -47,6 +47,7 @@ import android.content.res.Resources.Theme;
import android.database.sqlite.SQLiteCompatibilityWalFlags;
import android.database.sqlite.SQLiteGlobal;
import android.graphics.GraphicsStatsService;
+import android.graphics.Typeface;
import android.hardware.display.DisplayManagerInternal;
import android.net.ConnectivityManager;
import android.net.ConnectivityModuleConnector;
@@ -120,6 +121,7 @@ import com.android.server.display.color.ColorDisplayService;
import com.android.server.dreams.DreamManagerService;
import com.android.server.emergency.EmergencyAffordanceService;
import com.android.server.gpu.GpuService;
+import com.android.server.graphics.fonts.FontManagerService;
import com.android.server.hdmi.HdmiControlService;
import com.android.server.incident.IncidentCompanionService;
import com.android.server.input.InputManagerService;
@@ -673,6 +675,11 @@ public final class SystemServer implements Dumpable {
SystemServerInitThreadPool tp = SystemServerInitThreadPool.start();
mDumper.addDumpable(tp);
+ // Load preinstalled system fonts for system server, so that WindowManagerService, etc
+ // can start using Typeface. Note that fonts are required not only for text rendering,
+ // but also for some text operations (e.g. TextUtils.makeSafeForPresentation()).
+ Typeface.loadPreinstalledSystemFontMap();
+
// Attach JVMTI agent if this is a debuggable build and the system property is set.
if (Build.IS_DEBUGGABLE) {
// Property is of the form "library_path=parameters".
@@ -1604,6 +1611,10 @@ public final class SystemServer implements Dumpable {
}
t.traceEnd();
+ t.traceBegin("StartFontManagerService");
+ mSystemServiceManager.startService(FontManagerService.Lifecycle.class);
+ t.traceEnd();
+
t.traceBegin("StartTextServicesManager");
mSystemServiceManager.startService(TextServicesManagerService.Lifecycle.class);
t.traceEnd();
diff --git a/services/people/java/com/android/server/people/PeopleService.java b/services/people/java/com/android/server/people/PeopleService.java
index 7c3b7a67178e..49a41f02c484 100644
--- a/services/people/java/com/android/server/people/PeopleService.java
+++ b/services/people/java/com/android/server/people/PeopleService.java
@@ -74,7 +74,14 @@ public class PeopleService extends SystemService {
@Override
public void onStart() {
- publishBinderService(Context.PEOPLE_SERVICE, mService);
+ onStart(/* isForTesting= */ false);
+ }
+
+ @VisibleForTesting
+ protected void onStart(boolean isForTesting) {
+ if (!isForTesting) {
+ publishBinderService(Context.PEOPLE_SERVICE, mService);
+ }
publishLocalService(PeopleServiceInternal.class, new LocalService());
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsUpgradeTest.java b/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsUpgradeTest.java
index e48b67167cdf..9f895c678dd0 100644
--- a/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsUpgradeTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsUpgradeTest.java
@@ -35,6 +35,8 @@ import android.os.Handler;
import android.os.HandlerThread;
import android.util.Log;
import android.util.SparseArray;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
import android.util.Xml;
import androidx.test.InstrumentationRegistry;
@@ -181,7 +183,7 @@ public class AppOpsUpgradeTest {
boolean parse() {
try (FileInputStream stream = new FileInputStream(mFile)) {
- XmlPullParser parser = Xml.newPullParser();
+ TypedXmlPullParser parser = Xml.newFastPullParser();
parser.setInput(stream, StandardCharsets.UTF_8.name());
int type;
while ((type = parser.next()) != XmlPullParser.START_TAG
diff --git a/services/tests/servicestests/Android.bp b/services/tests/servicestests/Android.bp
index 0c2fab83ee66..343b156e443a 100644
--- a/services/tests/servicestests/Android.bp
+++ b/services/tests/servicestests/Android.bp
@@ -51,7 +51,6 @@ android_test {
"testng",
"junit",
"platform-compat-test-rules",
-
],
aidl: {
@@ -117,6 +116,7 @@ java_library {
"utils/**/*.java",
"utils/**/*.kt",
"utils-mockito/**/*.kt",
+ ":services.core-sources-deviceconfig-interface",
],
static_libs: [
"junit",
@@ -133,6 +133,7 @@ java_library {
"utils/**/*.java",
"utils/**/*.kt",
"utils-mockito/**/*.kt",
+ ":services.core-sources-deviceconfig-interface",
],
static_libs: [
"junit",
diff --git a/services/tests/servicestests/res/xml/usertypes_test_full.xml b/services/tests/servicestests/res/xml/usertypes_test_full.xml
index a281dcaafb3d..099ccbe5b5f6 100644
--- a/services/tests/servicestests/res/xml/usertypes_test_full.xml
+++ b/services/tests/servicestests/res/xml/usertypes_test_full.xml
@@ -22,4 +22,7 @@
<item res='@*android:color/profile_badge_1' />
</badge-colors>
</full-type>
+
+ <change-user-type from="android.old.name" to="android.test.1" whenVersionLeq="1" />
+
</user-types>
diff --git a/services/tests/servicestests/res/xml/usertypes_test_profile.xml b/services/tests/servicestests/res/xml/usertypes_test_profile.xml
index b6c8fbdcdd20..daa7d7b7341a 100644
--- a/services/tests/servicestests/res/xml/usertypes_test_profile.xml
+++ b/services/tests/servicestests/res/xml/usertypes_test_profile.xml
@@ -13,7 +13,7 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<user-types>
+<user-types version="1234">
<profile-type
name='android.test.2'
max-allowed-per-parent='12'
@@ -32,4 +32,7 @@
<default-restrictions no_remove_user='true' no_bluetooth='true' />
</profile-type>
<profile-type name='custom.test.1' max-allowed-per-parent='14' />
+
+ <change-user-type from="android.test.1" to="android.test.2" whenVersionLeq="1233" />
+
</user-types>
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java
index b9c2e56a4d90..3f3d5e5106c5 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java
@@ -17,7 +17,6 @@
package com.android.server.accessibility;
import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
@@ -42,7 +41,6 @@ import android.os.UserHandle;
import android.provider.Settings;
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.SmallTest;
-import android.view.Display;
import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
import androidx.test.InstrumentationRegistry;
@@ -208,34 +206,6 @@ public class AccessibilityManagerServiceTest extends AndroidTestCase {
}
@SmallTest
- public void testOnMagnificationScaleChanged_MagnificationCapabilitiesAll_showButton() {
- // Request showing magnification button if the magnification capability is all mode.
- mA11yms.mUserStates.get(
- mA11yms.getCurrentUserIdLocked()).setMagnificationCapabilitiesLocked(
- Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_ALL);
-
- mA11yms.onMagnificationScaleChanged(Display.DEFAULT_DISPLAY,
- Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN);
-
- verify(mMockWindowMagnificationMgr).showMagnificationButton(Display.DEFAULT_DISPLAY,
- Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN);
- }
-
- @SmallTest
- public void testOnMagnificationScaleChanged_MagnificationCapabilitiesNotAll_NoAction() {
- // Do nothing if the magnification capability is not all mode.
- mA11yms.mUserStates.get(
- mA11yms.getCurrentUserIdLocked()).setMagnificationCapabilitiesLocked(
- Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN);
-
- mA11yms.onMagnificationScaleChanged(Display.DEFAULT_DISPLAY,
- Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN);
-
- verify(mMockWindowMagnificationMgr, never()).showMagnificationButton(anyInt(),
- anyInt());
- }
-
- @SmallTest
public void testOnMagnificationTransitionFailed_capabilitiesIsAll_fallBackToPreviousMode() {
final AccessibilityUserState userState = mA11yms.mUserStates.get(
mA11yms.getCurrentUserIdLocked());
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandlerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandlerTest.java
index e43a002806ee..c038a0f33904 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandlerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandlerTest.java
@@ -54,7 +54,6 @@ import androidx.test.runner.AndroidJUnit4;
import com.android.server.accessibility.AccessibilityManagerService;
import com.android.server.accessibility.EventStreamTransformation;
import com.android.server.accessibility.magnification.FullScreenMagnificationController.MagnificationRequestObserver;
-import com.android.server.accessibility.magnification.MagnificationGestureHandler.ScaleChangedListener;
import com.android.server.testutils.OffsettableClock;
import com.android.server.testutils.TestHandler;
import com.android.server.wm.WindowManagerInternal;
@@ -125,7 +124,7 @@ public class FullScreenMagnificationGestureHandlerTest {
private Context mContext;
FullScreenMagnificationController mFullScreenMagnificationController;
@Mock
- ScaleChangedListener mMockScaleChangedListener;
+ MagnificationGestureHandler.ScaleChangedListener mMockScaleChangedListener;
@Mock
MagnificationRequestObserver mMagnificationRequestObserver;
@Mock
@@ -181,8 +180,8 @@ public class FullScreenMagnificationGestureHandlerTest {
boolean detectShortcutTrigger) {
FullScreenMagnificationGestureHandler h = new FullScreenMagnificationGestureHandler(
mContext, mFullScreenMagnificationController, mMockScaleChangedListener,
- detectTripleTap, detectShortcutTrigger, mWindowMagnificationPromptController,
- DISPLAY_0);
+ detectTripleTap, detectShortcutTrigger,
+ mWindowMagnificationPromptController, DISPLAY_0);
mHandler = new TestHandler(h.mDetectingState, mClock) {
@Override
protected String messageToString(Message m) {
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java
index aed590b8b7e0..cba618bf94b8 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java
@@ -29,6 +29,7 @@ import static org.mockito.ArgumentMatchers.nullable;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -106,8 +107,8 @@ public class MagnificationControllerTest {
mock(WindowMagnificationManager.Callback.class)));
mMockConnection = new MockWindowMagnificationConnection(true);
mWindowMagnificationManager.setConnection(mMockConnection.getConnection());
- mMagnificationController = new MagnificationController(mService, new Object(), mContext,
- mScreenMagnificationController, mWindowMagnificationManager);
+ mMagnificationController = spy(new MagnificationController(mService, new Object(), mContext,
+ mScreenMagnificationController, mWindowMagnificationManager));
}
@After
@@ -277,8 +278,32 @@ public class MagnificationControllerTest {
verify(mWindowMagnificationManager).setScale(eq(TEST_DISPLAY), eq(newScale));
verify(mWindowMagnificationManager).persistScale(eq(TEST_DISPLAY));
- verify(mService).onMagnificationScaleChanged(eq(TEST_DISPLAY),
- eq(Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW));
+ verify(mMagnificationController).onMagnificationScaleChanged(eq(TEST_DISPLAY),
+ eq(MODE_WINDOW));
+ }
+
+ @Test
+ public void onMagnificationScaleChanged_capabilitiesAllMode_showMagnificationButton()
+ throws RemoteException {
+ mMagnificationController.setMagnificationCapabilities(
+ Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_ALL);
+
+ mMagnificationController.onMagnificationScaleChanged(TEST_DISPLAY, MODE_WINDOW);
+
+ verify(mWindowMagnificationManager).showMagnificationButton(eq(TEST_DISPLAY),
+ eq(MODE_WINDOW));
+ }
+
+ @Test
+ public void onMagnificationScaleChanged_capabilitiesNotAllMode_notShowMagnificationButton()
+ throws RemoteException {
+ mMagnificationController.setMagnificationCapabilities(
+ Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN);
+
+ mMagnificationController.onMagnificationScaleChanged(TEST_DISPLAY, MODE_WINDOW);
+
+ verify(mWindowMagnificationManager, never()).showMagnificationButton(eq(TEST_DISPLAY),
+ eq(MODE_WINDOW));
}
private void setMagnificationEnabled(int mode) throws RemoteException {
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationGestureHandlerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationGestureHandlerTest.java
index 41b6e987f819..9f930da4ee29 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationGestureHandlerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationGestureHandlerTest.java
@@ -32,7 +32,6 @@ import androidx.test.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
import com.android.server.accessibility.EventStreamTransformation;
-import com.android.server.accessibility.magnification.MagnificationGestureHandler.ScaleChangedListener;
import com.android.server.accessibility.utils.TouchEventGenerator;
import org.junit.After;
@@ -74,7 +73,8 @@ public class WindowMagnificationGestureHandlerTest {
mock(WindowMagnificationManager.Callback.class));
mMockConnection = new MockWindowMagnificationConnection();
mWindowMagnificationGestureHandler = new WindowMagnificationGestureHandler(
- mContext, mWindowMagnificationManager, mock(ScaleChangedListener.class),
+ mContext, mWindowMagnificationManager, mock(
+ MagnificationGestureHandler.ScaleChangedListener.class),
/** detectTripleTap= */true, /** detectShortcutTrigger= */true, DISPLAY_0);
mWindowMagnificationManager.setConnection(mMockConnection.getConnection());
mWindowMagnificationGestureHandler.setNext(strictMock(EventStreamTransformation.class));
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
index 904e93b7d8cf..e2b48d439a47 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
@@ -127,6 +127,8 @@ public class DevicePolicyManagerServiceTestable extends DevicePolicyManagerServi
// Used as an override when set to nonzero.
private long mCurrentTimeMillis = 0;
+ private final Map<Long, Pair<String, Integer>> mEnabledChanges = new ArrayMap<>();
+
public MockInjector(MockSystemServices services, DpmMockContext context) {
super(context);
this.services = services;
@@ -487,5 +489,33 @@ public class DevicePolicyManagerServiceTestable extends DevicePolicyManagerServi
public long systemCurrentTimeMillis() {
return mCurrentTimeMillis != 0 ? mCurrentTimeMillis : System.currentTimeMillis();
}
+
+ public void setChangeEnabledForPackage(
+ long changeId, boolean enabled, String packageName, int userId) {
+ if (enabled) {
+ mEnabledChanges.put(changeId, Pair.create(packageName, userId));
+ } else {
+ mEnabledChanges.remove(changeId);
+ }
+ }
+
+ public void clearEnabledChanges() {
+ mEnabledChanges.clear();
+ }
+
+ @Override
+ public boolean isChangeEnabled(long changeId, String packageName, int userId) {
+ Pair<String, Integer> packageAndUser = mEnabledChanges.get(changeId);
+ if (packageAndUser == null) {
+ return false;
+ }
+
+ if (!packageAndUser.first.equals(packageName)
+ || !packageAndUser.second.equals(userId)) {
+ return false;
+ }
+
+ return true;
+ }
}
}
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index c0c82d53b4f0..e2c5e97b8896 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -4252,10 +4252,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
mContext.packageName = admin1.getPackageName();
mContext.applicationInfo = new ApplicationInfo();
- when(mContext.resources.getColor(eq(R.color.notification_action_list), anyObject()))
- .thenReturn(Color.WHITE);
- when(mContext.resources.getColor(eq(R.color.notification_material_background_color),
- anyObject())).thenReturn(Color.WHITE);
+ when(mContext.resources.getColor(anyInt(), anyObject())).thenReturn(Color.WHITE);
// setUp() adds a secondary user for CALLER_USER_HANDLE. Remove it as otherwise the
// feature is disabled because there are non-affiliated secondary users.
@@ -4301,10 +4298,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
setupDeviceOwner();
mContext.packageName = admin1.getPackageName();
mContext.applicationInfo = new ApplicationInfo();
- when(mContext.resources.getColor(eq(R.color.notification_action_list), anyObject()))
- .thenReturn(Color.WHITE);
- when(mContext.resources.getColor(eq(R.color.notification_material_background_color),
- anyObject())).thenReturn(Color.WHITE);
+ when(mContext.resources.getColor(anyInt(), anyObject())).thenReturn(Color.WHITE);
// setUp() adds a secondary user for CALLER_USER_HANDLE. Remove it as otherwise the
// feature is disabled because there are non-affiliated secondary users.
@@ -5090,11 +5084,11 @@ public class DevicePolicyManagerTest extends DpmTestBase {
doReturn(true).when(getServices().lockPatternUtils)
.isSeparateProfileChallengeEnabled(managedProfileUserId);
- dpm.setPasswordQuality(admin1, DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC);
- parentDpm.setPasswordQuality(admin1, DevicePolicyManager.PASSWORD_QUALITY_NUMERIC);
+ dpm.setRequiredPasswordComplexity(PASSWORD_COMPLEXITY_HIGH);
+ parentDpm.setRequiredPasswordComplexity(PASSWORD_COMPLEXITY_MEDIUM);
when(getServices().lockSettingsInternal.getUserPasswordMetrics(UserHandle.USER_SYSTEM))
- .thenReturn(computeForPassword("1234".getBytes()));
+ .thenReturn(computeForPassword("184342".getBytes()));
// Numeric password is compliant with current requirement (QUALITY_NUMERIC set explicitly
// on the parent admin)
@@ -5107,6 +5101,68 @@ public class DevicePolicyManagerTest extends DpmTestBase {
managedProfileUserId)).isFalse();
}
+ @Test
+ public void testCanSetPasswordRequirementOnParentPreS() throws Exception {
+ final int managedProfileUserId = CALLER_USER_HANDLE;
+ final int managedProfileAdminUid =
+ UserHandle.getUid(managedProfileUserId, DpmMockContext.SYSTEM_UID);
+ mContext.binder.callingUid = managedProfileAdminUid;
+ addManagedProfile(admin1, managedProfileAdminUid, admin1, VERSION_CODES.R);
+ dpms.mMockInjector.setChangeEnabledForPackage(165573442L, false,
+ admin1.getPackageName(), managedProfileUserId);
+
+ parentDpm.setPasswordQuality(admin1, DevicePolicyManager.PASSWORD_QUALITY_COMPLEX);
+ assertThat(parentDpm.getPasswordQuality(admin1))
+ .isEqualTo(DevicePolicyManager.PASSWORD_QUALITY_COMPLEX);
+ }
+
+ @Test
+ public void testCannotSetPasswordRequirementOnParent() throws Exception {
+ final int managedProfileUserId = CALLER_USER_HANDLE;
+ final int managedProfileAdminUid =
+ UserHandle.getUid(managedProfileUserId, DpmMockContext.SYSTEM_UID);
+ mContext.binder.callingUid = managedProfileAdminUid;
+ addManagedProfile(admin1, managedProfileAdminUid, admin1);
+ dpms.mMockInjector.setChangeEnabledForPackage(165573442L, true,
+ admin1.getPackageName(), managedProfileUserId);
+
+ try {
+ assertExpectException(IllegalArgumentException.class, null, () ->
+ parentDpm.setPasswordQuality(
+ admin1, DevicePolicyManager.PASSWORD_QUALITY_COMPLEX));
+ } finally {
+ dpms.mMockInjector.clearEnabledChanges();
+ }
+ }
+
+ @Test
+ public void testPasswordQualityAppliesToParentPreS() throws Exception {
+ final int managedProfileUserId = CALLER_USER_HANDLE;
+ final int managedProfileAdminUid =
+ UserHandle.getUid(managedProfileUserId, DpmMockContext.SYSTEM_UID);
+ mContext.binder.callingUid = managedProfileAdminUid;
+ addManagedProfile(admin1, managedProfileAdminUid, admin1, VERSION_CODES.R);
+ when(getServices().userManager.getProfileParent(CALLER_USER_HANDLE))
+ .thenReturn(new UserInfo(UserHandle.USER_SYSTEM, "user system", 0));
+
+ dpm.setPasswordQuality(admin1, DevicePolicyManager.PASSWORD_QUALITY_COMPLEX);
+ assertThat(parentDpm.getPasswordQuality(null))
+ .isEqualTo(DevicePolicyManager.PASSWORD_QUALITY_COMPLEX);
+ }
+
+ @Test
+ public void testPasswordQualityDoesNotApplyToParentPostS() throws Exception {
+ final int managedProfileUserId = CALLER_USER_HANDLE;
+ final int managedProfileAdminUid =
+ UserHandle.getUid(managedProfileUserId, DpmMockContext.SYSTEM_UID);
+ mContext.binder.callingUid = managedProfileAdminUid;
+ addManagedProfile(admin1, managedProfileAdminUid, admin1, VERSION_CODES.R);
+
+ dpm.setPasswordQuality(admin1, DevicePolicyManager.PASSWORD_QUALITY_COMPLEX);
+ assertThat(parentDpm.getPasswordQuality(admin1))
+ .isEqualTo(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED);
+ }
+
private void setActivePasswordState(PasswordMetrics passwordMetrics)
throws Exception {
final int userHandle = UserHandle.getUserId(mContext.binder.callingUid);
@@ -7014,20 +7070,32 @@ public class DevicePolicyManagerTest extends DpmTestBase {
* @param adminUid uid of the admin package.
* @param copyFromAdmin package information for {@code admin} will be built based on this
* component's information.
+ * @param appTargetSdk admin's target SDK level
*/
private void addManagedProfile(
- ComponentName admin, int adminUid, ComponentName copyFromAdmin) throws Exception {
+ ComponentName admin, int adminUid, ComponentName copyFromAdmin, int appTargetSdk)
+ throws Exception {
final int userId = UserHandle.getUserId(adminUid);
getServices().addUser(userId, 0, UserManager.USER_TYPE_PROFILE_MANAGED,
UserHandle.USER_SYSTEM);
mContext.callerPermissions.addAll(OWNER_SETUP_PERMISSIONS);
- setUpPackageManagerForFakeAdmin(admin, adminUid, copyFromAdmin);
+ setUpPackageManagerForFakeAdmin(admin, adminUid, /* enabledSetting= */ null,
+ appTargetSdk, copyFromAdmin);
dpm.setActiveAdmin(admin, false, userId);
assertThat(dpm.setProfileOwner(admin, null, userId)).isTrue();
mContext.callerPermissions.removeAll(OWNER_SETUP_PERMISSIONS);
}
/**
+ * Same as {@code addManagedProfile} above, except using development API level as the API
+ * level of the admin.
+ */
+ private void addManagedProfile(
+ ComponentName admin, int adminUid, ComponentName copyFromAdmin) throws Exception {
+ addManagedProfile(admin, adminUid, copyFromAdmin, VERSION_CODES.CUR_DEVELOPMENT);
+ }
+
+ /**
* Convert String[] to StringParceledListSlice.
*/
private static StringParceledListSlice asSlice(String[] s) {
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/FactoryResetProtectionPolicyTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/FactoryResetProtectionPolicyTest.java
index 3aa5a80d814f..d58d71fb44c3 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/FactoryResetProtectionPolicyTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/FactoryResetProtectionPolicyTest.java
@@ -23,6 +23,8 @@ import static org.mockito.Mockito.when;
import android.app.admin.FactoryResetProtectionPolicy;
import android.os.Parcel;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
import android.util.Xml;
import androidx.test.runner.AndroidJUnit4;
@@ -98,7 +100,7 @@ public class FactoryResetProtectionPolicyTest {
throws Exception {
ByteArrayOutputStream outStream = serialize(policy);
ByteArrayInputStream inStream = new ByteArrayInputStream(outStream.toByteArray());
- XmlPullParser parser = Xml.newPullParser();
+ TypedXmlPullParser parser = Xml.newFastPullParser();
parser.setInput(new InputStreamReader(inStream));
assertThat(parser.next()).isEqualTo(XmlPullParser.START_TAG);
@@ -109,7 +111,7 @@ public class FactoryResetProtectionPolicyTest {
throws Exception {
ByteArrayOutputStream outStream = serialize(policy);
ByteArrayInputStream inStream = new ByteArrayInputStream(outStream.toByteArray());
- XmlPullParser parser = mock(XmlPullParser.class);
+ TypedXmlPullParser parser = mock(TypedXmlPullParser.class);
when(parser.next()).thenThrow(XmlPullParserException.class);
parser.setInput(new InputStreamReader(inStream));
@@ -120,7 +122,7 @@ public class FactoryResetProtectionPolicyTest {
private ByteArrayOutputStream serialize(FactoryResetProtectionPolicy policy)
throws IOException {
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
- final XmlSerializer outXml = new FastXmlSerializer();
+ final TypedXmlSerializer outXml = Xml.newFastSerializer();
outXml.setOutput(outStream, StandardCharsets.UTF_8.name());
outXml.startDocument(null, true);
outXml.startTag(null, TAG_FACTORY_RESET_PROTECTION_POLICY);
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/SystemUpdatePolicyTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/SystemUpdatePolicyTest.java
index 0a9aad771ff0..1308a3e74881 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/SystemUpdatePolicyTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/SystemUpdatePolicyTest.java
@@ -29,6 +29,8 @@ import static org.junit.Assert.fail;
import android.app.admin.FreezePeriod;
import android.app.admin.SystemUpdatePolicy;
import android.os.Parcel;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
import android.util.Xml;
import androidx.test.runner.AndroidJUnit4;
@@ -471,7 +473,7 @@ public final class SystemUpdatePolicyTest {
// Test XML serialization
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
- final XmlSerializer outXml = new FastXmlSerializer();
+ final TypedXmlSerializer outXml = Xml.newFastSerializer();
outXml.setOutput(outStream, StandardCharsets.UTF_8.name());
outXml.startDocument(null, true);
outXml.startTag(null, "ota");
@@ -481,7 +483,7 @@ public final class SystemUpdatePolicyTest {
outXml.flush();
ByteArrayInputStream inStream = new ByteArrayInputStream(outStream.toByteArray());
- XmlPullParser parser = Xml.newPullParser();
+ TypedXmlPullParser parser = Xml.newFastPullParser();
parser.setInput(new InputStreamReader(inStream));
assertThat(parser.next()).isEqualTo(XmlPullParser.START_TAG);
checkFreezePeriods(SystemUpdatePolicy.restoreFromXml(parser), expectedPeriods);
diff --git a/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java b/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java
index 325ba118c711..cb5ca04c1fde 100644
--- a/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java
@@ -16,49 +16,97 @@
package com.android.server.display;
+import static android.hardware.display.DisplayManager.DeviceConfig.KEY_FIXED_REFRESH_RATE_HIGH_AMBIENT_BRIGHTNESS_THRESHOLDS;
+import static android.hardware.display.DisplayManager.DeviceConfig.KEY_FIXED_REFRESH_RATE_HIGH_DISPLAY_BRIGHTNESS_THRESHOLDS;
+import static android.hardware.display.DisplayManager.DeviceConfig.KEY_FIXED_REFRESH_RATE_LOW_AMBIENT_BRIGHTNESS_THRESHOLDS;
+import static android.hardware.display.DisplayManager.DeviceConfig.KEY_FIXED_REFRESH_RATE_LOW_DISPLAY_BRIGHTNESS_THRESHOLDS;
+import static android.hardware.display.DisplayManager.DeviceConfig.KEY_REFRESH_RATE_IN_HIGH_ZONE;
+import static android.hardware.display.DisplayManager.DeviceConfig.KEY_REFRESH_RATE_IN_LOW_ZONE;
+
+import static com.android.server.display.DisplayModeDirector.Vote.PRIORITY_FLICKER;
+
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import android.annotation.NonNull;
+import android.content.ContentResolver;
import android.content.Context;
+import android.content.ContextWrapper;
+import android.database.ContentObserver;
+import android.hardware.Sensor;
+import android.hardware.SensorEventListener;
+import android.hardware.SensorManager;
import android.os.Handler;
import android.os.Looper;
+import android.provider.DeviceConfig;
+import android.provider.Settings;
+import android.test.mock.MockContentResolver;
+import android.util.Slog;
import android.util.SparseArray;
import android.view.Display;
-import androidx.test.InstrumentationRegistry;
+import androidx.test.core.app.ApplicationProvider;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
+import com.android.internal.util.Preconditions;
+import com.android.internal.util.test.FakeSettingsProvider;
+import com.android.internal.util.test.FakeSettingsProviderRule;
import com.android.server.display.DisplayModeDirector.BrightnessObserver;
import com.android.server.display.DisplayModeDirector.DesiredDisplayModeSpecs;
import com.android.server.display.DisplayModeDirector.Vote;
+import com.android.server.testutils.FakeDeviceConfigInterface;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.Executor;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
+
@SmallTest
@RunWith(AndroidJUnit4.class)
public class DisplayModeDirectorTest {
// The tolerance within which we consider something approximately equals.
+ private static final String TAG = "DisplayModeDirectorTest";
+ private static final boolean DEBUG = false;
private static final float FLOAT_TOLERANCE = 0.01f;
private Context mContext;
+ private FakesInjector mInjector;
+ private Handler mHandler;
+ @Rule
+ public FakeSettingsProviderRule mSettingsProviderRule = FakeSettingsProvider.rule();
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
- mContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
+ mContext = spy(new ContextWrapper(ApplicationProvider.getApplicationContext()));
+ final MockContentResolver resolver = mSettingsProviderRule.mockContentResolver(mContext);
+ when(mContext.getContentResolver()).thenReturn(resolver);
+ mInjector = new FakesInjector();
+ mHandler = new Handler(Looper.getMainLooper());
}
private DisplayModeDirector createDirectorFromRefreshRateArray(
float[] refreshRates, int baseModeId) {
DisplayModeDirector director =
- new DisplayModeDirector(mContext, new Handler(Looper.getMainLooper()));
+ new DisplayModeDirector(mContext, mHandler, mInjector);
int displayId = 0;
Display.Mode[] modes = new Display.Mode[refreshRates.length];
for (int i = 0; i < refreshRates.length; i++) {
@@ -159,9 +207,9 @@ public class DisplayModeDirectorTest {
}
@Test
- public void testBrightnessHasLowerPriorityThanUser() {
- assertTrue(Vote.PRIORITY_LOW_BRIGHTNESS < Vote.PRIORITY_APP_REQUEST_REFRESH_RATE);
- assertTrue(Vote.PRIORITY_LOW_BRIGHTNESS < Vote.PRIORITY_APP_REQUEST_SIZE);
+ public void testFlickerHasLowerPriorityThanUser() {
+ assertTrue(PRIORITY_FLICKER < Vote.PRIORITY_APP_REQUEST_REFRESH_RATE);
+ assertTrue(PRIORITY_FLICKER < Vote.PRIORITY_APP_REQUEST_SIZE);
int displayId = 0;
DisplayModeDirector director = createDirectorFromFpsRange(60, 90);
@@ -169,7 +217,7 @@ public class DisplayModeDirectorTest {
SparseArray<SparseArray<Vote>> votesByDisplay = new SparseArray<>();
votesByDisplay.put(displayId, votes);
votes.put(Vote.PRIORITY_APP_REQUEST_REFRESH_RATE, Vote.forRefreshRates(60, 90));
- votes.put(Vote.PRIORITY_LOW_BRIGHTNESS, Vote.forRefreshRates(60, 60));
+ votes.put(PRIORITY_FLICKER, Vote.forRefreshRates(60, 60));
director.injectVotesByDisplay(votesByDisplay);
DesiredDisplayModeSpecs desiredSpecs = director.getDesiredDisplayModeSpecs(displayId);
assertThat(desiredSpecs.primaryRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(60);
@@ -177,7 +225,7 @@ public class DisplayModeDirectorTest {
votes.clear();
votes.put(Vote.PRIORITY_APP_REQUEST_REFRESH_RATE, Vote.forRefreshRates(60, 90));
- votes.put(Vote.PRIORITY_LOW_BRIGHTNESS, Vote.forRefreshRates(90, 90));
+ votes.put(PRIORITY_FLICKER, Vote.forRefreshRates(90, 90));
director.injectVotesByDisplay(votesByDisplay);
desiredSpecs = director.getDesiredDisplayModeSpecs(displayId);
assertThat(desiredSpecs.primaryRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(90);
@@ -185,7 +233,7 @@ public class DisplayModeDirectorTest {
votes.clear();
votes.put(Vote.PRIORITY_APP_REQUEST_REFRESH_RATE, Vote.forRefreshRates(90, 90));
- votes.put(Vote.PRIORITY_LOW_BRIGHTNESS, Vote.forRefreshRates(60, 60));
+ votes.put(PRIORITY_FLICKER, Vote.forRefreshRates(60, 60));
director.injectVotesByDisplay(votesByDisplay);
desiredSpecs = director.getDesiredDisplayModeSpecs(displayId);
assertThat(desiredSpecs.primaryRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(90);
@@ -193,7 +241,7 @@ public class DisplayModeDirectorTest {
votes.clear();
votes.put(Vote.PRIORITY_APP_REQUEST_REFRESH_RATE, Vote.forRefreshRates(60, 60));
- votes.put(Vote.PRIORITY_LOW_BRIGHTNESS, Vote.forRefreshRates(90, 90));
+ votes.put(PRIORITY_FLICKER, Vote.forRefreshRates(90, 90));
director.injectVotesByDisplay(votesByDisplay);
desiredSpecs = director.getDesiredDisplayModeSpecs(displayId);
assertThat(desiredSpecs.primaryRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(60);
@@ -202,10 +250,10 @@ public class DisplayModeDirectorTest {
@Test
public void testAppRequestRefreshRateRange() {
- // Confirm that the app request range doesn't include low brightness or min refresh rate
- // settings, but does include everything else.
+ // Confirm that the app request range doesn't include flicker or min refresh rate settings,
+ // but does include everything else.
assertTrue(
- Vote.PRIORITY_LOW_BRIGHTNESS < Vote.APP_REQUEST_REFRESH_RATE_RANGE_PRIORITY_CUTOFF);
+ PRIORITY_FLICKER < Vote.APP_REQUEST_REFRESH_RATE_RANGE_PRIORITY_CUTOFF);
assertTrue(Vote.PRIORITY_USER_SETTING_MIN_REFRESH_RATE
< Vote.APP_REQUEST_REFRESH_RATE_RANGE_PRIORITY_CUTOFF);
assertTrue(Vote.PRIORITY_APP_REQUEST_REFRESH_RATE
@@ -216,7 +264,7 @@ public class DisplayModeDirectorTest {
SparseArray<Vote> votes = new SparseArray<>();
SparseArray<SparseArray<Vote>> votesByDisplay = new SparseArray<>();
votesByDisplay.put(displayId, votes);
- votes.put(Vote.PRIORITY_LOW_BRIGHTNESS, Vote.forRefreshRates(60, 60));
+ votes.put(PRIORITY_FLICKER, Vote.forRefreshRates(60, 60));
director.injectVotesByDisplay(votesByDisplay);
DesiredDisplayModeSpecs desiredSpecs = director.getDesiredDisplayModeSpecs(displayId);
assertThat(desiredSpecs.primaryRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(60);
@@ -310,7 +358,7 @@ public class DisplayModeDirectorTest {
SparseArray<Vote> votes = new SparseArray<>();
SparseArray<SparseArray<Vote>> votesByDisplay = new SparseArray<>();
votesByDisplay.put(displayId, votes);
- votes.put(Vote.PRIORITY_LOW_BRIGHTNESS, Vote.forRefreshRates(0, 60));
+ votes.put(PRIORITY_FLICKER, Vote.forRefreshRates(0, 60));
votes.put(Vote.PRIORITY_USER_SETTING_MIN_REFRESH_RATE, Vote.forRefreshRates(60, 90));
votes.put(Vote.PRIORITY_APP_REQUEST_REFRESH_RATE, Vote.forRefreshRates(90, 90));
votes.put(Vote.PRIORITY_USER_SETTING_PEAK_REFRESH_RATE, Vote.forRefreshRates(60, 60));
@@ -398,4 +446,343 @@ public class DisplayModeDirectorTest {
DesiredDisplayModeSpecs desiredSpecs = director.getDesiredDisplayModeSpecs(displayId);
assertThat(desiredSpecs.allowGroupSwitching).isTrue();
}
+
+ @Test
+ public void testBrightnessObserverGetsUpdatedRefreshRatesForZone() {
+ DisplayModeDirector director =
+ createDirectorFromRefreshRateArray(new float[] {60.f, 90.f}, /* baseModeId= */ 0);
+ SensorManager sensorManager = createMockSensorManager(createLightSensor());
+
+ final int initialRefreshRate = 60;
+ mInjector.getDeviceConfig().setRefreshRateInLowZone(initialRefreshRate);
+ director.start(sensorManager);
+ assertThat(director.getBrightnessObserver().getRefreshRateInLowZone())
+ .isEqualTo(initialRefreshRate);
+
+ final int updatedRefreshRate = 90;
+ mInjector.getDeviceConfig().setRefreshRateInLowZone(updatedRefreshRate);
+ // Need to wait for the property change to propagate to the main thread.
+ waitForIdleSync();
+ assertThat(director.getBrightnessObserver().getRefreshRateInLowZone())
+ .isEqualTo(updatedRefreshRate);
+ }
+
+ @Test
+ public void testBrightnessObserverThresholdsInZone() {
+ DisplayModeDirector director =
+ createDirectorFromRefreshRateArray(new float[] {60.f, 90.f}, /* baseModeId= */ 0);
+ SensorManager sensorManager = createMockSensorManager(createLightSensor());
+
+ final int[] initialDisplayThresholds = { 10 };
+ final int[] initialAmbientThresholds = { 20 };
+
+ final FakeDeviceConfig config = mInjector.getDeviceConfig();
+ config.setLowDisplayBrightnessThresholds(initialDisplayThresholds);
+ config.setLowAmbientBrightnessThresholds(initialAmbientThresholds);
+ director.start(sensorManager);
+
+ assertThat(director.getBrightnessObserver().getLowDisplayBrightnessThresholds())
+ .isEqualTo(initialDisplayThresholds);
+ assertThat(director.getBrightnessObserver().getLowAmbientBrightnessThresholds())
+ .isEqualTo(initialAmbientThresholds);
+
+ final int[] updatedDisplayThresholds = { 9, 14 };
+ final int[] updatedAmbientThresholds = { -1, 19 };
+ config.setLowDisplayBrightnessThresholds(updatedDisplayThresholds);
+ config.setLowAmbientBrightnessThresholds(updatedAmbientThresholds);
+ // Need to wait for the property change to propagate to the main thread.
+ waitForIdleSync();
+ assertThat(director.getBrightnessObserver().getLowDisplayBrightnessThresholds())
+ .isEqualTo(updatedDisplayThresholds);
+ assertThat(director.getBrightnessObserver().getLowAmbientBrightnessThresholds())
+ .isEqualTo(updatedAmbientThresholds);
+ }
+
+ @Test
+ public void testLockFpsForLowZone() throws Exception {
+ DisplayModeDirector director =
+ createDirectorFromRefreshRateArray(new float[] {60.f, 90.f}, 0);
+ setPeakRefreshRate(90);
+ director.getSettingsObserver().setDefaultRefreshRate(90);
+ director.getBrightnessObserver().setDefaultDisplayState(true);
+
+ final FakeDeviceConfig config = mInjector.getDeviceConfig();
+ config.setRefreshRateInLowZone(90);
+ config.setLowDisplayBrightnessThresholds(new int[] { 10 });
+ config.setLowAmbientBrightnessThresholds(new int[] { 20 });
+
+ Sensor lightSensor = createLightSensor();
+ SensorManager sensorManager = createMockSensorManager(lightSensor);
+
+ director.start(sensorManager);
+
+ ArgumentCaptor<SensorEventListener> listenerCaptor =
+ ArgumentCaptor.forClass(SensorEventListener.class);
+ Mockito.verify(sensorManager, Mockito.timeout(TimeUnit.SECONDS.toMillis(1)))
+ .registerListener(
+ listenerCaptor.capture(),
+ eq(lightSensor),
+ anyInt(),
+ any(Handler.class));
+ SensorEventListener listener = listenerCaptor.getValue();
+
+ setBrightness(10);
+ // Sensor reads 20 lux,
+ listener.onSensorChanged(TestUtils.createSensorEvent(lightSensor, 20 /*lux*/));
+
+ Vote vote = director.getVote(Display.DEFAULT_DISPLAY, PRIORITY_FLICKER);
+ assertVoteForRefreshRateLocked(vote, 90 /*fps*/);
+
+ setBrightness(125);
+ // Sensor reads 1000 lux,
+ listener.onSensorChanged(TestUtils.createSensorEvent(lightSensor, 1000 /*lux*/));
+
+ vote = director.getVote(Display.DEFAULT_DISPLAY, PRIORITY_FLICKER);
+ assertThat(vote).isNull();
+ }
+
+ @Test
+ public void testLockFpsForHighZone() throws Exception {
+ DisplayModeDirector director =
+ createDirectorFromRefreshRateArray(new float[] {60.f, 90.f}, 0);
+ setPeakRefreshRate(90 /*fps*/);
+ director.getSettingsObserver().setDefaultRefreshRate(90);
+ director.getBrightnessObserver().setDefaultDisplayState(true);
+
+ final FakeDeviceConfig config = mInjector.getDeviceConfig();
+ config.setRefreshRateInHighZone(60);
+ config.setHighDisplayBrightnessThresholds(new int[] { 255 });
+ config.setHighAmbientBrightnessThresholds(new int[] { 8000 });
+
+ Sensor lightSensor = createLightSensor();
+ SensorManager sensorManager = createMockSensorManager(lightSensor);
+
+ director.start(sensorManager);
+
+ ArgumentCaptor<SensorEventListener> listenerCaptor =
+ ArgumentCaptor.forClass(SensorEventListener.class);
+ Mockito.verify(sensorManager, Mockito.timeout(TimeUnit.SECONDS.toMillis(1)))
+ .registerListener(
+ listenerCaptor.capture(),
+ eq(lightSensor),
+ anyInt(),
+ any(Handler.class));
+ SensorEventListener listener = listenerCaptor.getValue();
+
+ setBrightness(100);
+ // Sensor reads 2000 lux,
+ listener.onSensorChanged(TestUtils.createSensorEvent(lightSensor, 2000));
+
+ Vote vote = director.getVote(Display.DEFAULT_DISPLAY, PRIORITY_FLICKER);
+ assertThat(vote).isNull();
+
+ setBrightness(255);
+ // Sensor reads 9000 lux,
+ listener.onSensorChanged(TestUtils.createSensorEvent(lightSensor, 9000));
+
+ vote = director.getVote(Display.DEFAULT_DISPLAY, PRIORITY_FLICKER);
+ assertVoteForRefreshRateLocked(vote, 60 /*fps*/);
+ }
+
+ private void assertVoteForRefreshRateLocked(Vote vote, float refreshRate) {
+ assertThat(vote).isNotNull();
+ final DisplayModeDirector.RefreshRateRange expectedRange =
+ new DisplayModeDirector.RefreshRateRange(refreshRate, refreshRate);
+ assertThat(vote.refreshRateRange).isEqualTo(expectedRange);
+ }
+
+ private static class FakeDeviceConfig extends FakeDeviceConfigInterface {
+ @Override
+ public String getProperty(String namespace, String name) {
+ Preconditions.checkArgument(DeviceConfig.NAMESPACE_DISPLAY_MANAGER.equals(namespace));
+ return super.getProperty(namespace, name);
+ }
+
+ @Override
+ public void addOnPropertiesChangedListener(
+ String namespace,
+ Executor executor,
+ DeviceConfig.OnPropertiesChangedListener listener) {
+ Preconditions.checkArgument(DeviceConfig.NAMESPACE_DISPLAY_MANAGER.equals(namespace));
+ super.addOnPropertiesChangedListener(namespace, executor, listener);
+ }
+
+ void setRefreshRateInLowZone(int fps) {
+ putPropertyAndNotify(
+ DeviceConfig.NAMESPACE_DISPLAY_MANAGER, KEY_REFRESH_RATE_IN_LOW_ZONE,
+ String.valueOf(fps));
+ }
+
+ void setLowDisplayBrightnessThresholds(int[] brightnessThresholds) {
+ String thresholds = toPropertyValue(brightnessThresholds);
+
+ if (DEBUG) {
+ Slog.e(TAG, "Brightness Thresholds = " + thresholds);
+ }
+
+ putPropertyAndNotify(
+ DeviceConfig.NAMESPACE_DISPLAY_MANAGER,
+ KEY_FIXED_REFRESH_RATE_LOW_DISPLAY_BRIGHTNESS_THRESHOLDS,
+ thresholds);
+ }
+
+ void setLowAmbientBrightnessThresholds(int[] ambientThresholds) {
+ String thresholds = toPropertyValue(ambientThresholds);
+
+ if (DEBUG) {
+ Slog.e(TAG, "Ambient Thresholds = " + thresholds);
+ }
+
+ putPropertyAndNotify(
+ DeviceConfig.NAMESPACE_DISPLAY_MANAGER,
+ KEY_FIXED_REFRESH_RATE_LOW_AMBIENT_BRIGHTNESS_THRESHOLDS,
+ thresholds);
+ }
+
+ void setRefreshRateInHighZone(int fps) {
+ putPropertyAndNotify(
+ DeviceConfig.NAMESPACE_DISPLAY_MANAGER, KEY_REFRESH_RATE_IN_HIGH_ZONE,
+ String.valueOf(fps));
+ }
+
+ void setHighDisplayBrightnessThresholds(int[] brightnessThresholds) {
+ String thresholds = toPropertyValue(brightnessThresholds);
+
+ if (DEBUG) {
+ Slog.e(TAG, "Brightness Thresholds = " + thresholds);
+ }
+
+ putPropertyAndNotify(
+ DeviceConfig.NAMESPACE_DISPLAY_MANAGER,
+ KEY_FIXED_REFRESH_RATE_HIGH_DISPLAY_BRIGHTNESS_THRESHOLDS,
+ thresholds);
+ }
+
+ void setHighAmbientBrightnessThresholds(int[] ambientThresholds) {
+ String thresholds = toPropertyValue(ambientThresholds);
+
+ if (DEBUG) {
+ Slog.e(TAG, "Ambient Thresholds = " + thresholds);
+ }
+
+ putPropertyAndNotify(
+ DeviceConfig.NAMESPACE_DISPLAY_MANAGER,
+ KEY_FIXED_REFRESH_RATE_HIGH_AMBIENT_BRIGHTNESS_THRESHOLDS,
+ thresholds);
+ }
+
+ @NonNull
+ private static String toPropertyValue(@NonNull int[] intArray) {
+ return Arrays.stream(intArray)
+ .mapToObj(Integer::toString)
+ .collect(Collectors.joining(","));
+ }
+ }
+
+ private void setBrightness(int brightness) {
+ Settings.System.putInt(mContext.getContentResolver(), Settings.System.SCREEN_BRIGHTNESS,
+ brightness);
+ mInjector.notifyBrightnessChanged();
+ waitForIdleSync();
+ }
+
+ private void setPeakRefreshRate(float fps) {
+ Settings.System.putFloat(mContext.getContentResolver(), Settings.System.PEAK_REFRESH_RATE,
+ fps);
+ mInjector.notifyPeakRefreshRateChanged();
+ waitForIdleSync();
+ }
+
+ private static SensorManager createMockSensorManager(Sensor... sensors) {
+ SensorManager sensorManager = Mockito.mock(SensorManager.class);
+ when(sensorManager.getSensorList(anyInt())).then((invocation) -> {
+ List<Sensor> requestedSensors = new ArrayList<>();
+ int type = invocation.getArgument(0);
+ for (Sensor sensor : sensors) {
+ if (sensor.getType() == type || type == Sensor.TYPE_ALL) {
+ requestedSensors.add(sensor);
+ }
+ }
+ return requestedSensors;
+ });
+
+ when(sensorManager.getDefaultSensor(anyInt())).then((invocation) -> {
+ int type = invocation.getArgument(0);
+ for (Sensor sensor : sensors) {
+ if (sensor.getType() == type) {
+ return sensor;
+ }
+ }
+ return null;
+ });
+ return sensorManager;
+ }
+
+ private static Sensor createLightSensor() {
+ try {
+ return TestUtils.createSensor(Sensor.TYPE_LIGHT, Sensor.STRING_TYPE_LIGHT);
+ } catch (Exception e) {
+ // There's nothing we can do if this fails, just throw a RuntimeException so that we
+ // don't have to mark every function that might call this as throwing Exception
+ throw new RuntimeException("Failed to create a light sensor", e);
+ }
+ }
+
+ private void waitForIdleSync() {
+ mHandler.runWithScissors(() -> { }, 500 /*timeout*/);
+ }
+
+ static class FakesInjector implements DisplayModeDirector.Injector {
+ private final FakeDeviceConfig mDeviceConfig;
+ private ContentObserver mBrightnessObserver;
+ private ContentObserver mPeakRefreshRateObserver;
+
+ FakesInjector() {
+ mDeviceConfig = new FakeDeviceConfig();
+ }
+
+ @NonNull
+ public FakeDeviceConfig getDeviceConfig() {
+ return mDeviceConfig;
+ }
+
+ @Override
+ public void registerBrightnessObserver(@NonNull ContentResolver cr,
+ @NonNull ContentObserver observer) {
+ if (mBrightnessObserver != null) {
+ throw new IllegalStateException("Tried to register a second brightness observer");
+ }
+ mBrightnessObserver = observer;
+ }
+
+ @Override
+ public void unregisterBrightnessObserver(@NonNull ContentResolver cr,
+ @NonNull ContentObserver observer) {
+ mBrightnessObserver = null;
+ }
+
+ void notifyBrightnessChanged() {
+ if (mBrightnessObserver != null) {
+ mBrightnessObserver.dispatchChange(false /*selfChange*/, DISPLAY_BRIGHTNESS_URI);
+ }
+ }
+
+ @Override
+ public void registerPeakRefreshRateObserver(@NonNull ContentResolver cr,
+ @NonNull ContentObserver observer) {
+ mPeakRefreshRateObserver = observer;
+ }
+
+ void notifyPeakRefreshRateChanged() {
+ if (mPeakRefreshRateObserver != null) {
+ mPeakRefreshRateObserver.dispatchChange(false /*selfChange*/,
+ PEAK_REFRESH_RATE_URI);
+ }
+ }
+
+ @Override
+ public boolean isDeviceInteractive(@NonNull Context context) {
+ return true;
+ }
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecConfigTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecConfigTest.java
index de9a5e4f0fe7..d10e075c5136 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecConfigTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecConfigTest.java
@@ -18,17 +18,13 @@ package com.android.server.hdmi;
import static com.google.common.truth.Truth.assertThat;
import static junit.framework.Assert.assertTrue;
-import static junit.framework.Assert.fail;
-import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.testng.Assert.assertThrows;
-import android.annotation.NonNull;
import android.content.Context;
import android.hardware.hdmi.HdmiControlManager;
-import android.os.Looper;
import android.platform.test.annotations.Presubmit;
import android.provider.Settings.Global;
@@ -42,21 +38,15 @@ import org.junit.runners.JUnit4;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
@SmallTest
@Presubmit
@RunWith(JUnit4.class)
public final class HdmiCecConfigTest {
private static final String TAG = "HdmiCecConfigTest";
- private static final int TIMEOUT_CONTENT_CHANGE_SEC = 4;
-
private Context mContext;
@Mock private HdmiCecConfig.StorageAdapter mStorageAdapter;
- @Mock private HdmiCecConfig.SettingChangeListener mSettingChangeListener;
@Before
public void setUp() throws Exception {
@@ -1029,105 +1019,4 @@ public final class HdmiCecConfigTest {
HdmiControlManager.CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING,
Integer.toString(HdmiControlManager.SYSTEM_AUDIO_MODE_MUTING_DISABLED));
}
-
- @Test
- public void registerChangeListener_SharedPref_BasicSanity() {
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter,
- "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
- + "<cec-settings>"
- + " <setting name=\"system_audio_mode_muting\""
- + " value-type=\"int\""
- + " user-configurable=\"true\">"
- + " <allowed-values>"
- + " <value int-value=\"0\" />"
- + " <value int-value=\"1\" />"
- + " </allowed-values>"
- + " <default-value int-value=\"1\" />"
- + " </setting>"
- + "</cec-settings>", null);
- hdmiCecConfig.registerChangeListener(
- HdmiControlManager.CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING,
- mSettingChangeListener);
- hdmiCecConfig.setIntValue(
- HdmiControlManager.CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING,
- HdmiControlManager.SYSTEM_AUDIO_MODE_MUTING_DISABLED);
- verify(mSettingChangeListener).onChange(
- HdmiControlManager.CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING);
- }
-
- @Test
- public void removeChangeListener_SharedPref_BasicSanity() {
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter,
- "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
- + "<cec-settings>"
- + " <setting name=\"system_audio_mode_muting\""
- + " value-type=\"int\""
- + " user-configurable=\"true\">"
- + " <allowed-values>"
- + " <value int-value=\"0\" />"
- + " <value int-value=\"1\" />"
- + " </allowed-values>"
- + " <default-value int-value=\"1\" />"
- + " </setting>"
- + "</cec-settings>", null);
- hdmiCecConfig.registerChangeListener(
- HdmiControlManager.CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING,
- mSettingChangeListener);
- hdmiCecConfig.removeChangeListener(
- HdmiControlManager.CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING,
- mSettingChangeListener);
- hdmiCecConfig.setIntValue(
- HdmiControlManager.CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING,
- HdmiControlManager.SYSTEM_AUDIO_MODE_MUTING_DISABLED);
- verify(mSettingChangeListener, never()).onChange(
- HdmiControlManager.CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING);
- }
-
- /**
- * Externally modified Global Settings still need to be supported. This test verifies that
- * setting change notification is being forwarded to listeners registered via HdmiCecConfig.
- */
- @Test
- public void globalSettingObserver_BasicSanity() throws Exception {
- CountDownLatch notifyLatch = new CountDownLatch(1);
- // Get current value of the setting in the system.
- String val = Global.getString(mContext.getContentResolver(), Global.HDMI_CONTROL_ENABLED);
- HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
- mContext, mStorageAdapter,
- "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
- + "<cec-settings>"
- + " <setting name=\"hdmi_cec_enabled\""
- + " value-type=\"int\""
- + " user-configurable=\"true\">"
- + " <allowed-values>"
- + " <value int-value=\"0\" />"
- + " <value int-value=\"1\" />"
- + " </allowed-values>"
- + " <default-value int-value=\"1\" />"
- + " </setting>"
- + "</cec-settings>", null);
- hdmiCecConfig.registerGlobalSettingsObserver(Looper.getMainLooper());
- HdmiCecConfig.SettingChangeListener latchUpdateListener =
- new HdmiCecConfig.SettingChangeListener() {
- @Override
- public void onChange(@NonNull @HdmiControlManager.CecSettingName String setting) {
- notifyLatch.countDown();
- assertThat(setting).isEqualTo(HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED);
- }
- };
- hdmiCecConfig.registerChangeListener(
- HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED,
- latchUpdateListener);
- // Flip the value of the setting.
- Global.putString(mContext.getContentResolver(), Global.HDMI_CONTROL_ENABLED,
- ((val == null || val.equals("1")) ? "0" : "1"));
- if (!notifyLatch.await(TIMEOUT_CONTENT_CHANGE_SEC, TimeUnit.SECONDS)) {
- fail("Timed out waiting for the notify callback");
- }
- hdmiCecConfig.unregisterGlobalSettingsObserver();
- // Restore the previous value of the setting in the system.
- Global.putString(mContext.getContentResolver(), Global.HDMI_CONTROL_ENABLED, val);
- }
}
diff --git a/services/tests/servicestests/src/com/android/server/om/OverlayManagerSettingsTests.java b/services/tests/servicestests/src/com/android/server/om/OverlayManagerSettingsTests.java
index 9ef755791c80..20f9b703e29d 100644
--- a/services/tests/servicestests/src/com/android/server/om/OverlayManagerSettingsTests.java
+++ b/services/tests/servicestests/src/com/android/server/om/OverlayManagerSettingsTests.java
@@ -27,6 +27,8 @@ import static org.junit.Assert.fail;
import android.content.om.OverlayInfo;
import android.text.TextUtils;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
import android.util.Xml;
import androidx.test.runner.AndroidJUnit4;
@@ -403,7 +405,7 @@ public class OverlayManagerSettingsTests {
private int countXmlTags(String xml, String tagToLookFor) throws Exception {
int count = 0;
- XmlPullParser parser = Xml.newPullParser();
+ TypedXmlPullParser parser = Xml.newFastPullParser();
parser.setInput(new StringReader(xml));
int event = parser.getEventType();
while (event != XmlPullParser.END_DOCUMENT) {
@@ -418,7 +420,7 @@ public class OverlayManagerSettingsTests {
private int countXmlAttributesWhere(String xml, String tag, String attr, String value)
throws Exception {
int count = 0;
- XmlPullParser parser = Xml.newPullParser();
+ TypedXmlPullParser parser = Xml.newFastPullParser();
parser.setInput(new StringReader(xml));
int event = parser.getEventType();
while (event != XmlPullParser.END_DOCUMENT) {
diff --git a/services/tests/servicestests/src/com/android/server/people/PeopleServiceTest.java b/services/tests/servicestests/src/com/android/server/people/PeopleServiceTest.java
index 9213e1fe5a25..a112b145fdc9 100644
--- a/services/tests/servicestests/src/com/android/server/people/PeopleServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/people/PeopleServiceTest.java
@@ -69,7 +69,7 @@ public final class PeopleServiceTest {
when(mCallback.asBinder()).thenReturn(new Binder());
PeopleService service = new PeopleService(mContext);
- service.onStart();
+ service.onStart(/* isForTesting= */ true);
mServiceInternal = LocalServices.getService(PeopleServiceInternal.class);
mLocalService = (PeopleService.LocalService) mServiceInternal;
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageInstallerSessionTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageInstallerSessionTest.java
index bbb83b6b46cf..11d00f0fd406 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageInstallerSessionTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageInstallerSessionTest.java
@@ -29,6 +29,8 @@ import android.util.AtomicFile;
import android.util.Slog;
import android.util.TypedXmlPullParser;
import android.util.TypedXmlSerializer;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
import android.util.Xml;
import androidx.test.runner.AndroidJUnit4;
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageSignaturesTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageSignaturesTest.java
index 89c3d5006347..90658055ad6f 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageSignaturesTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageSignaturesTest.java
@@ -25,6 +25,8 @@ import android.content.Context;
import android.content.pm.PackageParser;
import android.content.pm.Signature;
import android.util.TypedXmlPullParser;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
import android.util.Xml;
import androidx.test.InstrumentationRegistry;
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
index 194ae055e01f..23fcf701a8bb 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
@@ -98,6 +98,8 @@ import android.os.UserHandle;
import android.test.suitebuilder.annotation.SmallTest;
import android.util.Log;
import android.util.SparseArray;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
import android.util.Xml;
import com.android.frameworks.servicestests.R;
@@ -8695,7 +8697,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
// Write ShareTargets to Xml
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
- final XmlSerializer outXml = new FastXmlSerializer();
+ final TypedXmlSerializer outXml = Xml.newFastSerializer();
outXml.setOutput(outStream, StandardCharsets.UTF_8.name());
outXml.startDocument(null, true);
for (int i = 0; i < expectedValues.size(); i++) {
@@ -8706,7 +8708,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
// Read ShareTargets from Xml
ByteArrayInputStream inStream = new ByteArrayInputStream(outStream.toByteArray());
- XmlPullParser parser = Xml.newPullParser();
+ TypedXmlPullParser parser = Xml.newFastPullParser();
parser.setInput(new InputStreamReader(inStream));
List<ShareTargetInfo> shareTargets = new ArrayList<>();
int type;
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserInfoTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserInfoTest.java
index 4fac9dc391e3..dfc25e0c7cb6 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserInfoTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserInfoTest.java
@@ -21,6 +21,7 @@ import static android.content.pm.UserInfo.FLAG_DISABLED;
import static android.content.pm.UserInfo.FLAG_EPHEMERAL;
import static android.content.pm.UserInfo.FLAG_FULL;
import static android.content.pm.UserInfo.FLAG_GUEST;
+import static android.content.pm.UserInfo.FLAG_INITIALIZED;
import static android.content.pm.UserInfo.FLAG_MANAGED_PROFILE;
import static android.content.pm.UserInfo.FLAG_PROFILE;
import static android.content.pm.UserInfo.FLAG_RESTRICTED;
@@ -44,6 +45,7 @@ import android.content.pm.UserInfo.UserInfoFlag;
import android.os.Looper;
import android.os.Parcel;
import android.os.UserHandle;
+import android.os.UserManager;
import android.text.TextUtils;
import androidx.test.InstrumentationRegistry;
@@ -206,6 +208,8 @@ public class UserManagerServiceUserInfoTest {
@Test
public void testUpgradeIfNecessaryLP_9() {
final int versionToTest = 9;
+ // do not trigger a user type upgrade
+ final int userTypeVersion = UserTypeFactory.getUserTypeVersion();
mUserManagerService.putUserInfo(createUser(100, FLAG_MANAGED_PROFILE, null));
mUserManagerService.putUserInfo(createUser(101,
@@ -216,7 +220,7 @@ public class UserManagerServiceUserInfoTest {
mUserManagerService.putUserInfo(createUser(105, FLAG_SYSTEM | FLAG_FULL, null));
mUserManagerService.putUserInfo(createUser(106, FLAG_DEMO | FLAG_FULL, null));
- mUserManagerService.upgradeIfNecessaryLP(null, versionToTest - 1);
+ mUserManagerService.upgradeIfNecessaryLP(null, versionToTest - 1, userTypeVersion);
assertTrue(mUserManagerService.isUserOfType(100, USER_TYPE_PROFILE_MANAGED));
assertTrue((mUserManagerService.getUserInfo(100).flags & FLAG_PROFILE) != 0);
@@ -278,4 +282,86 @@ public class UserManagerServiceUserInfoTest {
two.convertedFromPreCreated);
}
}
+
+ /** Tests upgrading profile types */
+ @Test
+ public void testUpgradeProfileType_updateTypeAndFlags() {
+ final int userId = 42;
+ final String newUserTypeName = "new.user.type";
+ final String oldUserTypeName = USER_TYPE_PROFILE_MANAGED;
+
+ UserTypeDetails.Builder oldUserTypeBuilder = new UserTypeDetails.Builder()
+ .setName(oldUserTypeName)
+ .setBaseType(FLAG_PROFILE)
+ .setDefaultUserInfoPropertyFlags(FLAG_MANAGED_PROFILE)
+ .setMaxAllowedPerParent(32)
+ .setIconBadge(401)
+ .setBadgeColors(402, 403, 404)
+ .setBadgeLabels(23, 24, 25);
+ UserTypeDetails oldUserType = oldUserTypeBuilder.createUserTypeDetails();
+
+ UserInfo userInfo = createUser(userId,
+ oldUserType.getDefaultUserInfoFlags() | FLAG_INITIALIZED, oldUserTypeName);
+ mUserManagerService.putUserInfo(userInfo);
+
+ UserTypeDetails.Builder newUserTypeBuilder = new UserTypeDetails.Builder()
+ .setName(newUserTypeName)
+ .setBaseType(FLAG_PROFILE)
+ .setMaxAllowedPerParent(32)
+ .setIconBadge(401)
+ .setBadgeColors(402, 403, 404)
+ .setBadgeLabels(23, 24, 25);
+ UserTypeDetails newUserType = newUserTypeBuilder.createUserTypeDetails();
+
+ mUserManagerService.upgradeProfileToTypeLU(userInfo, newUserType);
+
+ assertTrue(mUserManagerService.isUserOfType(userId, newUserTypeName));
+ assertTrue((mUserManagerService.getUserInfo(userId).flags & FLAG_PROFILE) != 0);
+ assertTrue((mUserManagerService.getUserInfo(userId).flags & FLAG_MANAGED_PROFILE) == 0);
+ assertTrue((mUserManagerService.getUserInfo(userId).flags & FLAG_INITIALIZED) != 0);
+ }
+
+ @Test
+ public void testUpgradeProfileType_updateRestrictions() {
+ final int userId = 42;
+ final String newUserTypeName = "new.user.type";
+ final String oldUserTypeName = USER_TYPE_PROFILE_MANAGED;
+
+ UserTypeDetails.Builder oldUserTypeBuilder = new UserTypeDetails.Builder()
+ .setName(oldUserTypeName)
+ .setBaseType(FLAG_PROFILE)
+ .setDefaultUserInfoPropertyFlags(FLAG_MANAGED_PROFILE)
+ .setMaxAllowedPerParent(32)
+ .setIconBadge(401)
+ .setBadgeColors(402, 403, 404)
+ .setBadgeLabels(23, 24, 25);
+ UserTypeDetails oldUserType = oldUserTypeBuilder.createUserTypeDetails();
+
+ UserInfo userInfo = createUser(userId, oldUserType.getDefaultUserInfoFlags(),
+ oldUserTypeName);
+ mUserManagerService.putUserInfo(userInfo);
+ mUserManagerService.setUserRestriction(UserManager.DISALLOW_CAMERA, true, userId);
+ mUserManagerService.setUserRestriction(UserManager.DISALLOW_PRINTING, true, userId);
+
+ UserTypeDetails.Builder newUserTypeBuilder = new UserTypeDetails.Builder()
+ .setName(newUserTypeName)
+ .setBaseType(FLAG_PROFILE)
+ .setMaxAllowedPerParent(32)
+ .setIconBadge(401)
+ .setBadgeColors(402, 403, 404)
+ .setBadgeLabels(23, 24, 25)
+ .setDefaultRestrictions(
+ UserManagerServiceUserTypeTest.makeRestrictionsBundle(
+ UserManager.DISALLOW_WALLPAPER));
+ UserTypeDetails newUserType = newUserTypeBuilder.createUserTypeDetails();
+
+ mUserManagerService.upgradeProfileToTypeLU(userInfo, newUserType);
+
+ assertTrue(mUserManagerService.getUserRestrictions(userId).getBoolean(
+ UserManager.DISALLOW_PRINTING));
+ assertTrue(mUserManagerService.getUserRestrictions(userId).getBoolean(
+ UserManager.DISALLOW_CAMERA));
+ assertTrue(mUserManagerService.getUserRestrictions(userId).getBoolean(
+ UserManager.DISALLOW_WALLPAPER));
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserTypeTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserTypeTest.java
index 8e74c903534f..ee30f68de7a0 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserTypeTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserTypeTest.java
@@ -51,6 +51,8 @@ import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.List;
+
/**
* Tests for {@link UserTypeDetails} and {@link UserTypeFactory}.
*
@@ -358,13 +360,56 @@ public class UserManagerServiceUserTypeTest {
() -> UserTypeFactory.customizeBuilders(builders, parser));
}
+ @Test
+ public void testUserTypeFactoryVersion_versionMissing() {
+ final XmlResourceParser parser = mResources.getXml(R.xml.usertypes_test_eraseArray);
+ assertEquals(0, UserTypeFactory.getUserTypeVersion(parser));
+ }
+
+ @Test
+ public void testUserTypeFactoryVersion_versionPresent() {
+ final XmlResourceParser parser = mResources.getXml(R.xml.usertypes_test_profile);
+ assertEquals(1234, UserTypeFactory.getUserTypeVersion(parser));
+ }
+
+ @Test
+ public void testUserTypeFactoryUpgrades_validUpgrades() {
+ final ArrayMap<String, UserTypeDetails.Builder> builders = new ArrayMap<>();
+ builders.put("name", getMinimalBuilder());
+
+ final XmlResourceParser parser = mResources.getXml(R.xml.usertypes_test_profile);
+ List<UserTypeFactory.UserTypeUpgrade> upgrades = UserTypeFactory.parseUserUpgrades(builders,
+ parser);
+
+ assertFalse(upgrades.isEmpty());
+ UserTypeFactory.UserTypeUpgrade upgrade = upgrades.get(0);
+ assertEquals("android.test.1", upgrade.getFromType());
+ assertEquals("android.test.2", upgrade.getToType());
+ assertEquals(1233, upgrade.getUpToVersion());
+ }
+
+ @Test
+ public void testUserTypeFactoryUpgrades_illegalBaseTypeUpgrade() {
+ final String userTypeFull = "android.test.1";
+ final ArrayMap<String, UserTypeDetails.Builder> builders = new ArrayMap<>();
+ builders.put(userTypeFull, new UserTypeDetails.Builder()
+ .setName(userTypeFull)
+ .setBaseType(FLAG_FULL));
+
+ final XmlResourceParser parser = mResources.getXml(R.xml.usertypes_test_full);
+
+ // parser is illegal because the "to" upgrade type is not a profile, but a full user
+ assertThrows(IllegalArgumentException.class,
+ () -> UserTypeFactory.parseUserUpgrades(builders, parser));
+ }
+
/** Returns a minimal {@link UserTypeDetails.Builder} that can legitimately be created. */
private UserTypeDetails.Builder getMinimalBuilder() {
return new UserTypeDetails.Builder().setName("name").setBaseType(FLAG_FULL);
}
/** Creates a Bundle of the given String restrictions, each set to true. */
- private Bundle makeRestrictionsBundle(String ... restrictions) {
+ public static Bundle makeRestrictionsBundle(String ... restrictions) {
final Bundle bundle = new Bundle();
for (String restriction : restrictions) {
bundle.putBoolean(restriction, true);
diff --git a/services/tests/servicestests/src/com/android/server/search/SearchablesTest.java b/services/tests/servicestests/src/com/android/server/search/SearchablesTest.java
index 0f9bf2f6cd86..8bccce102887 100644
--- a/services/tests/servicestests/src/com/android/server/search/SearchablesTest.java
+++ b/services/tests/servicestests/src/com/android/server/search/SearchablesTest.java
@@ -367,7 +367,7 @@ public class SearchablesTest extends AndroidTestCase {
* for you if needed; if you already have this information around, it can
* be much more efficient to supply it here.
*
- * @return Returns an XmlPullParser allowing you to parse out the XML
+ * @return Returns an TypedXmlPullParser allowing you to parse out the XML
* data. Returns null if the xml resource could not be found for any
* reason.
*/
diff --git a/services/tests/servicestests/src/com/android/server/storage/CacheQuotaStrategyTest.java b/services/tests/servicestests/src/com/android/server/storage/CacheQuotaStrategyTest.java
index 1d62e01c068d..7ac493828610 100644
--- a/services/tests/servicestests/src/com/android/server/storage/CacheQuotaStrategyTest.java
+++ b/services/tests/servicestests/src/com/android/server/storage/CacheQuotaStrategyTest.java
@@ -21,6 +21,8 @@ import static com.google.common.truth.Truth.assertThat;
import android.app.usage.CacheQuotaHint;
import android.test.AndroidTestCase;
import android.util.Pair;
+import android.util.TypedXmlSerializer;
+import android.util.Xml;
import com.android.internal.util.FastXmlSerializer;
@@ -37,12 +39,12 @@ import java.util.List;
@RunWith(JUnit4.class)
public class CacheQuotaStrategyTest extends AndroidTestCase {
StringWriter mWriter;
- FastXmlSerializer mOut;
+ TypedXmlSerializer mOut;
@Before
public void setUp() throws Exception {
mWriter = new StringWriter();
- mOut = new FastXmlSerializer();
+ mOut = Xml.newFastSerializer();
mOut.setOutput(mWriter);
}
diff --git a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java
index c23fb8028224..21396fd0516e 100644
--- a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java
@@ -525,6 +525,7 @@ public class TimeDetectorStrategyImplTest {
@Test
public void testSuggestNetworkTime_autoTimeEnabled() {
mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO)
+ .pokeAutoOriginPriorities(ORIGIN_NETWORK)
.pokeAutoTimeDetectionEnabled(true);
NetworkTimeSuggestion timeSuggestion =
@@ -541,6 +542,7 @@ public class TimeDetectorStrategyImplTest {
@Test
public void testSuggestNetworkTime_autoTimeDisabled() {
mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO)
+ .pokeAutoOriginPriorities(ORIGIN_NETWORK)
.pokeAutoTimeDetectionEnabled(false);
NetworkTimeSuggestion timeSuggestion =
@@ -552,10 +554,26 @@ public class TimeDetectorStrategyImplTest {
}
@Test
- public void testSuggestNetworkTime_telephonySuggestionsBeatNetworkSuggestions() {
+ public void networkTimeSuggestion_ignoredWhenReferencedTimeIsInThePast() {
mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO)
+ .pokeAutoOriginPriorities(ORIGIN_NETWORK)
.pokeAutoTimeDetectionEnabled(true);
+ Instant suggestedTime = TIME_LOWER_BOUND.minus(Duration.ofDays(1));
+ NetworkTimeSuggestion timeSuggestion = mScript
+ .generateNetworkTimeSuggestion(suggestedTime);
+
+ mScript.simulateNetworkTimeSuggestion(timeSuggestion)
+ .verifySystemClockWasNotSetAndResetCallTracking()
+ .assertLatestNetworkSuggestion(null);
+ }
+
+ @Test
+ public void highPrioritySuggestionsShouldBeatLowerPrioritySuggestions() {
+ mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO)
+ .pokeAutoTimeDetectionEnabled(true)
+ .pokeAutoOriginPriorities(ORIGIN_TELEPHONY, ORIGIN_NETWORK);
+
// Three obviously different times that could not be mistaken for each other.
Instant networkTime1 = ARBITRARY_TEST_TIME;
Instant networkTime2 = ARBITRARY_TEST_TIME.plus(Duration.ofDays(30));
@@ -576,7 +594,7 @@ public class TimeDetectorStrategyImplTest {
mScript.assertLatestTelephonySuggestion(ARBITRARY_SLOT_INDEX, null)
.assertLatestNetworkSuggestion(networkTimeSuggestion1);
assertEquals(networkTimeSuggestion1, mScript.peekLatestValidNetworkSuggestion());
- assertNull(mScript.peekBestTelephonySuggestion());
+ assertNull("No telephony suggestions were made:", mScript.peekBestTelephonySuggestion());
// Simulate a little time passing.
mScript.simulateTimePassing(smallTimeIncrementMillis)
@@ -631,7 +649,9 @@ public class TimeDetectorStrategyImplTest {
mScript.assertLatestTelephonySuggestion(ARBITRARY_SLOT_INDEX, telephonyTimeSuggestion)
.assertLatestNetworkSuggestion(networkTimeSuggestion2);
assertEquals(networkTimeSuggestion2, mScript.peekLatestValidNetworkSuggestion());
- assertNull(mScript.peekBestTelephonySuggestion());
+ assertNull(
+ "Telephony suggestion should be expired:",
+ mScript.peekBestTelephonySuggestion());
// Toggle auto-time off and on to force the detection logic to run.
mScript.simulateAutoTimeDetectionToggle()
@@ -646,27 +666,16 @@ public class TimeDetectorStrategyImplTest {
mScript.assertLatestTelephonySuggestion(ARBITRARY_SLOT_INDEX, telephonyTimeSuggestion)
.assertLatestNetworkSuggestion(networkTimeSuggestion2);
assertEquals(networkTimeSuggestion2, mScript.peekLatestValidNetworkSuggestion());
- assertNull(mScript.peekBestTelephonySuggestion());
- }
-
- @Test
- public void networkTimeSuggestion_ignoredWhenReferencedTimeIsInThePast() {
- mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO)
- .pokeAutoTimeDetectionEnabled(true);
-
- Instant suggestedTime = TIME_LOWER_BOUND.minus(Duration.ofDays(1));
- NetworkTimeSuggestion timeSuggestion = mScript
- .generateNetworkTimeSuggestion(suggestedTime);
-
- mScript.simulateNetworkTimeSuggestion(timeSuggestion)
- .verifySystemClockWasNotSetAndResetCallTracking()
- .assertLatestNetworkSuggestion(null);
+ assertNull(
+ "Telephony suggestion should still be expired:",
+ mScript.peekBestTelephonySuggestion());
}
@Test
public void whenAllTimeSuggestionsAreAvailable_higherPriorityWins_lowerPriorityComesFirst() {
mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO)
- .pokeAutoTimeDetectionEnabled(true);
+ .pokeAutoTimeDetectionEnabled(true)
+ .pokeAutoOriginPriorities(ORIGIN_TELEPHONY, ORIGIN_NETWORK);
Instant networkTime = ARBITRARY_TEST_TIME;
Instant telephonyTime = ARBITRARY_TEST_TIME.plus(Duration.ofDays(30));
@@ -686,7 +695,8 @@ public class TimeDetectorStrategyImplTest {
@Test
public void whenAllTimeSuggestionsAreAvailable_higherPriorityWins_higherPriorityComesFirst() {
mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO)
- .pokeAutoTimeDetectionEnabled(true);
+ .pokeAutoTimeDetectionEnabled(true)
+ .pokeAutoOriginPriorities(ORIGIN_TELEPHONY, ORIGIN_NETWORK);
Instant networkTime = ARBITRARY_TEST_TIME;
Instant telephonyTime = ARBITRARY_TEST_TIME.plus(Duration.ofDays(30));
@@ -706,7 +716,8 @@ public class TimeDetectorStrategyImplTest {
@Test
public void whenHighestPrioritySuggestionIsNotAvailable_fallbacksToNext() {
mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO)
- .pokeAutoTimeDetectionEnabled(true);
+ .pokeAutoTimeDetectionEnabled(true)
+ .pokeAutoOriginPriorities(ORIGIN_TELEPHONY, ORIGIN_NETWORK);
NetworkTimeSuggestion timeSuggestion =
mScript.generateNetworkTimeSuggestion(ARBITRARY_TEST_TIME);
@@ -720,7 +731,7 @@ public class TimeDetectorStrategyImplTest {
public void suggestionsFromSourceNotListedInPrioritiesList_areIgnored() {
mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO)
.pokeAutoTimeDetectionEnabled(true)
- .pokeAutoOriginPriorities(new int[]{ORIGIN_TELEPHONY});
+ .pokeAutoOriginPriorities(ORIGIN_TELEPHONY);
NetworkTimeSuggestion timeSuggestion = mScript.generateNetworkTimeSuggestion(
ARBITRARY_TEST_TIME);
@@ -730,6 +741,19 @@ public class TimeDetectorStrategyImplTest {
.verifySystemClockWasNotSetAndResetCallTracking();
}
+ @Test
+ public void autoOriginPrioritiesList_doesNotAffectManualSuggestion() {
+ mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO)
+ .pokeAutoTimeDetectionEnabled(false)
+ .pokeAutoOriginPriorities(ORIGIN_TELEPHONY);
+
+ ManualTimeSuggestion timeSuggestion =
+ mScript.generateManualTimeSuggestion(ARBITRARY_TEST_TIME);
+
+ mScript.simulateManualTimeSuggestion(timeSuggestion, true /* expectedResult */)
+ .verifySystemClockWasSetAndResetCallTracking(ARBITRARY_TEST_TIME.toEpochMilli());
+ }
+
/**
* A fake implementation of TimeDetectorStrategy.Callback. Besides tracking changes and behaving
* like the real thing should, it also asserts preconditions.
@@ -761,7 +785,7 @@ public class TimeDetectorStrategyImplTest {
}
@Override
- public int[] getAutoOriginPriorities() {
+ public int[] autoOriginPriorities() {
return mAutoOriginPriorities;
}
@@ -886,8 +910,8 @@ public class TimeDetectorStrategyImplTest {
return this;
}
- Script pokeAutoOriginPriorities(@Origin int[] autoOriginPriorites) {
- mFakeCallback.pokeAutoOriginPriorities(autoOriginPriorites);
+ Script pokeAutoOriginPriorities(@Origin int... autoOriginPriorities) {
+ mFakeCallback.pokeAutoOriginPriorities(autoOriginPriorities);
return this;
}
diff --git a/services/tests/servicestests/src/com/android/server/utils/WatchableTester.java b/services/tests/servicestests/src/com/android/server/utils/WatchableTester.java
new file mode 100644
index 000000000000..590df3c18f5a
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/utils/WatchableTester.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.utils;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * A class to count the number of notifications received.
+ */
+public class WatchableTester extends Watcher {
+
+ // The count of changes.
+ public int mChanges = 0;
+
+ // The change count at the last verifyChangeReported() call.
+ public int mLastChangeCount = 0;
+
+ // The single Watchable that this monitors.
+ public final Watchable mWatched;
+
+ // The key, used for messages
+ public String mKey;
+
+ // Clear the changes count, for when the tester is reused.
+ public void clear() {
+ mChanges = 0;
+ }
+
+ /**
+ * Create the WatchableTester with a Watcher and a key. The key is used for logging
+ * test failures.
+ * @param w The {@link Watchable} under test
+ * @param k A key that is prefixed to any test failures.
+ **/
+ public WatchableTester(Watchable w, String k) {
+ mWatched = w;
+ mKey = k;
+ }
+
+ // Listen for events
+ public void register() {
+ mWatched.registerObserver(this);
+ }
+
+ // Stop listening for events
+ public void unregister() {
+ mWatched.unregisterObserver(this);
+ }
+
+ // Count the number of notifications received.
+ @Override
+ public void onChange(Watchable what) {
+ mChanges++;
+ }
+
+ // Verify the count.
+ public void verify(int want, String msg) {
+ assertEquals(mKey + " " + msg, want, mChanges);
+ }
+
+ // Verify that at least one change was reported since the last verify. The actual
+ // number of changes is not important. This resets the count of changes.
+ public void verifyChangeReported(String msg) {
+ assertTrue(mKey + " " + msg, mLastChangeCount < mChanges);
+ mLastChangeCount = mChanges;
+ }
+
+ // Verify that no change was reported since the last verify.
+ public void verifyNoChangeReported(String msg) {
+ assertTrue(mKey + " " + msg, mLastChangeCount == mChanges);
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/utils/WatcherTest.java b/services/tests/servicestests/src/com/android/server/utils/WatcherTest.java
index 40575e4cf16f..9bea9d4cedbd 100644
--- a/services/tests/servicestests/src/com/android/server/utils/WatcherTest.java
+++ b/services/tests/servicestests/src/com/android/server/utils/WatcherTest.java
@@ -18,15 +18,10 @@ package com.android.server.utils;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
-
-import android.content.Context;
-import android.platform.test.annotations.Presubmit;
+import static org.junit.Assert.fail;
import androidx.test.filters.SmallTest;
-import com.android.internal.util.Preconditions;
-import com.android.internal.util.TraceBuffer;
-
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@@ -42,56 +37,76 @@ import org.junit.Test;
@SmallTest
public class WatcherTest {
+ // A counter to generate unique IDs for Leaf elements.
+ private int mLeafId = 0;
+
+ // Useful indices used int the tests.
+ private static final int INDEX_A = 1;
+ private static final int INDEX_B = 2;
+ private static final int INDEX_C = 3;
+ private static final int INDEX_D = 4;
+
// A small Watchable leaf node
- private class Leaf extends WatchableImpl {
- private int datum = 0;
+ private class Leaf extends WatchableImpl implements Snappable {
+ private int mId;
+ private int mDatum;
+
+ Leaf() {
+ mDatum = 0;
+ mId = mLeafId++;
+ }
+
void set(int i) {
- if (datum != i) {
- datum = i;
+ if (mDatum != i) {
+ mDatum = i;
dispatchChange(this);
}
}
+ int get() {
+ return mDatum;
+ }
void tick() {
- set(datum + 1);
+ set(mDatum + 1);
}
- }
-
- // A top-most watcher. It counts the number of notifications that it receives.
- private class Tester extends Watcher {
- // The count of changes.
- public int changes = 0;
-
- // The single Watchable that this monitors.
- public final Watchable mWatched;
-
- // The key, used for messages
- public String mKey;
-
- // Create the Tester with a Watcher
- public Tester(Watchable w, String k) {
- mWatched = w;
- mKey = k;
+ public Leaf snapshot() {
+ Leaf result = new Leaf();
+ result.mDatum = mDatum;
+ result.mId = mId;
+ result.seal();
+ return result;
}
-
- // Listen for events
- public void register() {
- mWatched.registerObserver(this);
+ @Override
+ public boolean equals(Object o) {
+ if (o instanceof Leaf) {
+ return mDatum == ((Leaf) o).mDatum && mId == ((Leaf) o).mId;
+ } else {
+ return false;
+ }
}
-
- // Stop listening for events
- public void unregister() {
- mWatched.unregisterObserver(this);
+ @Override
+ public String toString() {
+ return "Leaf(" + mDatum + "," + mId + ")";
}
+ }
- // Count the number of notifications received.
- @Override
- public void onChange(Watchable what) {
- changes++;
+ // Execute the {@link Runnable} and if {@link UnsupportedOperationException} is
+ // thrown, do nothing. If no exception is thrown, fail the test.
+ private void verifySealed(String msg, Runnable test) {
+ try {
+ test.run();
+ fail(msg + " should be sealed");
+ } catch (IllegalStateException e) {
+ // The exception was expected.
}
+ }
- // Verify the count.
- public void verify(int want, String msg) {
- assertEquals(mKey + " " + msg, want, changes);
+ // Execute the {@link Runnable} and if {@link UnsupportedOperationException} is
+ // thrown, fail the test. If no exception is thrown, do nothing.
+ private void verifyNotSealed(String msg, Runnable test) {
+ try {
+ test.run();
+ } catch (IllegalStateException e) {
+ fail(msg + " should be not sealed");
}
}
@@ -104,168 +119,212 @@ public class WatcherTest {
}
@Test
- public void test_notify() {
-
- Tester tester;
+ public void testBasicBehavior() {
+ WatchableTester tester;
// Create a few leaves
- Leaf a = new Leaf();
- Leaf b = new Leaf();
- Leaf c = new Leaf();
- Leaf d = new Leaf();
+ Leaf leafA = new Leaf();
// Basic test. Create a leaf and verify that changes to the leaf get notified to
// the tester.
- tester = new Tester(a, "Leaf");
+ tester = new WatchableTester(leafA, "Leaf");
tester.verify(0, "Initial leaf - no registration");
- a.tick();
+ leafA.tick();
tester.verify(0, "Updates with no registration");
tester.register();
- a.tick();
+ leafA.tick();
tester.verify(1, "Updates with registration");
- a.tick();
- a.tick();
+ leafA.tick();
+ leafA.tick();
tester.verify(3, "Updates with registration");
+ // Create a snapshot. Verify that the snapshot matches the
+ Leaf leafASnapshot = leafA.snapshot();
+ assertEquals("Leaf snapshot", leafA.get(), leafASnapshot.get());
+ leafA.tick();
+ assertTrue(leafA.get() != leafASnapshot.get());
+ tester.verify(4, "Tick after snapshot");
+ verifySealed("Leaf", ()->leafASnapshot.tick());
// Add the same leaf to more than one tester. Verify that a change to the leaf is seen by
// all registered listeners.
- Tester buddy1 = new Tester(a, "Leaf2");
- Tester buddy2 = new Tester(a, "Leaf3");
+ tester.clear();
+ WatchableTester buddy1 = new WatchableTester(leafA, "Leaf2");
+ WatchableTester buddy2 = new WatchableTester(leafA, "Leaf3");
buddy1.verify(0, "Initial leaf - no registration");
buddy2.verify(0, "Initial leaf - no registration");
- a.tick();
- tester.verify(4, "Updates with buddies");
+ leafA.tick();
+ tester.verify(1, "Updates with buddies");
buddy1.verify(0, "Updates - no registration");
buddy2.verify(0, "Updates - no registration");
buddy1.register();
buddy2.register();
buddy1.verify(0, "No updates - registered");
buddy2.verify(0, "No updates - registered");
- a.tick();
+ leafA.tick();
buddy1.verify(1, "First update");
buddy2.verify(1, "First update");
buddy1.unregister();
- a.tick();
+ leafA.tick();
buddy1.verify(1, "Second update - unregistered");
buddy2.verify(2, "Second update");
+ }
- buddy1 = null;
- buddy2 = null;
+ @Test
+ public void testWatchedArrayMap() {
+ WatchableTester tester;
- final int INDEX_A = 1;
- final int INDEX_B = 2;
- final int INDEX_C = 3;
- final int INDEX_D = 4;
+ // Create a few leaves
+ Leaf leafA = new Leaf();
+ Leaf leafB = new Leaf();
+ Leaf leafC = new Leaf();
+ Leaf leafD = new Leaf();
// Test WatchedArrayMap
- WatchedArrayMap<Integer, Leaf> am = new WatchedArrayMap<>();
- am.put(INDEX_A, a);
- am.put(INDEX_B, b);
- tester = new Tester(am, "WatchedArrayMap");
+ WatchedArrayMap<Integer, Leaf> array = new WatchedArrayMap<>();
+ array.put(INDEX_A, leafA);
+ array.put(INDEX_B, leafB);
+ tester = new WatchableTester(array, "WatchedArrayMap");
tester.verify(0, "Initial array - no registration");
- a.tick();
+ leafA.tick();
tester.verify(0, "Updates with no registration");
tester.register();
tester.verify(0, "Updates with no registration");
- a.tick();
+ leafA.tick();
tester.verify(1, "Updates with registration");
- b.tick();
+ leafB.tick();
tester.verify(2, "Updates with registration");
- am.remove(INDEX_B);
+ array.remove(INDEX_B);
tester.verify(3, "Removed b");
- b.tick();
+ leafB.tick();
tester.verify(3, "Updates with b not watched");
- am.put(INDEX_B, b);
- am.put(INDEX_C, b);
+ array.put(INDEX_B, leafB);
+ array.put(INDEX_C, leafB);
tester.verify(5, "Added b twice");
- b.tick();
+ leafB.tick();
tester.verify(6, "Changed b - single notification");
- am.remove(INDEX_C);
+ array.remove(INDEX_C);
tester.verify(7, "Removed first b");
- b.tick();
+ leafB.tick();
tester.verify(8, "Changed b - single notification");
- am.remove(INDEX_B);
+ array.remove(INDEX_B);
tester.verify(9, "Removed second b");
- b.tick();
+ leafB.tick();
tester.verify(9, "Updated b - no change");
- am.clear();
+ array.clear();
tester.verify(10, "Cleared array");
- b.tick();
+ leafB.tick();
tester.verify(10, "Change to b not in array");
// Special methods
- am.put(INDEX_C, c);
+ array.put(INDEX_C, leafC);
tester.verify(11, "Added c");
- c.tick();
+ leafC.tick();
tester.verify(12, "Ticked c");
- am.setValueAt(am.indexOfKey(INDEX_C), d);
+ array.setValueAt(array.indexOfKey(INDEX_C), leafD);
tester.verify(13, "Replaced c with d");
- c.tick();
- d.tick();
+ leafC.tick();
+ leafD.tick();
tester.verify(14, "Ticked d and c (c not registered)");
- am = null;
+ // Snapshot
+ {
+ final WatchedArrayMap<Integer, Leaf> arraySnap = array.snapshot();
+ tester.verify(14, "Generate snapshot (no changes)");
+ // Verify that the snapshot is a proper copy of the source.
+ assertEquals("WatchedArrayMap snap same size",
+ array.size(), arraySnap.size());
+ for (int i = 0; i < array.size(); i++) {
+ for (int j = 0; j < arraySnap.size(); j++) {
+ assertTrue("WatchedArrayMap elements differ",
+ array.valueAt(i) != arraySnap.valueAt(j));
+ }
+ assertTrue("WatchedArrayMap element copy",
+ array.valueAt(i).equals(arraySnap.valueAt(i)));
+ }
+ leafD.tick();
+ tester.verify(15, "Tick after snapshot");
+ // Verify that the snapshot is sealed
+ verifySealed("WatchedArrayMap", ()->arraySnap.put(INDEX_A, leafA));
+ }
+ // Recreate the snapshot since the test corrupted it.
+ {
+ final WatchedArrayMap<Integer, Leaf> arraySnap = array.snapshot();
+ // Verify that elements are also snapshots
+ final Leaf arraySnapElement = arraySnap.valueAt(0);
+ verifySealed("ArraySnapshotElement", ()->arraySnapElement.tick());
+ }
+ }
+
+ @Test
+ public void testWatchedSparseArray() {
+ WatchableTester tester;
+
+ // Create a few leaves
+ Leaf leafA = new Leaf();
+ Leaf leafB = new Leaf();
+ Leaf leafC = new Leaf();
+ Leaf leafD = new Leaf();
// Test WatchedSparseArray
- WatchedSparseArray<Leaf> sa = new WatchedSparseArray<>();
- sa.put(INDEX_A, a);
- sa.put(INDEX_B, b);
- tester = new Tester(sa, "WatchedSparseArray");
+ WatchedSparseArray<Leaf> array = new WatchedSparseArray<>();
+ array.put(INDEX_A, leafA);
+ array.put(INDEX_B, leafB);
+ tester = new WatchableTester(array, "WatchedSparseArray");
tester.verify(0, "Initial array - no registration");
- a.tick();
+ leafA.tick();
tester.verify(0, "Updates with no registration");
tester.register();
tester.verify(0, "Updates with no registration");
- a.tick();
+ leafA.tick();
tester.verify(1, "Updates with registration");
- b.tick();
+ leafB.tick();
tester.verify(2, "Updates with registration");
- sa.remove(INDEX_B);
+ array.remove(INDEX_B);
tester.verify(3, "Removed b");
- b.tick();
+ leafB.tick();
tester.verify(3, "Updates with b not watched");
- sa.put(INDEX_B, b);
- sa.put(INDEX_C, b);
+ array.put(INDEX_B, leafB);
+ array.put(INDEX_C, leafB);
tester.verify(5, "Added b twice");
- b.tick();
+ leafB.tick();
tester.verify(6, "Changed b - single notification");
- sa.remove(INDEX_C);
+ array.remove(INDEX_C);
tester.verify(7, "Removed first b");
- b.tick();
+ leafB.tick();
tester.verify(8, "Changed b - single notification");
- sa.remove(INDEX_B);
+ array.remove(INDEX_B);
tester.verify(9, "Removed second b");
- b.tick();
- tester.verify(9, "Updated b - no change");
- sa.clear();
+ leafB.tick();
+ tester.verify(9, "Updated leafB - no change");
+ array.clear();
tester.verify(10, "Cleared array");
- b.tick();
+ leafB.tick();
tester.verify(10, "Change to b not in array");
// Special methods
- sa.put(INDEX_A, a);
- sa.put(INDEX_B, b);
- sa.put(INDEX_C, c);
+ array.put(INDEX_A, leafA);
+ array.put(INDEX_B, leafB);
+ array.put(INDEX_C, leafC);
tester.verify(13, "Added c");
- c.tick();
+ leafC.tick();
tester.verify(14, "Ticked c");
- sa.setValueAt(sa.indexOfKey(INDEX_C), d);
+ array.setValueAt(array.indexOfKey(INDEX_C), leafD);
tester.verify(15, "Replaced c with d");
- c.tick();
- d.tick();
+ leafC.tick();
+ leafD.tick();
tester.verify(16, "Ticked d and c (c not registered)");
- sa.append(INDEX_D, c);
+ array.append(INDEX_D, leafC);
tester.verify(17, "Append c");
- c.tick();
- d.tick();
+ leafC.tick();
+ leafD.tick();
tester.verify(19, "Ticked d and c");
- assertEquals("Verify four elements", 4, sa.size());
+ assertEquals("Verify four elements", 4, array.size());
// Figure out which elements are at which indices.
Leaf[] x = new Leaf[4];
for (int i = 0; i < 4; i++) {
- x[i] = sa.valueAt(i);
+ x[i] = array.valueAt(i);
}
- sa.removeAtRange(0, 2);
+ array.removeAtRange(0, 2);
tester.verify(20, "Removed two elements in one operation");
x[0].tick();
x[1].tick();
@@ -274,31 +333,77 @@ public class WatcherTest {
x[3].tick();
tester.verify(22, "Ticked two remaining elements");
- sa = null;
+ // Snapshot
+ {
+ final WatchedSparseArray<Leaf> arraySnap = array.snapshot();
+ tester.verify(22, "Generate snapshot (no changes)");
+ // Verify that the snapshot is a proper copy of the source.
+ assertEquals("WatchedSparseArray snap same size",
+ array.size(), arraySnap.size());
+ for (int i = 0; i < array.size(); i++) {
+ for (int j = 0; j < arraySnap.size(); j++) {
+ assertTrue("WatchedSparseArray elements differ",
+ array.valueAt(i) != arraySnap.valueAt(j));
+ }
+ assertTrue("WatchedArrayMap element copy",
+ array.valueAt(i).equals(arraySnap.valueAt(i)));
+ }
+ leafD.tick();
+ tester.verify(23, "Tick after snapshot");
+ // Verify that the array snapshot is sealed
+ verifySealed("WatchedSparseArray", ()->arraySnap.put(INDEX_A, leafB));
+ }
+ // Recreate the snapshot since the test corrupted it.
+ {
+ final WatchedSparseArray<Leaf> arraySnap = array.snapshot();
+ // Verify that elements are also snapshots
+ final Leaf arraySnapElement = arraySnap.valueAt(0);
+ verifySealed("ArraySnapshotElement", ()->arraySnapElement.tick());
+ }
+ }
+
+ @Test
+ public void testWatchedSparseBooleanArray() {
+ WatchableTester tester;
// Test WatchedSparseBooleanArray
- WatchedSparseBooleanArray sb = new WatchedSparseBooleanArray();
- tester = new Tester(sb, "WatchedSparseBooleanArray");
+ WatchedSparseBooleanArray array = new WatchedSparseBooleanArray();
+ tester = new WatchableTester(array, "WatchedSparseBooleanArray");
tester.verify(0, "Initial array - no registration");
- sb.put(INDEX_A, true);
+ array.put(INDEX_A, true);
tester.verify(0, "Updates with no registration");
tester.register();
tester.verify(0, "Updates with no registration");
- sb.put(INDEX_B, true);
+ array.put(INDEX_B, true);
tester.verify(1, "Updates with registration");
- sb.put(INDEX_B, true);
+ array.put(INDEX_B, true);
tester.verify(1, "Null update");
- sb.put(INDEX_B, false);
- sb.put(INDEX_C, true);
+ array.put(INDEX_B, false);
+ array.put(INDEX_C, true);
tester.verify(3, "Updates with registration");
// Special methods
- sb.put(INDEX_C, true);
+ array.put(INDEX_C, true);
tester.verify(3, "Added true, no change");
- sb.setValueAt(sb.indexOfKey(INDEX_C), false);
+ array.setValueAt(array.indexOfKey(INDEX_C), false);
tester.verify(4, "Replaced true with false");
- sb.append(INDEX_D, true);
+ array.append(INDEX_D, true);
tester.verify(5, "Append true");
- sb = null;
+ // Snapshot
+ {
+ WatchedSparseBooleanArray arraySnap = array.snapshot();
+ tester.verify(5, "Generate snapshot");
+ // Verify that the snapshot is a proper copy of the source.
+ assertEquals("WatchedSparseBooleanArray snap same size",
+ array.size(), arraySnap.size());
+ for (int i = 0; i < array.size(); i++) {
+ assertEquals("WatchedSparseArray element copy",
+ array.valueAt(i), arraySnap.valueAt(i));
+ }
+ array.put(INDEX_D, false);
+ tester.verify(6, "Tick after snapshot");
+ // Verify that the array is sealed
+ verifySealed("WatchedSparseBooleanArray", ()->arraySnap.put(INDEX_D, false));
+ }
}
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/utils/FakeDeviceConfigInterface.java b/services/tests/servicestests/utils/com/android/server/testutils/FakeDeviceConfigInterface.java
index 2904a5b73646..a67f64596ef5 100644
--- a/services/tests/wmtests/src/com/android/server/wm/utils/FakeDeviceConfigInterface.java
+++ b/services/tests/servicestests/utils/com/android/server/testutils/FakeDeviceConfigInterface.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.wm.utils;
+package com.android.server.testutils;
import android.annotation.NonNull;
import android.provider.DeviceConfig;
@@ -22,6 +22,7 @@ import android.util.ArrayMap;
import android.util.Pair;
import com.android.internal.util.Preconditions;
+import com.android.server.utils.DeviceConfigInterface;
import java.lang.reflect.Constructor;
import java.util.HashMap;
@@ -122,6 +123,19 @@ public class FakeDeviceConfigInterface implements DeviceConfigInterface {
}
@Override
+ public float getFloat(String namespace, String name, float defaultValue) {
+ String value = getProperty(namespace, name);
+ if (value == null) {
+ return defaultValue;
+ }
+ try {
+ return Float.parseFloat(value);
+ } catch (NumberFormatException e) {
+ return defaultValue;
+ }
+ }
+
+ @Override
public boolean getBoolean(String namespace, String name, boolean defaultValue) {
String value = getProperty(namespace, name);
return value != null ? Boolean.parseBoolean(value) : defaultValue;
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java
index c50792866582..4a4d9bc174fb 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java
@@ -54,6 +54,8 @@ import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.IntArray;
import android.util.SparseArray;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
import android.util.Xml;
import com.android.internal.util.FastXmlSerializer;
@@ -267,7 +269,7 @@ public class ManagedServicesTest extends UiServiceTestCase {
mIpm, approvalLevel);
// approved services aren't in xml
- XmlPullParser parser = Xml.newPullParser();
+ TypedXmlPullParser parser = Xml.newFastPullParser();
parser.setInput(new BufferedInputStream(new ByteArrayInputStream(new byte[]{})),
null);
writeExpectedValuesToSettings(approvalLevel);
@@ -335,7 +337,7 @@ public class ManagedServicesTest extends UiServiceTestCase {
String testComponent = "user.test.component/C1";
String resolvedValue =
(approvalLevel == APPROVAL_BY_COMPONENT) ? testComponent : testPackage;
- XmlPullParser parser =
+ TypedXmlPullParser parser =
getParserWithEntries(service, getXmlEntry(resolvedValue, 0, true));
service.readXml(parser, null, true, 10);
@@ -357,7 +359,7 @@ public class ManagedServicesTest extends UiServiceTestCase {
String resolvedValue =
(approvalLevel == APPROVAL_BY_COMPONENT) ? testComponent : testPackage;
String xmlEntry = getXmlEntry(resolvedValue, 0, true, false);
- XmlPullParser parser = getParserWithEntries(service, xmlEntry);
+ TypedXmlPullParser parser = getParserWithEntries(service, xmlEntry);
service.readXml(parser, null, true, 0);
@@ -384,7 +386,7 @@ public class ManagedServicesTest extends UiServiceTestCase {
ManagedServices service2 =
new TestManagedServices(
getContext(), mLock, mUserProfiles, mIpm, APPROVAL_BY_COMPONENT);
- XmlSerializer serializer = new FastXmlSerializer();
+ TypedXmlSerializer serializer = Xml.newFastSerializer();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
BufferedOutputStream outStream = new BufferedOutputStream(baos);
serializer.setOutput(outStream, "utf-8");
@@ -396,7 +398,7 @@ public class ManagedServicesTest extends UiServiceTestCase {
serializer.endDocument();
outStream.flush();
- final XmlPullParser parser = Xml.newPullParser();
+ final TypedXmlPullParser parser = Xml.newFastPullParser();
BufferedInputStream input = new BufferedInputStream(
new ByteArrayInputStream(baos.toByteArray()));
@@ -536,7 +538,7 @@ public class ManagedServicesTest extends UiServiceTestCase {
service,
Collections.singletonList(service.getPackageName(resolvedValue10)),
10);
- XmlPullParser parser =
+ TypedXmlPullParser parser =
getParserWithEntries(
service,
getXmlEntry(resolvedValue0, 0, true),
@@ -544,7 +546,7 @@ public class ManagedServicesTest extends UiServiceTestCase {
service.readXml(parser, null, false, UserHandle.USER_ALL);
// Write backup.
- XmlSerializer serializer = new FastXmlSerializer();
+ TypedXmlSerializer serializer = Xml.newFastSerializer();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
serializer.setOutput(new BufferedOutputStream(baos), "utf-8");
serializer.startDocument(null, true);
@@ -557,7 +559,7 @@ public class ManagedServicesTest extends UiServiceTestCase {
service.setPackageOrComponentEnabled(resolvedValue10, 10, true, false);
// Parse backup via restore.
- XmlPullParser restoreParser = Xml.newPullParser();
+ TypedXmlPullParser restoreParser = Xml.newFastPullParser();
restoreParser.setInput(
new BufferedInputStream(new ByteArrayInputStream(baos.toByteArray())), null);
restoreParser.nextTag();
@@ -608,7 +610,7 @@ public class ManagedServicesTest extends UiServiceTestCase {
addExpectedServices(service, entriesExpectedToHaveServices, userInfo.id);
}
- XmlSerializer serializer = new FastXmlSerializer();
+ TypedXmlSerializer serializer = Xml.newFastSerializer();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
serializer.setOutput(new BufferedOutputStream(baos), "utf-8");
serializer.startDocument(null, true);
@@ -618,7 +620,7 @@ public class ManagedServicesTest extends UiServiceTestCase {
serializer.endDocument();
serializer.flush();
- XmlPullParser parser = Xml.newPullParser();
+ TypedXmlPullParser parser = Xml.newFastPullParser();
parser.setInput(new BufferedInputStream(
new ByteArrayInputStream(baos.toByteArray())), null);
parser.nextTag();
@@ -640,7 +642,7 @@ public class ManagedServicesTest extends UiServiceTestCase {
mIpm, approvalLevel);
loadXml(service);
- XmlSerializer serializer = new FastXmlSerializer();
+ TypedXmlSerializer serializer = Xml.newFastSerializer();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
serializer.setOutput(new BufferedOutputStream(baos), "utf-8");
serializer.startDocument(null, true);
@@ -666,7 +668,7 @@ public class ManagedServicesTest extends UiServiceTestCase {
mIpm, approvalLevel);
loadXml(service);
- XmlSerializer serializer = new FastXmlSerializer();
+ TypedXmlSerializer serializer = Xml.newFastSerializer();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
serializer.setOutput(new BufferedOutputStream(baos), "utf-8");
serializer.startDocument(null, true);
@@ -674,7 +676,7 @@ public class ManagedServicesTest extends UiServiceTestCase {
serializer.endDocument();
serializer.flush();
- XmlPullParser parser = Xml.newPullParser();
+ TypedXmlPullParser parser = Xml.newFastPullParser();
byte[] rawOutput = baos.toByteArray();
parser.setInput(new BufferedInputStream(
new ByteArrayInputStream(rawOutput)), null);
@@ -1387,7 +1389,7 @@ public class ManagedServicesTest extends UiServiceTestCase {
private void loadXml(ManagedServices service) throws Exception {
String xmlString = createXml(service);
- XmlPullParser parser = Xml.newPullParser();
+ TypedXmlPullParser parser = Xml.newFastPullParser();
parser.setInput(new BufferedInputStream(
new ByteArrayInputStream(xmlString.getBytes())), null);
parser.nextTag();
@@ -1423,7 +1425,7 @@ public class ManagedServicesTest extends UiServiceTestCase {
return xml.toString();
}
- private XmlPullParser getParserWithEntries(ManagedServices service, String... xmlEntries)
+ private TypedXmlPullParser getParserWithEntries(ManagedServices service, String... xmlEntries)
throws Exception {
final StringBuffer xml = new StringBuffer();
xml.append("<" + service.getConfig().xmlTag + ">\n");
@@ -1432,7 +1434,7 @@ public class ManagedServicesTest extends UiServiceTestCase {
}
xml.append("</" + service.getConfig().xmlTag + ">");
- XmlPullParser parser = Xml.newPullParser();
+ TypedXmlPullParser parser = Xml.newFastPullParser();
parser.setInput(new BufferedInputStream(
new ByteArrayInputStream(xml.toString().getBytes())), null);
parser.nextTag();
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java
index f649911b6bb9..b3116d970725 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java
@@ -36,6 +36,7 @@ import android.content.pm.UserInfo;
import android.os.UserHandle;
import android.os.UserManager;
import android.util.IntArray;
+import android.util.TypedXmlPullParser;
import android.util.Xml;
import com.android.server.UiServiceTestCase;
@@ -45,7 +46,6 @@ import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-import org.xmlpull.v1.XmlPullParser;
import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
@@ -126,7 +126,7 @@ public class NotificationAssistantsTest extends UiServiceTestCase {
+ "<service_listing approved=\"b/b\" user=\"10\" primary=\"true\" />"
+ "</enabled_assistants>";
- XmlPullParser parser = Xml.newPullParser();
+ TypedXmlPullParser parser = Xml.newFastPullParser();
parser.setInput(new BufferedInputStream(
new ByteArrayInputStream(xml.toString().getBytes())), null);
parser.nextTag();
@@ -142,24 +142,24 @@ public class NotificationAssistantsTest extends UiServiceTestCase {
ComponentName component1 = ComponentName.unflattenFromString("package/Component1");
ComponentName component2 = ComponentName.unflattenFromString("package/Component2");
mAssistants.setPackageOrComponentEnabled(component1.flattenToString(), mZero.id, true,
- true);
+ true, true);
verify(mNm, never()).setNotificationAssistantAccessGrantedForUserInternal(
- any(ComponentName.class), eq(mZero.id), anyBoolean());
+ any(ComponentName.class), eq(mZero.id), anyBoolean(), anyBoolean());
mAssistants.setPackageOrComponentEnabled(component2.flattenToString(), mZero.id, true,
- true);
+ true, true);
verify(mNm, times(1)).setNotificationAssistantAccessGrantedForUserInternal(
- component1, mZero.id, false);
+ component1, mZero.id, false, true);
}
@Test
public void testSetPackageOrComponentEnabled_samePackage() throws Exception {
ComponentName component1 = ComponentName.unflattenFromString("package/Component1");
mAssistants.setPackageOrComponentEnabled(component1.flattenToString(), mZero.id, true,
- true);
+ true, true);
mAssistants.setPackageOrComponentEnabled(component1.flattenToString(), mZero.id, true,
- true);
+ true, true);
verify(mNm, never()).setNotificationAssistantAccessGrantedForUserInternal(
- any(ComponentName.class), eq(mZero.id), anyBoolean());
+ any(ComponentName.class), eq(mZero.id), anyBoolean(), anyBoolean());
}
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index 09a4289ece3f..5cf529a239dc 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -160,6 +160,8 @@ import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.AtomicFile;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
import android.util.Xml;
import android.widget.RemoteViews;
@@ -170,7 +172,6 @@ import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
import com.android.internal.logging.InstanceIdSequence;
import com.android.internal.logging.InstanceIdSequenceFake;
import com.android.internal.statusbar.NotificationVisibility;
-import com.android.internal.util.FastXmlSerializer;
import com.android.server.DeviceIdleInternal;
import com.android.server.LocalServices;
import com.android.server.SystemService;
@@ -194,8 +195,6 @@ import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.stubbing.Answer;
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlSerializer;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
@@ -355,12 +354,14 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
@Override
protected void setNotificationAssistantAccessGrantedForUserInternal(
- ComponentName assistant, int userId, boolean granted) {
+ ComponentName assistant, int userId, boolean granted, boolean userSet) {
if (mNotificationAssistantAccessGrantedCallback != null) {
- mNotificationAssistantAccessGrantedCallback.onGranted(assistant, userId, granted);
+ mNotificationAssistantAccessGrantedCallback.onGranted(assistant, userId, granted,
+ userSet);
return;
}
- super.setNotificationAssistantAccessGrantedForUserInternal(assistant, userId, granted);
+ super.setNotificationAssistantAccessGrantedForUserInternal(assistant, userId, granted,
+ userSet);
}
@Override
@@ -374,7 +375,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
}
interface NotificationAssistantAccessGrantedCallback {
- void onGranted(ComponentName assistant, int userId, boolean granted);
+ void onGranted(ComponentName assistant, int userId, boolean granted, boolean userSet);
}
}
@@ -897,7 +898,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
mService.setDefaultAssistantForUser(userId);
verify(mAssistants).setPackageOrComponentEnabled(
- eq(testComponent), eq(userId), eq(true), eq(true));
+ eq(testComponent), eq(userId), eq(true), eq(true), eq(false));
}
@Test
@@ -2907,7 +2908,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
verify(mContext, times(1)).sendBroadcastAsUser(any(), eq(user), any());
verify(mAssistants, times(1)).setPackageOrComponentEnabled(
- c.flattenToString(), user.getIdentifier(), true, true);
+ c.flattenToString(), user.getIdentifier(), true, true, true);
verify(mAssistants).setUserSet(10, true);
verify(mConditionProviders, times(1)).setPackageOrComponentEnabled(
c.flattenToString(), user.getIdentifier(), false, true);
@@ -2951,7 +2952,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
verify(mConditionProviders, times(1)).setPackageOrComponentEnabled(
c.getPackageName(), user.getIdentifier(), true, true);
verify(mAssistants, never()).setPackageOrComponentEnabled(
- any(), anyInt(), anyBoolean(), anyBoolean());
+ any(), anyInt(), anyBoolean(), anyBoolean(), anyBoolean());
verify(mListeners, never()).setPackageOrComponentEnabled(
any(), anyInt(), anyBoolean(), anyBoolean());
}
@@ -2966,7 +2967,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
verify(mConditionProviders, times(1)).setPackageOrComponentEnabled(
c.flattenToString(), 0, false, true, true);
verify(mAssistants, never()).setPackageOrComponentEnabled(
- any(), anyInt(), anyBoolean(), anyBoolean());
+ any(), anyInt(), anyBoolean(), anyBoolean(), anyBoolean());
}
@Test
@@ -2981,7 +2982,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
mBinderService.setNotificationAssistantAccessGranted(c, true);
verify(mAssistants, times(1)).setPackageOrComponentEnabled(
- c.flattenToString(), 0, true, true);
+ c.flattenToString(), 0, true, true, true);
verify(mConditionProviders, times(1)).setPackageOrComponentEnabled(
c.flattenToString(), 0, false, true);
verify(mListeners, never()).setPackageOrComponentEnabled(
@@ -3003,9 +3004,9 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
mBinderService.setNotificationAssistantAccessGranted(c, true);
verify(mAssistants, times(1)).setPackageOrComponentEnabled(
- c.flattenToString(), 0, true, true);
+ c.flattenToString(), 0, true, true, true);
verify(mAssistants, times(1)).setPackageOrComponentEnabled(
- c.flattenToString(), 10, true, true);
+ c.flattenToString(), 10, true, true, true);
verify(mConditionProviders, times(1)).setPackageOrComponentEnabled(
c.flattenToString(), 0, false, true);
verify(mConditionProviders, times(1)).setPackageOrComponentEnabled(
@@ -3029,7 +3030,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
mBinderService.setNotificationAssistantAccessGranted(null, true);
verify(mAssistants, times(1)).setPackageOrComponentEnabled(
- c.flattenToString(), 0, true, false);
+ c.flattenToString(), 0, true, false, true);
verify(mConditionProviders, times(1)).setPackageOrComponentEnabled(
c.flattenToString(), 0, false, false);
verify(mListeners, never()).setPackageOrComponentEnabled(
@@ -3053,7 +3054,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
null, user.getIdentifier(), true);
verify(mAssistants, times(1)).setPackageOrComponentEnabled(
- c.flattenToString(), user.getIdentifier(), true, false);
+ c.flattenToString(), user.getIdentifier(), true, false, true);
verify(mAssistants).setUserSet(10, true);
verify(mConditionProviders, times(1)).setPackageOrComponentEnabled(
c.flattenToString(), user.getIdentifier(), false, false);
@@ -3082,9 +3083,9 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
null, user.getIdentifier(), true);
verify(mAssistants, times(1)).setPackageOrComponentEnabled(
- c.flattenToString(), user.getIdentifier(), true, false);
+ c.flattenToString(), user.getIdentifier(), true, false, true);
verify(mAssistants, times(1)).setPackageOrComponentEnabled(
- c.flattenToString(), ui10.id, true, false);
+ c.flattenToString(), ui10.id, true, false, true);
verify(mAssistants).setUserSet(0, true);
verify(mAssistants).setUserSet(10, true);
verify(mConditionProviders, times(1)).setPackageOrComponentEnabled(
@@ -3104,7 +3105,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
verify(mConditionProviders, times(1)).setPackageOrComponentEnabled(
c.getPackageName(), 0, true, true);
verify(mAssistants, never()).setPackageOrComponentEnabled(
- any(), anyInt(), anyBoolean(), anyBoolean());
+ any(), anyInt(), anyBoolean(), anyBoolean(), anyBoolean());
verify(mListeners, never()).setPackageOrComponentEnabled(
any(), anyInt(), anyBoolean(), anyBoolean());
}
@@ -3189,7 +3190,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
verify(mConditionProviders, times(1)).setPackageOrComponentEnabled(
c.flattenToString(), 0, false, true);
verify(mAssistants, times(1)).setPackageOrComponentEnabled(
- c.flattenToString(), 0, true, true);
+ c.flattenToString(), 0, true, true, true);
}
@Test
@@ -3205,7 +3206,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
verify(mConditionProviders, times(1)).setPackageOrComponentEnabled(
c.getPackageName(), 0, true, true);
verify(mAssistants, never()).setPackageOrComponentEnabled(
- any(), anyInt(), anyBoolean(), anyBoolean());
+ any(), anyInt(), anyBoolean(), anyBoolean(), anyBoolean());
}
@Test
@@ -3446,7 +3447,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
new BufferedInputStream(new ByteArrayInputStream(upgradeXml.getBytes())),
false,
UserHandle.USER_ALL);
- verify(mSnoozeHelper, times(1)).readXml(any(XmlPullParser.class), anyLong());
+ verify(mSnoozeHelper, times(1)).readXml(any(TypedXmlPullParser.class), anyLong());
}
@Test
@@ -3887,12 +3888,12 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
NotificationChannel channel = new NotificationChannel("a", "ab", IMPORTANCE_DEFAULT);
channel.setSound(Uri.EMPTY, null);
- XmlSerializer serializer = new FastXmlSerializer();
+ TypedXmlSerializer serializer = Xml.newFastSerializer();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
serializer.setOutput(new BufferedOutputStream(baos), "utf-8");
channel.writeXmlForBackup(serializer, getContext());
- XmlPullParser parser = Xml.newPullParser();
+ TypedXmlPullParser parser = Xml.newFastPullParser();
parser.setInput(new BufferedInputStream(
new ByteArrayInputStream(baos.toByteArray())), null);
NotificationChannel restored = new NotificationChannel("a", "ab", IMPORTANCE_DEFAULT);
@@ -3915,7 +3916,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
NotificationChannel channel = new NotificationChannel("a", "ab", IMPORTANCE_DEFAULT);
channel.setVibrationPattern(new long[0]);
- XmlSerializer serializer = new FastXmlSerializer();
+ TypedXmlSerializer serializer = Xml.newFastSerializer();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
serializer.setOutput(new BufferedOutputStream(baos), "utf-8");
channel.writeXml(serializer);
@@ -5417,7 +5418,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
mService.setDefaultAssistantForUser(0);
verify(mNotificationAssistantAccessGrantedCallback)
- .onGranted(eq(xmlConfig), eq(0), eq(true));
+ .onGranted(eq(xmlConfig), eq(0), eq(true), eq(false));
}
@Test
@@ -5439,7 +5440,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
mService.setDefaultAssistantForUser(0);
verify(mNotificationAssistantAccessGrantedCallback)
- .onGranted(eq(deviceConfig), eq(0), eq(true));
+ .onGranted(eq(deviceConfig), eq(0), eq(true), eq(false));
}
@Test
@@ -5462,7 +5463,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
mService.setDefaultAssistantForUser(0);
verify(mNotificationAssistantAccessGrantedCallback)
- .onGranted(eq(xmlConfig), eq(0), eq(true));
+ .onGranted(eq(xmlConfig), eq(0), eq(true), eq(false));
}
@Test
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
index 7ec8689e5387..98c4a2da6a4f 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
@@ -99,6 +99,8 @@ import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Pair;
import android.util.StatsEvent;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
import android.util.Xml;
import androidx.test.InstrumentationRegistry;
@@ -280,7 +282,7 @@ public class PreferencesHelperTest extends UiServiceTestCase {
private ByteArrayOutputStream writeXmlAndPurge(
String pkg, int uid, boolean forBackup, int userId, String... channelIds)
throws Exception {
- XmlSerializer serializer = new FastXmlSerializer();
+ TypedXmlSerializer serializer = Xml.newFastSerializer();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
serializer.setOutput(new BufferedOutputStream(baos), "utf-8");
serializer.startDocument(null, true);
@@ -300,7 +302,7 @@ public class PreferencesHelperTest extends UiServiceTestCase {
private void loadByteArrayXml(byte[] byteArray, boolean forRestore, int userId)
throws Exception {
- XmlPullParser parser = Xml.newPullParser();
+ TypedXmlPullParser parser = Xml.newFastPullParser();
parser.setInput(new BufferedInputStream(new ByteArrayInputStream(byteArray)), null);
parser.nextTag();
mHelper.readXml(parser, forRestore, userId);
@@ -717,7 +719,7 @@ public class PreferencesHelperTest extends UiServiceTestCase {
mHelper.onPackagesChanged(true, UserHandle.myUserId(), new String[]{PKG_N_MR1}, new int[]{
UID_N_MR1});
- XmlPullParser parser = Xml.newPullParser();
+ TypedXmlPullParser parser = Xml.newFastPullParser();
parser.setInput(new BufferedInputStream(new ByteArrayInputStream(baos.toByteArray())),
null);
parser.nextTag();
@@ -772,7 +774,7 @@ public class PreferencesHelperTest extends UiServiceTestCase {
+ "<package name=\"" + PKG_O + "\" uid=\"" + UID_O + "\" visibility=\""
+ Notification.VISIBILITY_PRIVATE + "\" />\n"
+ "</ranking>";
- XmlPullParser parser = Xml.newPullParser();
+ TypedXmlPullParser parser = Xml.newFastPullParser();
parser.setInput(new BufferedInputStream(new ByteArrayInputStream(preupgradeXml.getBytes())),
null);
parser.nextTag();
@@ -2559,7 +2561,7 @@ public class PreferencesHelperTest extends UiServiceTestCase {
+ " importance=\"3\"/>"
+ "</package>"
+ "</ranking>";
- XmlPullParser parser = Xml.newPullParser();
+ TypedXmlPullParser parser = Xml.newFastPullParser();
parser.setInput(new BufferedInputStream(new ByteArrayInputStream(xml.getBytes())),
null);
parser.nextTag();
@@ -2580,7 +2582,7 @@ public class PreferencesHelperTest extends UiServiceTestCase {
+ " importance=\"3\"/>"
+ "</package>"
+ "</ranking>";
- XmlPullParser parser = Xml.newPullParser();
+ TypedXmlPullParser parser = Xml.newFastPullParser();
parser.setInput(new BufferedInputStream(new ByteArrayInputStream(xml.getBytes())),
null);
parser.nextTag();
@@ -2612,7 +2614,7 @@ public class PreferencesHelperTest extends UiServiceTestCase {
+ " importance=\"3\"/>"
+ "</package>"
+ "</ranking>";
- XmlPullParser parser = Xml.newPullParser();
+ TypedXmlPullParser parser = Xml.newFastPullParser();
parser.setInput(new BufferedInputStream(new ByteArrayInputStream(xml.getBytes())),
null);
parser.nextTag();
@@ -2753,7 +2755,7 @@ public class PreferencesHelperTest extends UiServiceTestCase {
+ "<channel id=\"b\" name=\"b\" importance=\"3\"/>"
+ "</package>"
+ "</ranking>";
- XmlPullParser parser = Xml.newPullParser();
+ TypedXmlPullParser parser = Xml.newFastPullParser();
parser.setInput(new BufferedInputStream(new ByteArrayInputStream(xml.getBytes())),
null);
parser.nextTag();
@@ -2779,7 +2781,7 @@ public class PreferencesHelperTest extends UiServiceTestCase {
+ "<channel id=\"c\" name=\"c\" importance=\"3\"/>"
+ "</package>"
+ "</ranking>";
- XmlPullParser parser = Xml.newPullParser();
+ TypedXmlPullParser parser = Xml.newFastPullParser();
parser.setInput(new BufferedInputStream(new ByteArrayInputStream(xml.getBytes())),
null);
parser.nextTag();
@@ -3047,7 +3049,7 @@ public class PreferencesHelperTest extends UiServiceTestCase {
toAdd.add(new Pair(PKG_O, UID_O));
mHelper.updateDefaultApps(UserHandle.getUserId(UID_O), null, toAdd);
- XmlPullParser parser = Xml.newPullParser();
+ TypedXmlPullParser parser = Xml.newFastPullParser();
parser.setInput(new BufferedInputStream(new ByteArrayInputStream(baos.toByteArray())),
null);
parser.nextTag();
@@ -3121,7 +3123,7 @@ public class PreferencesHelperTest extends UiServiceTestCase {
+ "<channel id=\"" + extraChannel1 + "\" name=\"hi\" importance=\"3\"/>"
+ "</package>"
+ "</ranking>";
- XmlPullParser parser = Xml.newPullParser();
+ TypedXmlPullParser parser = Xml.newFastPullParser();
parser.setInput(new BufferedInputStream(new ByteArrayInputStream(xml.getBytes())),
null);
parser.nextTag();
@@ -3154,12 +3156,12 @@ public class PreferencesHelperTest extends UiServiceTestCase {
+ "</ranking>";
// trigger a restore for both users
- XmlPullParser parser = Xml.newPullParser();
+ TypedXmlPullParser parser = Xml.newFastPullParser();
parser.setInput(new BufferedInputStream(new ByteArrayInputStream(xmlUser0.getBytes())),
null);
parser.nextTag();
mHelper.readXml(parser, true, 0);
- parser = Xml.newPullParser();
+ parser = Xml.newFastPullParser();
parser.setInput(new BufferedInputStream(new ByteArrayInputStream(xmlUser10.getBytes())),
null);
parser.nextTag();
@@ -3242,7 +3244,7 @@ public class PreferencesHelperTest extends UiServiceTestCase {
+ "<channel id=\"id\" name=\"hi\" importance=\"3\" conv_id=\"foo:placeholder_id\"/>"
+ "</package>"
+ "</ranking>";
- XmlPullParser parser = Xml.newPullParser();
+ TypedXmlPullParser parser = Xml.newFastPullParser();
parser.setInput(new BufferedInputStream(new ByteArrayInputStream(xml.getBytes())),
null);
parser.nextTag();
@@ -3261,7 +3263,7 @@ public class PreferencesHelperTest extends UiServiceTestCase {
+ "<channel id=\"id\" name=\"hi\" importance=\"3\" conv_id=\"other\"/>"
+ "</package>"
+ "</ranking>";
- XmlPullParser parser = Xml.newPullParser();
+ TypedXmlPullParser parser = Xml.newFastPullParser();
parser.setInput(new BufferedInputStream(new ByteArrayInputStream(xml.getBytes())),
null);
parser.nextTag();
@@ -3280,7 +3282,7 @@ public class PreferencesHelperTest extends UiServiceTestCase {
+ "<channel id=\"id\" name=\"hi\" importance=\"3\"/>"
+ "</package>"
+ "</ranking>";
- XmlPullParser parser = Xml.newPullParser();
+ TypedXmlPullParser parser = Xml.newFastPullParser();
parser.setInput(new BufferedInputStream(new ByteArrayInputStream(xml.getBytes())),
null);
parser.nextTag();
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java
index 3deeea2d4577..35b224a24061 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java
@@ -43,6 +43,8 @@ import android.os.UserHandle;
import android.service.notification.StatusBarNotification;
import android.test.suitebuilder.annotation.SmallTest;
import android.util.IntArray;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
import android.util.Xml;
import androidx.test.runner.AndroidJUnit4;
@@ -95,7 +97,7 @@ public class SnoozeHelperTest extends UiServiceTestCase {
+ "<notification version=\"1\" user-id=\"0\" notification=\"notification\" "
+ "pkg=\"pkg\" key=\"key2\" time=\"" + max_time_str + "\"/>"
+ "</snoozed-notifications>";
- XmlPullParser parser = Xml.newPullParser();
+ TypedXmlPullParser parser = Xml.newFastPullParser();
parser.setInput(new BufferedInputStream(
new ByteArrayInputStream(xml_string.getBytes())), null);
mSnoozeHelper.readXml(parser, 1);
@@ -114,12 +116,12 @@ public class SnoozeHelperTest extends UiServiceTestCase {
+ "<notification version=\"1\" user-id=\"0\" notification=\"notification\" "
+ "pkg=\"pkg\" key=\"key2\" time=\"" + max_time_str + "\"/>"
+ "</snoozed-notifications>";
- XmlPullParser parser = Xml.newPullParser();
+ TypedXmlPullParser parser = Xml.newFastPullParser();
parser.setInput(new BufferedInputStream(
new ByteArrayInputStream(xml_string.getBytes())), null);
mSnoozeHelper.readXml(parser, 1);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
- XmlSerializer serializer = new FastXmlSerializer();
+ TypedXmlSerializer serializer = Xml.newFastSerializer();
serializer.setOutput(new BufferedOutputStream(baos), "utf-8");
serializer.startDocument(null, true);
mSnoozeHelper.writeXml(serializer);
@@ -137,7 +139,7 @@ public class SnoozeHelperTest extends UiServiceTestCase {
+ "<context version=\"1\" user-id=\"0\" notification=\"notification\" "
+ "pkg=\"pkg\" key=\"key2\" id=\"uri\"/>"
+ "</snoozed-notifications>";
- XmlPullParser parser = Xml.newPullParser();
+ TypedXmlPullParser parser = Xml.newFastPullParser();
parser.setInput(new BufferedInputStream(
new ByteArrayInputStream(xml_string.getBytes())), null);
mSnoozeHelper.readXml(parser, 1);
@@ -151,7 +153,7 @@ public class SnoozeHelperTest extends UiServiceTestCase {
throws XmlPullParserException, IOException {
NotificationRecord r = getNotificationRecord("pkg", 1, "one", UserHandle.SYSTEM);
mSnoozeHelper.snooze(r, 999999999);
- XmlSerializer serializer = new FastXmlSerializer();
+ TypedXmlSerializer serializer = Xml.newFastSerializer();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
serializer.setOutput(new BufferedOutputStream(baos), "utf-8");
serializer.startDocument(null, true);
@@ -159,7 +161,7 @@ public class SnoozeHelperTest extends UiServiceTestCase {
serializer.endDocument();
serializer.flush();
- XmlPullParser parser = Xml.newPullParser();
+ TypedXmlPullParser parser = Xml.newFastPullParser();
parser.setInput(new BufferedInputStream(
new ByteArrayInputStream(baos.toByteArray())), "utf-8");
mSnoozeHelper.readXml(parser, 1);
@@ -175,7 +177,7 @@ public class SnoozeHelperTest extends UiServiceTestCase {
NotificationRecord r = getNotificationRecord("pkg", 1, "one", UserHandle.SYSTEM);
mSnoozeHelper.snooze(r, 0);
// Thread.sleep(100);
- XmlSerializer serializer = new FastXmlSerializer();
+ TypedXmlSerializer serializer = Xml.newFastSerializer();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
serializer.setOutput(new BufferedOutputStream(baos), "utf-8");
serializer.startDocument(null, true);
@@ -183,7 +185,7 @@ public class SnoozeHelperTest extends UiServiceTestCase {
serializer.endDocument();
serializer.flush();
Thread.sleep(10);
- XmlPullParser parser = Xml.newPullParser();
+ TypedXmlPullParser parser = Xml.newFastPullParser();
parser.setInput(new BufferedInputStream(
new ByteArrayInputStream(baos.toByteArray())), "utf-8");
mSnoozeHelper.readXml(parser, 2);
@@ -227,7 +229,7 @@ public class SnoozeHelperTest extends UiServiceTestCase {
+ "<notification version=\"1\" user-id=\"0\" notification=\"notification\" "
+ "pkg=\"pkg\" key=\"key2\" time=\"" + 15+ "\"/>"
+ "</snoozed-notifications>";
- XmlPullParser parser = Xml.newPullParser();
+ TypedXmlPullParser parser = Xml.newFastPullParser();
parser.setInput(new BufferedInputStream(
new ByteArrayInputStream(xml_string.getBytes())), null);
mSnoozeHelper.readXml(parser, 4);
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java
index 013a99433041..5262465a399c 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java
@@ -30,6 +30,8 @@ import android.service.notification.ZenModeConfig;
import android.service.notification.ZenModeConfig.EventInfo;
import android.service.notification.ZenPolicy;
import android.test.suitebuilder.annotation.SmallTest;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
import android.util.Xml;
import androidx.test.runner.AndroidJUnit4;
@@ -199,7 +201,7 @@ public class ZenModeConfigTest extends UiServiceTestCase {
rule.name = "name";
rule.snoozing = true;
- XmlSerializer out = new FastXmlSerializer();
+ TypedXmlSerializer out = Xml.newFastSerializer();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
out.setOutput(new BufferedOutputStream(baos), "utf-8");
out.startDocument(null, true);
@@ -208,7 +210,7 @@ public class ZenModeConfigTest extends UiServiceTestCase {
out.endTag(null, tag);
out.endDocument();
- XmlPullParser parser = Xml.newPullParser();
+ TypedXmlPullParser parser = Xml.newFastPullParser();
parser.setInput(new BufferedInputStream(
new ByteArrayInputStream(baos.toByteArray())), null);
parser.nextTag();
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
index 3430dbdce753..cfdd2464322d 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
@@ -95,6 +95,8 @@ import android.testing.TestableLooper;
import android.util.ArrayMap;
import android.util.Log;
import android.util.StatsEvent;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
import android.util.Xml;
import com.android.internal.R;
@@ -189,14 +191,14 @@ public class ZenModeHelperTest extends UiServiceTestCase {
+ "&amp;end=7.0&amp;exitAtAlarm=true\"/>"
+ "<disallow visualEffects=\"511\" />"
+ "</zen>";
- XmlPullParser parser = Xml.newPullParser();
+ TypedXmlPullParser parser = Xml.newFastPullParser();
parser.setInput(new BufferedInputStream(new ByteArrayInputStream(xml.getBytes())), null);
parser.nextTag();
return new XmlResourceParserImpl(parser);
}
private ByteArrayOutputStream writeXmlAndPurge(Integer version) throws Exception {
- XmlSerializer serializer = new FastXmlSerializer();
+ TypedXmlSerializer serializer = Xml.newFastSerializer();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
serializer.setOutput(new BufferedOutputStream(baos), "utf-8");
serializer.startDocument(null, true);
@@ -209,7 +211,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
private ByteArrayOutputStream writeXmlAndPurgeForUser(Integer version, int userId)
throws Exception {
- XmlSerializer serializer = new FastXmlSerializer();
+ TypedXmlSerializer serializer = Xml.newFastSerializer();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
serializer.setOutput(new BufferedOutputStream(baos), "utf-8");
serializer.startDocument(null, true);
@@ -222,8 +224,8 @@ public class ZenModeHelperTest extends UiServiceTestCase {
return baos;
}
- private XmlPullParser getParserForByteStream(ByteArrayOutputStream baos) throws Exception {
- XmlPullParser parser = Xml.newPullParser();
+ private TypedXmlPullParser getParserForByteStream(ByteArrayOutputStream baos) throws Exception {
+ TypedXmlPullParser parser = Xml.newFastPullParser();
parser.setInput(
new BufferedInputStream(new ByteArrayInputStream(baos.toByteArray())), null);
parser.nextTag();
@@ -837,7 +839,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
ZenModeConfig expected = mZenModeHelperSpy.mConfig.copy();
ByteArrayOutputStream baos = writeXmlAndPurge(null);
- XmlPullParser parser = getParserForByteStream(baos);
+ TypedXmlPullParser parser = getParserForByteStream(baos);
mZenModeHelperSpy.readXml(parser, false, UserHandle.USER_ALL);
assertEquals("Config mismatch: current vs expected: "
@@ -962,7 +964,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
mZenModeHelperSpy.mConfigs.put(11, newConfig11);
// Parse backup data.
- XmlPullParser parser = getParserForByteStream(baos);
+ TypedXmlPullParser parser = getParserForByteStream(baos);
mZenModeHelperSpy.readXml(parser, true, 10);
mZenModeHelperSpy.readXml(parser, true, 11);
@@ -980,7 +982,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
ZenModeConfig original = mZenModeHelperSpy.mConfig.copy();
ByteArrayOutputStream baos = writeXmlAndPurgeForUser(null, UserHandle.USER_SYSTEM);
- XmlPullParser parser = getParserForByteStream(baos);
+ TypedXmlPullParser parser = getParserForByteStream(baos);
mZenModeHelperSpy.readXml(parser, true, UserHandle.USER_SYSTEM);
assertEquals("Config mismatch: current vs original: "
@@ -1000,7 +1002,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
ByteArrayOutputStream baos = writeXmlAndPurgeForUser(null, UserHandle.USER_SYSTEM);
// Restore data for user 10.
- XmlPullParser parser = getParserForByteStream(baos);
+ TypedXmlPullParser parser = getParserForByteStream(baos);
mZenModeHelperSpy.readXml(parser, true, 10);
ZenModeConfig actual = mZenModeHelperSpy.mConfigs.get(10);
@@ -1045,7 +1047,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
ZenModeConfig expected = mZenModeHelperSpy.mConfig.copy();
ByteArrayOutputStream baos = writeXmlAndPurge(null);
- XmlPullParser parser = Xml.newPullParser();
+ TypedXmlPullParser parser = Xml.newFastPullParser();
parser.setInput(new BufferedInputStream(
new ByteArrayInputStream(baos.toByteArray())), null);
parser.nextTag();
@@ -1086,7 +1088,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
ZenModeConfig expected = mZenModeHelperSpy.mConfig.copy();
ByteArrayOutputStream baos = writeXmlAndPurgeForUser(null, UserHandle.USER_SYSTEM);
- XmlPullParser parser = getParserForByteStream(baos);
+ TypedXmlPullParser parser = getParserForByteStream(baos);
mZenModeHelperSpy.readXml(parser, true, UserHandle.USER_SYSTEM);
ZenModeConfig.ZenRule original = expected.automaticRules.get(ruleId);
@@ -1113,7 +1115,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
// set previous version
ByteArrayOutputStream baos = writeXmlAndPurge(5);
- XmlPullParser parser = Xml.newPullParser();
+ TypedXmlPullParser parser = Xml.newFastPullParser();
parser.setInput(new BufferedInputStream(
new ByteArrayInputStream(baos.toByteArray())), null);
parser.nextTag();
@@ -1133,7 +1135,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
+ "<disallow visualEffects=\"511\" />"
+ "</zen>";
- XmlPullParser parser = Xml.newPullParser();
+ TypedXmlPullParser parser = Xml.newFastPullParser();
parser.setInput(new BufferedInputStream(
new ByteArrayInputStream(xml.getBytes())), null);
parser.nextTag();
@@ -1149,7 +1151,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
+ "<disallow visualEffects=\"511\" />"
+ "</zen>";
- parser = Xml.newPullParser();
+ parser = Xml.newFastPullParser();
parser.setInput(new BufferedInputStream(
new ByteArrayInputStream(xml.getBytes())), null);
parser.nextTag();
@@ -1168,7 +1170,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
+ "<disallow visualEffects=\"511\" />"
+ "</zen>";
- XmlPullParser parser = Xml.newPullParser();
+ TypedXmlPullParser parser = Xml.newFastPullParser();
parser.setInput(new BufferedInputStream(
new ByteArrayInputStream(xml.getBytes())), null);
parser.nextTag();
@@ -1187,7 +1189,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
+ "<disallow visualEffects=\"511\" />"
+ "</zen>";
- XmlPullParser parser = Xml.newPullParser();
+ TypedXmlPullParser parser = Xml.newFastPullParser();
parser.setInput(new BufferedInputStream(
new ByteArrayInputStream(xml.getBytes())), null);
parser.nextTag();
@@ -1206,7 +1208,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
+ "<disallow visualEffects=\"511\" />"
+ "</zen>";
- parser = Xml.newPullParser();
+ parser = Xml.newFastPullParser();
parser.setInput(new BufferedInputStream(
new ByteArrayInputStream(xml.getBytes())), null);
parser.nextTag();
@@ -1222,7 +1224,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
+ "<disallow visualEffects=\"511\" />"
+ "</zen>";
- parser = Xml.newPullParser();
+ parser = Xml.newFastPullParser();
parser.setInput(new BufferedInputStream(
new ByteArrayInputStream(xml.getBytes())), null);
parser.nextTag();
@@ -1242,7 +1244,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
// set previous version
ByteArrayOutputStream baos = writeXmlAndPurge(5);
- XmlPullParser parser = Xml.newPullParser();
+ TypedXmlPullParser parser = Xml.newFastPullParser();
parser.setInput(new BufferedInputStream(
new ByteArrayInputStream(baos.toByteArray())), null);
parser.nextTag();
@@ -1278,7 +1280,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
// set previous version
ByteArrayOutputStream baos = writeXmlAndPurge(5);
- XmlPullParser parser = Xml.newPullParser();
+ TypedXmlPullParser parser = Xml.newFastPullParser();
parser.setInput(new BufferedInputStream(
new ByteArrayInputStream(baos.toByteArray())), null);
parser.nextTag();
@@ -1330,7 +1332,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
// set previous version
ByteArrayOutputStream baos = writeXmlAndPurge(5);
- XmlPullParser parser = Xml.newPullParser();
+ TypedXmlPullParser parser = Xml.newFastPullParser();
parser.setInput(new BufferedInputStream(
new ByteArrayInputStream(baos.toByteArray())), null);
parser.nextTag();
@@ -1399,7 +1401,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
// set previous version
ByteArrayOutputStream baos = writeXmlAndPurge(5);
- XmlPullParser parser = Xml.newPullParser();
+ TypedXmlPullParser parser = Xml.newFastPullParser();
parser.setInput(new BufferedInputStream(
new ByteArrayInputStream(baos.toByteArray())), null);
parser.nextTag();
@@ -1628,12 +1630,12 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
/**
- * Wrapper to use XmlPullParser as XmlResourceParser for Resources.getXml()
+ * Wrapper to use TypedXmlPullParser as XmlResourceParser for Resources.getXml()
*/
final class XmlResourceParserImpl implements XmlResourceParser {
- private XmlPullParser parser;
+ private TypedXmlPullParser parser;
- public XmlResourceParserImpl(XmlPullParser parser) {
+ public XmlResourceParserImpl(TypedXmlPullParser parser) {
this.parser = parser;
}
diff --git a/services/tests/wmtests/AndroidManifest.xml b/services/tests/wmtests/AndroidManifest.xml
index 7f4f3dd58812..0ed037c7e70a 100644
--- a/services/tests/wmtests/AndroidManifest.xml
+++ b/services/tests/wmtests/AndroidManifest.xml
@@ -65,8 +65,6 @@
android:turnScreenOn="true" />
<activity android:name="com.android.server.wm.TaskStackChangedListenerTest$ResumeWhilePausingActivity"
android:resumeWhilePausing="true"/>
- <activity android:name="com.android.server.wm.ScreenDecorWindowTests$TestActivity"
- android:showWhenLocked="true" android:allowEmbedded="true"/>
<activity android:name="com.android.server.wm.ActivityLeakTests$DetectLeakActivity" />
</application>
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java
index 9a6eb1cf2623..99bd0d7198c0 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java
@@ -68,16 +68,16 @@ public class ActivityDisplayTests extends WindowTestsBase {
mRootWindowContainer.getDefaultDisplay().getDefaultTaskDisplayArea();
final Task stack =
new TaskBuilder(mSupervisor).setOnTop(!ON_TOP).setCreateActivity(true).build();
- final Task prevFocusedStack = taskDisplayAreas.getFocusedStack();
+ final Task prevFocusedStack = taskDisplayAreas.getFocusedRootTask();
stack.moveToFront("moveStackToFront");
// After moving the stack to front, the previous focused should be the last focused.
assertTrue(stack.isFocusedStackOnDisplay());
- assertEquals(prevFocusedStack, taskDisplayAreas.getLastFocusedStack());
+ assertEquals(prevFocusedStack, taskDisplayAreas.getLastFocusedRootTask());
stack.moveToBack("moveStackToBack", null /* task */);
// After moving the stack to back, the stack should be the last focused.
- assertEquals(stack, taskDisplayAreas.getLastFocusedStack());
+ assertEquals(stack, taskDisplayAreas.getLastFocusedRootTask());
}
/**
@@ -88,7 +88,7 @@ public class ActivityDisplayTests extends WindowTestsBase {
public void testFullscreenStackCanBeFocusedWhenFocusablePinnedStackExists() {
// Create a pinned stack and move to front.
final Task pinnedStack = mRootWindowContainer.getDefaultTaskDisplayArea()
- .createStack(WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, ON_TOP);
+ .createRootTask(WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, ON_TOP);
final Task pinnedTask = new TaskBuilder(mAtm.mTaskSupervisor)
.setParentTask(pinnedStack).build();
new ActivityBuilder(mAtm).setActivityFlags(FLAG_ALWAYS_FOCUSABLE)
@@ -108,7 +108,7 @@ public class ActivityDisplayTests extends WindowTestsBase {
}
/**
- * Test {@link TaskDisplayArea#mPreferredTopFocusableStack} will be cleared when
+ * Test {@link TaskDisplayArea#mPreferredTopFocusableRootTask} will be cleared when
* the stack is removed or moved to back, and the focused stack will be according to z-order.
*/
@Test
@@ -128,7 +128,7 @@ public class ActivityDisplayTests extends WindowTestsBase {
assertTrue(stack1.isFocusedStackOnDisplay());
// Stack2 should be focused after removing stack1.
- stack1.getDisplayArea().removeStack(stack1);
+ stack1.getDisplayArea().removeRootTask(stack1);
assertTrue(stack2.isFocusedStackOnDisplay());
}
@@ -155,12 +155,12 @@ public class ActivityDisplayTests extends WindowTestsBase {
display.remove();
// The removed display should have no focused stack and its home stack should never resume.
- assertNull(display.getFocusedStack());
+ assertNull(display.getFocusedRootTask());
verify(homeStack, never()).resumeTopActivityUncheckedLocked(any(), any());
}
private Task createFullscreenStackWithSimpleActivityAt(DisplayContent display) {
- final Task fullscreenStack = display.getDefaultTaskDisplayArea().createStack(
+ final Task fullscreenStack = display.getDefaultTaskDisplayArea().createRootTask(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, ON_TOP);
final Task fullscreenTask = new TaskBuilder(mAtm.mTaskSupervisor)
.setParentTask(fullscreenStack).build();
@@ -191,7 +191,7 @@ public class ActivityDisplayTests extends WindowTestsBase {
// Move stack with activity to top.
stack.moveToFront("testStackToFront");
- assertEquals(stack, display.getFocusedStack());
+ assertEquals(stack, display.getFocusedRootTask());
assertEquals(activity, display.topRunningActivity());
assertNull(display.topRunningActivity(true /* considerKeyguardState */));
@@ -207,7 +207,7 @@ public class ActivityDisplayTests extends WindowTestsBase {
// Move empty stack to front. The running activity in focusable stack which below the
// empty stack should be returned.
emptyStack.moveToFront("emptyStackToFront");
- assertEquals(stack, display.getFocusedStack());
+ assertEquals(stack, display.getFocusedRootTask());
assertTopRunningActivity(showWhenLockedActivity, display);
}
@@ -222,7 +222,7 @@ public class ActivityDisplayTests extends WindowTestsBase {
@Test
public void testAlwaysOnTopStackLocation() {
final TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea();
- final Task alwaysOnTopStack = taskDisplayArea.createStack(WINDOWING_MODE_FREEFORM,
+ final Task alwaysOnTopStack = taskDisplayArea.createRootTask(WINDOWING_MODE_FREEFORM,
ACTIVITY_TYPE_STANDARD, true /* onTop */);
final ActivityRecord activity = new ActivityBuilder(mAtm)
.setTask(alwaysOnTopStack).build();
@@ -232,31 +232,31 @@ public class ActivityDisplayTests extends WindowTestsBase {
assertTrue(alwaysOnTopStack.isAlwaysOnTop());
// Ensure always on top state is synced to the children of the stack.
assertTrue(alwaysOnTopStack.getTopNonFinishingActivity().isAlwaysOnTop());
- assertEquals(alwaysOnTopStack, taskDisplayArea.getTopStack());
+ assertEquals(alwaysOnTopStack, taskDisplayArea.getTopRootTask());
- final Task pinnedStack = taskDisplayArea.createStack(
+ final Task pinnedStack = taskDisplayArea.createRootTask(
WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, true /* onTop */);
assertEquals(pinnedStack, taskDisplayArea.getRootPinnedTask());
- assertEquals(pinnedStack, taskDisplayArea.getTopStack());
+ assertEquals(pinnedStack, taskDisplayArea.getTopRootTask());
- final Task anotherAlwaysOnTopStack = taskDisplayArea.createStack(
+ final Task anotherAlwaysOnTopStack = taskDisplayArea.createRootTask(
WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD, true /* onTop */);
anotherAlwaysOnTopStack.setAlwaysOnTop(true);
taskDisplayArea.positionChildAt(POSITION_TOP, anotherAlwaysOnTopStack,
false /* includingParents */);
assertTrue(anotherAlwaysOnTopStack.isAlwaysOnTop());
- int topPosition = taskDisplayArea.getStackCount() - 1;
+ int topPosition = taskDisplayArea.getRootTaskCount() - 1;
// Ensure the new alwaysOnTop stack is put below the pinned stack, but on top of the
// existing alwaysOnTop stack.
- assertEquals(anotherAlwaysOnTopStack, taskDisplayArea.getStackAt(topPosition - 1));
+ assertEquals(anotherAlwaysOnTopStack, taskDisplayArea.getRootTaskAt(topPosition - 1));
- final Task nonAlwaysOnTopStack = taskDisplayArea.createStack(
+ final Task nonAlwaysOnTopStack = taskDisplayArea.createRootTask(
WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD, true /* onTop */);
assertEquals(taskDisplayArea, nonAlwaysOnTopStack.getDisplayArea());
- topPosition = taskDisplayArea.getStackCount() - 1;
+ topPosition = taskDisplayArea.getRootTaskCount() - 1;
// Ensure the non-alwaysOnTop stack is put below the three alwaysOnTop stacks, but above the
// existing other non-alwaysOnTop stacks.
- assertEquals(nonAlwaysOnTopStack, taskDisplayArea.getStackAt(topPosition - 3));
+ assertEquals(nonAlwaysOnTopStack, taskDisplayArea.getRootTaskAt(topPosition - 3));
anotherAlwaysOnTopStack.setAlwaysOnTop(false);
taskDisplayArea.positionChildAt(POSITION_TOP, anotherAlwaysOnTopStack,
@@ -264,37 +264,37 @@ public class ActivityDisplayTests extends WindowTestsBase {
assertFalse(anotherAlwaysOnTopStack.isAlwaysOnTop());
// Ensure, when always on top is turned off for a stack, the stack is put just below all
// other always on top stacks.
- assertEquals(anotherAlwaysOnTopStack, taskDisplayArea.getStackAt(topPosition - 2));
+ assertEquals(anotherAlwaysOnTopStack, taskDisplayArea.getRootTaskAt(topPosition - 2));
anotherAlwaysOnTopStack.setAlwaysOnTop(true);
// Ensure always on top state changes properly when windowing mode changes.
anotherAlwaysOnTopStack.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
assertFalse(anotherAlwaysOnTopStack.isAlwaysOnTop());
- assertEquals(anotherAlwaysOnTopStack, taskDisplayArea.getStackAt(topPosition - 2));
+ assertEquals(anotherAlwaysOnTopStack, taskDisplayArea.getRootTaskAt(topPosition - 2));
anotherAlwaysOnTopStack.setWindowingMode(WINDOWING_MODE_FREEFORM);
assertTrue(anotherAlwaysOnTopStack.isAlwaysOnTop());
- assertEquals(anotherAlwaysOnTopStack, taskDisplayArea.getStackAt(topPosition - 1));
+ assertEquals(anotherAlwaysOnTopStack, taskDisplayArea.getRootTaskAt(topPosition - 1));
- final Task dreamStack = taskDisplayArea.createStack(
+ final Task dreamStack = taskDisplayArea.createRootTask(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_DREAM, true /* onTop */);
assertEquals(taskDisplayArea, dreamStack.getDisplayArea());
assertTrue(dreamStack.isAlwaysOnTop());
- topPosition = taskDisplayArea.getStackCount() - 1;
+ topPosition = taskDisplayArea.getRootTaskCount() - 1;
// Ensure dream shows above all activities, including PiP
- assertEquals(dreamStack, taskDisplayArea.getTopStack());
- assertEquals(pinnedStack, taskDisplayArea.getStackAt(topPosition - 1));
+ assertEquals(dreamStack, taskDisplayArea.getTopRootTask());
+ assertEquals(pinnedStack, taskDisplayArea.getRootTaskAt(topPosition - 1));
- final Task assistStack = taskDisplayArea.createStack(
+ final Task assistStack = taskDisplayArea.createRootTask(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_ASSISTANT, true /* onTop */);
assertEquals(taskDisplayArea, assistStack.getDisplayArea());
assertFalse(assistStack.isAlwaysOnTop());
- topPosition = taskDisplayArea.getStackCount() - 1;
+ topPosition = taskDisplayArea.getRootTaskCount() - 1;
// Ensure Assistant shows as a non-always-on-top activity when config_assistantOnTopOfDream
// is false and on top of everything when true.
final boolean isAssistantOnTop = mContext.getResources()
.getBoolean(com.android.internal.R.bool.config_assistantOnTopOfDream);
- assertEquals(assistStack, taskDisplayArea.getStackAt(
+ assertEquals(assistStack, taskDisplayArea.getRootTaskAt(
isAssistantOnTop ? topPosition : topPosition - 4));
}
@@ -312,13 +312,13 @@ public class ActivityDisplayTests extends WindowTestsBase {
private void removeStackTests(Runnable runnable) {
final TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea();
- final Task stack1 = taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN,
+ final Task stack1 = taskDisplayArea.createRootTask(WINDOWING_MODE_FULLSCREEN,
ACTIVITY_TYPE_STANDARD, ON_TOP);
- final Task stack2 = taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN,
+ final Task stack2 = taskDisplayArea.createRootTask(WINDOWING_MODE_FULLSCREEN,
ACTIVITY_TYPE_STANDARD, ON_TOP);
- final Task stack3 = taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN,
+ final Task stack3 = taskDisplayArea.createRootTask(WINDOWING_MODE_FULLSCREEN,
ACTIVITY_TYPE_STANDARD, ON_TOP);
- final Task stack4 = taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN,
+ final Task stack4 = taskDisplayArea.createRootTask(WINDOWING_MODE_FULLSCREEN,
ACTIVITY_TYPE_STANDARD, ON_TOP);
final Task task1 = new TaskBuilder(mAtm.mTaskSupervisor).setParentTask(stack1).build();
final Task task2 = new TaskBuilder(mAtm.mTaskSupervisor).setParentTask(stack2).build();
@@ -333,7 +333,7 @@ public class ActivityDisplayTests extends WindowTestsBase {
// Removing stacks from the display while removing stacks.
doAnswer(invocation -> {
- taskDisplayArea.removeStack(stack2);
+ taskDisplayArea.removeRootTask(stack2);
return true;
}).when(mSupervisor).removeTask(eq(task2), anyBoolean(), anyBoolean(), any());
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index 53ade0ea64be..2f34f708a562 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -71,6 +71,7 @@ import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.isA;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.never;
@@ -154,7 +155,7 @@ public class ActivityRecordTests extends WindowTestsBase {
final Task rootTask = activity.getRootTask();
rootTask.removeChild(task, null /*reason*/);
// parentTask should be gone on task removal.
- assertNull(mAtm.mRootWindowContainer.getStack(rootTask.mTaskId));
+ assertNull(mAtm.mRootWindowContainer.getRootTask(rootTask.mTaskId));
}
@Test
@@ -376,6 +377,28 @@ public class ActivityRecordTests extends WindowTestsBase {
}
@Test
+ public void testDestroyedActivityNotScheduleConfigChanged() throws RemoteException {
+ final ActivityRecord activity = new ActivityBuilder(mAtm)
+ .setCreateTask(true)
+ .setConfigChanges(CONFIG_ORIENTATION)
+ .build();
+ final Task task = activity.getTask();
+ activity.setState(DESTROYED, "Testing");
+ clearInvocations(mAtm.getLifecycleManager());
+
+ final Configuration newConfig = new Configuration(task.getConfiguration());
+ newConfig.orientation = newConfig.orientation == ORIENTATION_PORTRAIT
+ ? ORIENTATION_LANDSCAPE
+ : ORIENTATION_PORTRAIT;
+ task.onRequestedOverrideConfigurationChanged(newConfig);
+
+ ensureActivityConfiguration(activity);
+
+ verify(mAtm.getLifecycleManager(), never())
+ .scheduleTransaction(any(), any(), isA(ActivityConfigurationChangeItem.class));
+ }
+
+ @Test
public void testSetRequestedOrientationUpdatesConfiguration() throws Exception {
final ActivityRecord activity = new ActivityBuilder(mAtm)
.setCreateTask(true)
@@ -386,6 +409,7 @@ public class ActivityRecordTests extends WindowTestsBase {
activity.setLastReportedConfiguration(new MergedConfiguration(new Configuration(),
activity.getConfiguration()));
+ clearInvocations(mAtm.getLifecycleManager());
final Configuration newConfig = new Configuration(activity.getConfiguration());
final int shortSide = Math.min(newConfig.screenWidthDp, newConfig.screenHeightDp);
final int longSide = Math.max(newConfig.screenWidthDp, newConfig.screenHeightDp);
@@ -401,7 +425,7 @@ public class ActivityRecordTests extends WindowTestsBase {
// Mimic the behavior that display doesn't handle app's requested orientation.
final DisplayContent dc = activity.getTask().getDisplayContent();
- doReturn(false).when(dc).onDescendantOrientationChanged(any(), any());
+ doReturn(false).when(dc).onDescendantOrientationChanged(any());
doReturn(false).when(dc).handlesOrientationChangeFromDescendant();
final int requestedOrientation;
@@ -574,6 +598,7 @@ public class ActivityRecordTests extends WindowTestsBase {
final Task stack = new TaskBuilder(mSupervisor).setCreateActivity(true).build();
try {
+ clearInvocations(mAtm.getLifecycleManager());
doReturn(false).when(stack).isTranslucent(any());
assertTrue(task.shouldBeVisible(null /* starting */));
@@ -853,7 +878,7 @@ public class ActivityRecordTests extends WindowTestsBase {
topRootableTask.moveToFront("test");
assertTrue(topRootableTask.isTopStackInDisplayArea());
assertEquals(topRootableTask, topActivityOnNonTopDisplay.getDisplayArea()
- .mPreferredTopFocusableStack);
+ .mPreferredTopFocusableRootTask);
final ActivityRecord secondaryDisplayActivity =
createActivityOnDisplay(false /* defaultDisplay */, null /* process */);
@@ -861,7 +886,7 @@ public class ActivityRecordTests extends WindowTestsBase {
topRootableTask.moveToFront("test");
assertTrue(topRootableTask.isTopStackInDisplayArea());
assertEquals(topRootableTask,
- secondaryDisplayActivity.getDisplayArea().mPreferredTopFocusableStack);
+ secondaryDisplayActivity.getDisplayArea().mPreferredTopFocusableRootTask);
// The global top focus activity is on secondary display now.
// Finish top activity on default display and verify the next preferred top focusable stack
@@ -870,7 +895,7 @@ public class ActivityRecordTests extends WindowTestsBase {
topActivityOnNonTopDisplay.finishIfPossible(0 /* resultCode */, null /* resultData */,
null /* resultGrants */, "test", false /* oomAdj */);
assertEquals(task, task.getTopMostTask());
- assertEquals(task, activity.getDisplayArea().mPreferredTopFocusableStack);
+ assertEquals(task, activity.getDisplayArea().mPreferredTopFocusableRootTask);
}
/**
@@ -1275,7 +1300,7 @@ public class ActivityRecordTests extends WindowTestsBase {
@Test
public void testDestroyIfPossible() {
final ActivityRecord activity = createActivityWithTask();
- doReturn(false).when(mRootWindowContainer).resumeFocusedStacksTopActivities();
+ doReturn(false).when(mRootWindowContainer).resumeFocusedTasksTopActivities();
activity.destroyIfPossible("test");
assertEquals(DESTROYING, activity.getState());
@@ -1297,7 +1322,7 @@ public class ActivityRecordTests extends WindowTestsBase {
homeStack.removeChild(t, "test");
}, true /* traverseTopToBottom */);
activity.finishing = true;
- doReturn(false).when(mRootWindowContainer).resumeFocusedStacksTopActivities();
+ doReturn(false).when(mRootWindowContainer).resumeFocusedTasksTopActivities();
// Try to destroy the last activity above the home stack.
activity.destroyIfPossible("test");
@@ -1658,7 +1683,7 @@ public class ActivityRecordTests extends WindowTestsBase {
final int rotatedOrentation = r.getConfiguration().orientation == ORIENTATION_PORTRAIT
? SCREEN_ORIENTATION_LANDSCAPE
: SCREEN_ORIENTATION_PORTRAIT;
- doReturn(false).when(r).onDescendantOrientationChanged(any(), any());
+ doReturn(false).when(r).onDescendantOrientationChanged(any());
r.setOrientation(rotatedOrentation);
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
index 8ccbb8fe62ad..8e3e668804ff 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
@@ -48,7 +48,7 @@ import static com.android.server.wm.Task.REPARENT_MOVE_ROOT_TASK_TO_FRONT;
import static com.android.server.wm.Task.TASK_VISIBILITY_INVISIBLE;
import static com.android.server.wm.Task.TASK_VISIBILITY_VISIBLE;
import static com.android.server.wm.Task.TASK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT;
-import static com.android.server.wm.TaskDisplayArea.getStackAbove;
+import static com.android.server.wm.TaskDisplayArea.getRootTaskAbove;
import static com.android.server.wm.WindowContainer.POSITION_BOTTOM;
import static com.android.server.wm.WindowContainer.POSITION_TOP;
@@ -74,6 +74,8 @@ import android.platform.test.annotations.Presubmit;
import androidx.test.filters.SmallTest;
+import com.android.server.wm.TaskDisplayArea.OnRootTaskOrderChangedListener;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -154,7 +156,7 @@ public class ActivityStackTests extends WindowTestsBase {
organizer.setMoveToSecondaryOnEnter(false);
// Create primary splitscreen stack.
- final Task primarySplitScreen = mDefaultTaskDisplayArea.createStack(
+ final Task primarySplitScreen = mDefaultTaskDisplayArea.createRootTask(
WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD, true /* onTop */);
// Assert windowing mode.
@@ -179,7 +181,7 @@ public class ActivityStackTests extends WindowTestsBase {
public void testMoveToPrimarySplitScreenThenMoveToBack() {
TestSplitOrganizer organizer = new TestSplitOrganizer(mAtm);
// This time, start with a fullscreen activitystack
- final Task primarySplitScreen = mDefaultTaskDisplayArea.createStack(
+ final Task primarySplitScreen = mDefaultTaskDisplayArea.createRootTask(
WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD, true /* onTop */);
primarySplitScreen.reparent(organizer.mPrimary, POSITION_TOP,
@@ -205,11 +207,11 @@ public class ActivityStackTests extends WindowTestsBase {
TestSplitOrganizer organizer = new TestSplitOrganizer(mAtm);
// Set up split-screen with primary on top and secondary containing the home task below
// another stack.
- final Task primaryTask = mDefaultTaskDisplayArea.createStack(
+ final Task primaryTask = mDefaultTaskDisplayArea.createRootTask(
WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD, true /* onTop */);
- final Task homeRoot = mDefaultTaskDisplayArea.getStack(
+ final Task homeRoot = mDefaultTaskDisplayArea.getRootTask(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME);
- final Task secondaryTask = mDefaultTaskDisplayArea.createStack(
+ final Task secondaryTask = mDefaultTaskDisplayArea.createRootTask(
WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, ACTIVITY_TYPE_STANDARD, true /* onTop */);
mDefaultTaskDisplayArea.positionChildAt(POSITION_TOP, organizer.mPrimary,
false /* includingParents */);
@@ -257,7 +259,7 @@ public class ActivityStackTests extends WindowTestsBase {
@Test
public void testStackInheritsDisplayWindowingMode() {
- final Task primarySplitScreen = mDefaultTaskDisplayArea.createStack(
+ final Task primarySplitScreen = mDefaultTaskDisplayArea.createRootTask(
WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD, true /* onTop */);
assertEquals(WINDOWING_MODE_FULLSCREEN, primarySplitScreen.getWindowingMode());
@@ -272,7 +274,7 @@ public class ActivityStackTests extends WindowTestsBase {
@Test
public void testStackOverridesDisplayWindowingMode() {
- final Task primarySplitScreen = mDefaultTaskDisplayArea.createStack(
+ final Task primarySplitScreen = mDefaultTaskDisplayArea.createRootTask(
WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD, true /* onTop */);
assertEquals(WINDOWING_MODE_FULLSCREEN, primarySplitScreen.getWindowingMode());
@@ -365,7 +367,7 @@ public class ActivityStackTests extends WindowTestsBase {
verify(stack2).positionChildAtBottom(any(), eq(false) /* includingParents */);
// Also move display to back because there is only one stack left.
- taskDisplayArea.removeStack(stack1);
+ taskDisplayArea.removeRootTask(stack1);
stack2.moveToBack("testMoveStackToBackIncludingParent", stack2.getTopMostTask());
verify(stack2).positionChildAtBottom(any(), eq(true) /* includingParents */);
}
@@ -747,8 +749,8 @@ public class ActivityStackTests extends WindowTestsBase {
// Ensure that we don't move the home stack if it is already behind the top fullscreen stack
int homeStackIndex = mDefaultTaskDisplayArea.getIndexOf(homeStack);
- assertEquals(fullscreenStack, getStackAbove(homeStack));
- mDefaultTaskDisplayArea.moveStackBehindBottomMostVisibleStack(homeStack);
+ assertEquals(fullscreenStack, getRootTaskAbove(homeStack));
+ mDefaultTaskDisplayArea.moveRootTaskBehindBottomMostVisibleRootTask(homeStack);
assertEquals(homeStackIndex, mDefaultTaskDisplayArea.getIndexOf(homeStack));
}
@@ -765,8 +767,8 @@ public class ActivityStackTests extends WindowTestsBase {
// Ensure that we don't move the home stack if it is already behind the top fullscreen stack
int homeStackIndex = mDefaultTaskDisplayArea.getIndexOf(homeStack);
- assertEquals(fullscreenStack, getStackAbove(homeStack));
- mDefaultTaskDisplayArea.moveStackBehindBottomMostVisibleStack(homeStack);
+ assertEquals(fullscreenStack, getRootTaskAbove(homeStack));
+ mDefaultTaskDisplayArea.moveRootTaskBehindBottomMostVisibleRootTask(homeStack);
assertEquals(homeStackIndex, mDefaultTaskDisplayArea.getIndexOf(homeStack));
}
@@ -783,8 +785,8 @@ public class ActivityStackTests extends WindowTestsBase {
// Ensure we don't move the home stack if it is already on top
int homeStackIndex = mDefaultTaskDisplayArea.getIndexOf(homeStack);
- assertNull(getStackAbove(homeStack));
- mDefaultTaskDisplayArea.moveStackBehindBottomMostVisibleStack(homeStack);
+ assertNull(getRootTaskAbove(homeStack));
+ mDefaultTaskDisplayArea.moveRootTaskBehindBottomMostVisibleRootTask(homeStack);
assertEquals(homeStackIndex, mDefaultTaskDisplayArea.getIndexOf(homeStack));
}
@@ -807,9 +809,9 @@ public class ActivityStackTests extends WindowTestsBase {
// Ensure that we move the home stack behind the bottom most fullscreen stack, ignoring the
// pinned stack
- assertEquals(fullscreenStack1, getStackAbove(homeStack));
- mDefaultTaskDisplayArea.moveStackBehindBottomMostVisibleStack(homeStack);
- assertEquals(fullscreenStack2, getStackAbove(homeStack));
+ assertEquals(fullscreenStack1, getRootTaskAbove(homeStack));
+ mDefaultTaskDisplayArea.moveRootTaskBehindBottomMostVisibleRootTask(homeStack);
+ assertEquals(fullscreenStack2, getRootTaskAbove(homeStack));
}
@Test
@@ -830,9 +832,9 @@ public class ActivityStackTests extends WindowTestsBase {
// Ensure that we move the home stack behind the bottom most non-translucent fullscreen
// stack
- assertEquals(fullscreenStack1, getStackAbove(homeStack));
- mDefaultTaskDisplayArea.moveStackBehindBottomMostVisibleStack(homeStack);
- assertEquals(fullscreenStack1, getStackAbove(homeStack));
+ assertEquals(fullscreenStack1, getRootTaskAbove(homeStack));
+ mDefaultTaskDisplayArea.moveRootTaskBehindBottomMostVisibleRootTask(homeStack);
+ assertEquals(fullscreenStack1, getRootTaskAbove(homeStack));
}
@Test
@@ -852,7 +854,7 @@ public class ActivityStackTests extends WindowTestsBase {
// Ensure we don't move the home stack behind itself
int homeStackIndex = mDefaultTaskDisplayArea.getIndexOf(homeStack);
- mDefaultTaskDisplayArea.moveStackBehindStack(homeStack, homeStack);
+ mDefaultTaskDisplayArea.moveRootTaskBehindRootTask(homeStack, homeStack);
assertEquals(homeStackIndex, mDefaultTaskDisplayArea.getIndexOf(homeStack));
}
@@ -873,14 +875,14 @@ public class ActivityStackTests extends WindowTestsBase {
final Task homeStack = createStackForShouldBeVisibleTest(mDefaultTaskDisplayArea,
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */);
- mDefaultTaskDisplayArea.moveStackBehindStack(homeStack, fullscreenStack1);
- assertEquals(fullscreenStack1, getStackAbove(homeStack));
- mDefaultTaskDisplayArea.moveStackBehindStack(homeStack, fullscreenStack2);
- assertEquals(fullscreenStack2, getStackAbove(homeStack));
- mDefaultTaskDisplayArea.moveStackBehindStack(homeStack, fullscreenStack4);
- assertEquals(fullscreenStack4, getStackAbove(homeStack));
- mDefaultTaskDisplayArea.moveStackBehindStack(homeStack, fullscreenStack2);
- assertEquals(fullscreenStack2, getStackAbove(homeStack));
+ mDefaultTaskDisplayArea.moveRootTaskBehindRootTask(homeStack, fullscreenStack1);
+ assertEquals(fullscreenStack1, getRootTaskAbove(homeStack));
+ mDefaultTaskDisplayArea.moveRootTaskBehindRootTask(homeStack, fullscreenStack2);
+ assertEquals(fullscreenStack2, getRootTaskAbove(homeStack));
+ mDefaultTaskDisplayArea.moveRootTaskBehindRootTask(homeStack, fullscreenStack4);
+ assertEquals(fullscreenStack4, getRootTaskAbove(homeStack));
+ mDefaultTaskDisplayArea.moveRootTaskBehindRootTask(homeStack, fullscreenStack2);
+ assertEquals(fullscreenStack2, getRootTaskAbove(homeStack));
}
@Test
@@ -889,7 +891,7 @@ public class ActivityStackTests extends WindowTestsBase {
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */);
final Task pinnedStack = createStackForShouldBeVisibleTest(mDefaultTaskDisplayArea,
WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, true /* onTop */);
- assertEquals(pinnedStack, getStackAbove(homeStack));
+ assertEquals(pinnedStack, getRootTaskAbove(homeStack));
final Task alwaysOnTopStack = createStackForShouldBeVisibleTest(
mDefaultTaskDisplayArea, WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD,
@@ -897,13 +899,13 @@ public class ActivityStackTests extends WindowTestsBase {
alwaysOnTopStack.setAlwaysOnTop(true);
assertTrue(alwaysOnTopStack.isAlwaysOnTop());
// Ensure (non-pinned) always on top stack is put below pinned stack.
- assertEquals(pinnedStack, getStackAbove(alwaysOnTopStack));
+ assertEquals(pinnedStack, getRootTaskAbove(alwaysOnTopStack));
final Task nonAlwaysOnTopStack = createStackForShouldBeVisibleTest(
mDefaultTaskDisplayArea, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD,
true /* onTop */);
// Ensure non always on top stack is put below always on top stacks.
- assertEquals(alwaysOnTopStack, getStackAbove(nonAlwaysOnTopStack));
+ assertEquals(alwaysOnTopStack, getRootTaskAbove(nonAlwaysOnTopStack));
final Task alwaysOnTopStack2 = createStackForShouldBeVisibleTest(
mDefaultTaskDisplayArea, WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD,
@@ -911,21 +913,21 @@ public class ActivityStackTests extends WindowTestsBase {
alwaysOnTopStack2.setAlwaysOnTop(true);
assertTrue(alwaysOnTopStack2.isAlwaysOnTop());
// Ensure newly created always on top stack is placed above other all always on top stacks.
- assertEquals(pinnedStack, getStackAbove(alwaysOnTopStack2));
+ assertEquals(pinnedStack, getRootTaskAbove(alwaysOnTopStack2));
alwaysOnTopStack2.setAlwaysOnTop(false);
// Ensure, when always on top is turned off for a stack, the stack is put just below all
// other always on top stacks.
- assertEquals(alwaysOnTopStack, getStackAbove(alwaysOnTopStack2));
+ assertEquals(alwaysOnTopStack, getRootTaskAbove(alwaysOnTopStack2));
alwaysOnTopStack2.setAlwaysOnTop(true);
// Ensure always on top state changes properly when windowing mode changes.
alwaysOnTopStack2.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
assertFalse(alwaysOnTopStack2.isAlwaysOnTop());
- assertEquals(alwaysOnTopStack, getStackAbove(alwaysOnTopStack2));
+ assertEquals(alwaysOnTopStack, getRootTaskAbove(alwaysOnTopStack2));
alwaysOnTopStack2.setWindowingMode(WINDOWING_MODE_FREEFORM);
assertTrue(alwaysOnTopStack2.isAlwaysOnTop());
- assertEquals(pinnedStack, getStackAbove(alwaysOnTopStack2));
+ assertEquals(pinnedStack, getRootTaskAbove(alwaysOnTopStack2));
}
@Test
@@ -980,7 +982,8 @@ public class ActivityStackTests extends WindowTestsBase {
int windowingMode, int activityType, boolean onTop, boolean twoLevelTask) {
final Task task;
if (activityType == ACTIVITY_TYPE_HOME) {
- task = mDefaultTaskDisplayArea.getStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME);
+ task = mDefaultTaskDisplayArea.getRootTask(WINDOWING_MODE_FULLSCREEN,
+ ACTIVITY_TYPE_HOME);
mDefaultTaskDisplayArea.positionChildAt(onTop ? POSITION_TOP : POSITION_BOTTOM, task,
false /* includingParents */);
} else if (twoLevelTask) {
@@ -1224,12 +1227,12 @@ public class ActivityStackTests extends WindowTestsBase {
@Test
public void testStackOrderChangedOnRemoveStack() {
final Task task = new TaskBuilder(mSupervisor).build();
- StackOrderChangedListener listener = new StackOrderChangedListener();
- mDefaultTaskDisplayArea.registerStackOrderChangedListener(listener);
+ RootTaskOrderChangedListener listener = new RootTaskOrderChangedListener();
+ mDefaultTaskDisplayArea.registerRootTaskOrderChangedListener(listener);
try {
- mDefaultTaskDisplayArea.removeStack(task);
+ mDefaultTaskDisplayArea.removeRootTask(task);
} finally {
- mDefaultTaskDisplayArea.unregisterStackOrderChangedListener(listener);
+ mDefaultTaskDisplayArea.unregisterRootTaskOrderChangedListener(listener);
}
assertTrue(listener.mChanged);
}
@@ -1237,31 +1240,31 @@ public class ActivityStackTests extends WindowTestsBase {
@Test
public void testStackOrderChangedOnAddPositionStack() {
final Task task = new TaskBuilder(mSupervisor).build();
- mDefaultTaskDisplayArea.removeStack(task);
+ mDefaultTaskDisplayArea.removeRootTask(task);
- StackOrderChangedListener listener = new StackOrderChangedListener();
- mDefaultTaskDisplayArea.registerStackOrderChangedListener(listener);
+ RootTaskOrderChangedListener listener = new RootTaskOrderChangedListener();
+ mDefaultTaskDisplayArea.registerRootTaskOrderChangedListener(listener);
try {
task.mReparenting = true;
mDefaultTaskDisplayArea.addChild(task, 0);
} finally {
- mDefaultTaskDisplayArea.unregisterStackOrderChangedListener(listener);
+ mDefaultTaskDisplayArea.unregisterRootTaskOrderChangedListener(listener);
}
assertTrue(listener.mChanged);
}
@Test
public void testStackOrderChangedOnPositionStack() {
- StackOrderChangedListener listener = new StackOrderChangedListener();
+ RootTaskOrderChangedListener listener = new RootTaskOrderChangedListener();
try {
final Task fullscreenStack1 = createStackForShouldBeVisibleTest(
mDefaultTaskDisplayArea, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD,
true /* onTop */);
- mDefaultTaskDisplayArea.registerStackOrderChangedListener(listener);
+ mDefaultTaskDisplayArea.registerRootTaskOrderChangedListener(listener);
mDefaultTaskDisplayArea.positionChildAt(POSITION_BOTTOM, fullscreenStack1,
false /*includingParents*/);
} finally {
- mDefaultTaskDisplayArea.unregisterStackOrderChangedListener(listener);
+ mDefaultTaskDisplayArea.unregisterRootTaskOrderChangedListener(listener);
}
assertTrue(listener.mChanged);
}
@@ -1447,12 +1450,12 @@ public class ActivityStackTests extends WindowTestsBase {
assertEquals(expected, task.shouldSleepActivities());
}
- private static class StackOrderChangedListener
- implements TaskDisplayArea.OnStackOrderChangedListener {
+ private static class RootTaskOrderChangedListener
+ implements OnRootTaskOrderChangedListener {
public boolean mChanged = false;
@Override
- public void onStackOrderChanged(Task stack) {
+ public void onRootTaskOrderChanged(Task rootTask) {
mChanged = true;
}
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStartControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStartControllerTests.java
index c799f2902547..ce96771c8c27 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStartControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStartControllerTests.java
@@ -33,8 +33,8 @@ import android.platform.test.annotations.Presubmit;
import androidx.test.filters.SmallTest;
-import com.android.server.wm.ActivityTaskSupervisor.PendingActivityLaunch;
import com.android.server.wm.ActivityStarter.Factory;
+import com.android.server.wm.ActivityTaskSupervisor.PendingActivityLaunch;
import org.junit.Before;
import org.junit.Test;
@@ -77,8 +77,8 @@ public class ActivityStartControllerTests extends WindowTestsBase {
.setCreateTask(true)
.build();
final int startFlags = random.nextInt();
- final Task stack = mAtm.mRootWindowContainer.getDefaultTaskDisplayArea()
- .createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
+ final Task rootTask = mAtm.mRootWindowContainer.getDefaultTaskDisplayArea().createRootTask(
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
final WindowProcessController wpc = new WindowProcessController(mAtm,
mAtm.mContext.getApplicationInfo(), "name", 12345,
UserHandle.getUserId(12345), mock(Object.class),
@@ -86,7 +86,7 @@ public class ActivityStartControllerTests extends WindowTestsBase {
wpc.setThread(mock(IApplicationThread.class));
mController.addPendingActivityLaunch(
- new PendingActivityLaunch(activity, source, startFlags, stack, wpc, null));
+ new PendingActivityLaunch(activity, source, startFlags, rootTask, wpc, null));
final boolean resume = random.nextBoolean();
mController.doPendingActivityLaunches(resume);
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
index 565bf8b615c7..ef2e88913914 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -326,7 +326,7 @@ public class ActivityStarterTests extends WindowTestsBase {
* Creates a {@link ActivityStarter} with default parameters and necessary mocks.
*
* @param launchFlags The intent flags to launch activity.
- * @param mockGetLaunchStack Whether to mock {@link RootWindowContainer#getLaunchStack} for
+ * @param mockGetLaunchStack Whether to mock {@link RootWindowContainer#getLaunchRootTask} for
* always launching to the testing stack. Set to false when allowing
* the activity can be launched to any stack that is decided by real
* implementation.
@@ -342,14 +342,14 @@ public class ActivityStarterTests extends WindowTestsBase {
if (mockGetLaunchStack) {
// Instrument the stack and task used.
final Task stack = mRootWindowContainer.getDefaultTaskDisplayArea()
- .createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD,
+ .createRootTask(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD,
true /* onTop */);
// Direct starter to use spy stack.
doReturn(stack).when(mRootWindowContainer)
- .getLaunchStack(any(), any(), any(), anyBoolean());
- doReturn(stack).when(mRootWindowContainer)
- .getLaunchStack(any(), any(), any(), anyBoolean(), any(), anyInt(), anyInt());
+ .getLaunchRootTask(any(), any(), any(), anyBoolean());
+ doReturn(stack).when(mRootWindowContainer).getLaunchRootTask(any(), any(), any(),
+ anyBoolean(), any(), anyInt(), anyInt());
}
// Set up mock package manager internal and make sure no unmocked methods are called
@@ -513,8 +513,8 @@ public class ActivityStarterTests extends WindowTestsBase {
private void assertNoTasks(DisplayContent display) {
display.forAllTaskDisplayAreas(taskDisplayArea -> {
- for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {
- final Task stack = taskDisplayArea.getStackAt(sNdx);
+ for (int sNdx = taskDisplayArea.getRootTaskCount() - 1; sNdx >= 0; --sNdx) {
+ final Task stack = taskDisplayArea.getRootTaskAt(sNdx);
assertFalse(stack.hasChild());
}
});
@@ -806,7 +806,7 @@ public class ActivityStarterTests extends WindowTestsBase {
new TestDisplayContent.Builder(mAtm, 1000, 1500)
.setPosition(POSITION_BOTTOM).build();
final TaskDisplayArea secondaryTaskContainer = secondaryDisplay.getDefaultTaskDisplayArea();
- final Task stack = secondaryTaskContainer.createStack(
+ final Task stack = secondaryTaskContainer.createRootTask(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
// Create an activity record on the top of secondary display.
@@ -828,7 +828,7 @@ public class ActivityStarterTests extends WindowTestsBase {
assertEquals(START_DELIVERED_TO_TOP, result);
// Ensure secondary display only creates one stack.
- verify(secondaryTaskContainer, times(1)).createStack(anyInt(), anyInt(), anyBoolean());
+ verify(secondaryTaskContainer, times(1)).createRootTask(anyInt(), anyInt(), anyBoolean());
}
/**
@@ -848,11 +848,11 @@ public class ActivityStarterTests extends WindowTestsBase {
false /* includingParents */);
final TaskDisplayArea secondaryTaskContainer = secondaryDisplay.getDefaultTaskDisplayArea();
final ActivityRecord singleTaskActivity = createSingleTaskActivityOn(
- secondaryTaskContainer.createStack(WINDOWING_MODE_FULLSCREEN,
+ secondaryTaskContainer.createRootTask(WINDOWING_MODE_FULLSCREEN,
ACTIVITY_TYPE_STANDARD, false /* onTop */));
// Create another activity on top of the secondary display.
- final Task topStack = secondaryTaskContainer.createStack(WINDOWING_MODE_FULLSCREEN,
+ final Task topStack = secondaryTaskContainer.createRootTask(WINDOWING_MODE_FULLSCREEN,
ACTIVITY_TYPE_STANDARD, true /* onTop */);
final Task topTask = new TaskBuilder(mSupervisor).setParentTask(topStack).build();
new ActivityBuilder(mAtm).setTask(topTask).build();
@@ -870,7 +870,7 @@ public class ActivityStarterTests extends WindowTestsBase {
assertEquals(START_TASK_TO_FRONT, result);
// Ensure secondary display only creates two stacks.
- verify(secondaryTaskContainer, times(2)).createStack(anyInt(), anyInt(), anyBoolean());
+ verify(secondaryTaskContainer, times(2)).createRootTask(anyInt(), anyInt(), anyBoolean());
// The metrics logger should receive the same result and non-null options.
verify(mActivityMetricsLogger).notifyActivityLaunched(any() /* launchingState */,
eq(result), eq(singleTaskActivity), notNull() /* options */);
@@ -938,7 +938,7 @@ public class ActivityStarterTests extends WindowTestsBase {
// Create a secondary display at bottom.
final TestDisplayContent secondaryDisplay = addNewDisplayContentAt(POSITION_BOTTOM);
final TaskDisplayArea secondaryTaskContainer = secondaryDisplay.getDefaultTaskDisplayArea();
- secondaryTaskContainer.createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD,
+ secondaryTaskContainer.createRootTask(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD,
true /* onTop */);
// Put an activity on default display as the top focused activity.
@@ -1053,7 +1053,7 @@ public class ActivityStarterTests extends WindowTestsBase {
final ActivityStarter starter = prepareStarter(0 /* flags */);
starter.mStartActivity = new ActivityBuilder(mAtm).build();
final Task task = new TaskBuilder(mAtm.mTaskSupervisor)
- .setParentTask(mAtm.mRootWindowContainer.getDefaultTaskDisplayArea().createStack(
+ .setParentTask(mAtm.mRootWindowContainer.getDefaultTaskDisplayArea().createRootTask(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */))
.setUserId(10)
.build();
@@ -1117,13 +1117,13 @@ public class ActivityStarterTests extends WindowTestsBase {
final Task stack = spy(
mRootWindowContainer.getDefaultTaskDisplayArea()
- .createStack(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD,
+ .createRootTask(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD,
/* onTop */true));
stack.addChild(targetRecord);
doReturn(stack).when(mRootWindowContainer)
- .getLaunchStack(any(), any(), any(), anyBoolean(), any(), anyInt(), anyInt());
+ .getLaunchRootTask(any(), any(), any(), anyBoolean(), any(), anyInt(), anyInt());
starter.mStartActivity = new ActivityBuilder(mAtm).build();
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
index 6ca69bf974d5..8cc515e83342 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
@@ -196,7 +196,7 @@ public class AppTransitionTests extends WindowTestsBase {
@Test
public void testCancelRemoteAnimationWhenFreeze() {
final DisplayContent dc = createNewDisplay(Display.STATE_ON);
- doReturn(false).when(dc).onDescendantOrientationChanged(any(), any());
+ doReturn(false).when(dc).onDescendantOrientationChanged(any());
final WindowState exitingAppWindow = createWindow(null /* parent */, TYPE_BASE_APPLICATION,
dc, "exiting app");
final ActivityRecord exitingActivity= exitingAppWindow.mActivityRecord;
diff --git a/services/tests/wmtests/src/com/android/server/wm/ConfigurationContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/ConfigurationContainerTests.java
index 5828d02948a1..59b12e406d70 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ConfigurationContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ConfigurationContainerTests.java
@@ -366,6 +366,30 @@ public class ConfigurationContainerTests {
assertTrue(child.getConfiguration().windowConfiguration.getMaxBounds().isEmpty());
}
+ @Test
+ public void testOnRequestedOverrideConfigurationChangedOverrideMaxBounds() {
+ final TestConfigurationContainer root =
+ new TestConfigurationContainer(true /* providesMaxBounds */);
+ final Rect bounds = new Rect(0, 0, 10, 10);
+ final TestConfigurationContainer child = new TestConfigurationContainer();
+ root.addChild(child);
+ final Configuration configuration = new Configuration();
+ configuration.windowConfiguration.setBounds(bounds);
+
+ root.onRequestedOverrideConfigurationChanged(configuration);
+
+ assertEquals(bounds, root.getBounds());
+ assertEquals(bounds, root.getConfiguration().windowConfiguration.getBounds());
+ assertEquals(bounds, child.getBounds());
+ assertEquals(bounds, child.getConfiguration().windowConfiguration.getBounds());
+
+ assertEquals(bounds, root.getMaxBounds());
+ assertEquals(bounds, root.getConfiguration().windowConfiguration.getMaxBounds());
+ assertEquals(bounds, child.getMaxBounds());
+ assertEquals(bounds, child.getConfiguration().windowConfiguration.getMaxBounds());
+ }
+
+
/**
* Contains minimal implementation of {@link ConfigurationContainer}'s abstract behavior needed
* for testing.
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaGroupTest.java b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaGroupTest.java
index 06a6882dc698..bc91c709aeb1 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaGroupTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaGroupTest.java
@@ -87,7 +87,7 @@ public class DisplayAreaGroupTest extends WindowTestsBase {
final Task task = new TaskBuilder(mSupervisor)
.setTaskDisplayArea(mTaskDisplayArea).setCreateActivity(true).build();
final ActivityRecord activity = task.getTopNonFinishingActivity();
- doReturn(true).when(mDisplayContent).onDescendantOrientationChanged(any(), any());
+ doReturn(true).when(mDisplayContent).onDescendantOrientationChanged(any());
activity.setRequestedOrientation(SCREEN_ORIENTATION_PORTRAIT);
// Display is portrait, DisplayAreaGroup inherits that
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaPolicyTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaPolicyTests.java
index 39bf8eb857b0..5a47493c12cd 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaPolicyTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaPolicyTests.java
@@ -94,9 +94,9 @@ public class DisplayAreaPolicyTests {
@Test
public void testTaskDisplayArea_taskPositionChanged_updatesTaskDisplayAreaPosition() {
- final Task stack1 = mTaskDisplayArea1.createStack(
+ final Task stack1 = mTaskDisplayArea1.createRootTask(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
- final Task stack2 = mTaskDisplayArea2.createStack(
+ final Task stack2 = mTaskDisplayArea2.createRootTask(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
// Initial order
@@ -155,11 +155,11 @@ public class DisplayAreaPolicyTests {
.addDisplayAreaGroupHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(group2)
.setTaskDisplayAreas(Lists.newArrayList(taskDisplayArea5)))
.build(wms);
- final Task stack1 = taskDisplayArea1.createStack(
+ final Task stack1 = taskDisplayArea1.createRootTask(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
- final Task stack3 = taskDisplayArea3.createStack(
+ final Task stack3 = taskDisplayArea3.createRootTask(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
- final Task stack4 = taskDisplayArea4.createStack(
+ final Task stack4 = taskDisplayArea4.createRootTask(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
// Initial order
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaTest.java b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaTest.java
index 59b2d4fc282b..025c5a6bb180 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaTest.java
@@ -468,14 +468,14 @@ public class DisplayAreaTest extends WindowTestsBase {
activity.setRequestedOrientation(SCREEN_ORIENTATION_LANDSCAPE);
- verify(tda).onDescendantOrientationChanged(any(), any());
- verify(mDisplayContent, never()).onDescendantOrientationChanged(any(), any());
+ verify(tda).onDescendantOrientationChanged(any());
+ verify(mDisplayContent, never()).onDescendantOrientationChanged(any());
tda.setIgnoreOrientationRequest(false /* ignoreOrientationRequest */);
activity.setRequestedOrientation(SCREEN_ORIENTATION_PORTRAIT);
- verify(tda, times(2)).onDescendantOrientationChanged(any(), any());
- verify(mDisplayContent).onDescendantOrientationChanged(any(), any());
+ verify(tda, times(2)).onDescendantOrientationChanged(any());
+ verify(mDisplayContent).onDescendantOrientationChanged(any());
}
private static class TestDisplayArea<T extends WindowContainer> extends DisplayArea<T> {
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
index d9217188582f..2053bfb45884 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -839,12 +839,12 @@ public class DisplayContentTests extends WindowTestsBase {
final DisplayContent newDisplay = createNewDisplay();
final WindowState appWin = createWindow(null, TYPE_APPLICATION, mDisplayContent, "appWin");
- final Task stack = mDisplayContent.getTopStack();
+ final Task stack = mDisplayContent.getTopRootTask();
final ActivityRecord activity = stack.topRunningActivity();
doReturn(true).when(activity).shouldBeVisibleUnchecked();
final WindowState appWin1 = createWindow(null, TYPE_APPLICATION, newDisplay, "appWin1");
- final Task stack1 = newDisplay.getTopStack();
+ final Task stack1 = newDisplay.getTopRootTask();
final ActivityRecord activity1 = stack1.topRunningActivity();
doReturn(true).when(activity1).shouldBeVisibleUnchecked();
appWin.setHasSurface(true);
@@ -886,7 +886,7 @@ public class DisplayContentTests extends WindowTestsBase {
doReturn(true).when(freeformStack).isVisible();
freeformStack.getTopChild().setBounds(100, 100, 300, 400);
- assertTrue(dc.getDefaultTaskDisplayArea().isStackVisible(WINDOWING_MODE_FREEFORM));
+ assertTrue(dc.getDefaultTaskDisplayArea().isRootTaskVisible(WINDOWING_MODE_FREEFORM));
freeformStack.getTopNonFinishingActivity().setOrientation(SCREEN_ORIENTATION_LANDSCAPE);
stack.getTopNonFinishingActivity().setOrientation(SCREEN_ORIENTATION_PORTRAIT);
@@ -1202,6 +1202,17 @@ public class DisplayContentTests extends WindowTestsBase {
assertTrue(mNavBarWindow.getParent().isAnimating(WindowContainer.AnimationFlags.PARENTS,
ANIMATION_TYPE_FIXED_TRANSFORM));
+ // If the visibility of insets state is changed, the rotated state should be updated too.
+ final InsetsState rotatedState = app.getFixedRotationTransformInsetsState();
+ final InsetsState state = mDisplayContent.getInsetsStateController().getRawInsetsState();
+ assertEquals(state.getSource(ITYPE_STATUS_BAR).isVisible(),
+ rotatedState.getSource(ITYPE_STATUS_BAR).isVisible());
+ state.getSource(ITYPE_STATUS_BAR).setVisible(
+ !rotatedState.getSource(ITYPE_STATUS_BAR).isVisible());
+ mDisplayContent.getInsetsStateController().notifyInsetsChanged();
+ assertEquals(state.getSource(ITYPE_STATUS_BAR).isVisible(),
+ rotatedState.getSource(ITYPE_STATUS_BAR).isVisible());
+
final Rect outFrame = new Rect();
final Rect outInsets = new Rect();
final Rect outStableInsets = new Rect();
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
index 21bdc9e7785e..79b2da187680 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
@@ -236,8 +236,7 @@ public class DisplayPolicyTests extends WindowTestsBase {
final WindowState activity = createBaseApplicationWindow();
activity.mAttrs.privateFlags |= PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS;
- policy.adjustWindowParamsLw(activity, activity.mAttrs, 0 /* callingPid */,
- 0 /* callingUid */);
+ policy.adjustWindowParamsLw(activity, activity.mAttrs);
}
private WindowState createApplicationWindow() {
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTestsBase.java
index 94ffcdab4fa7..20775e84fd8f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTestsBase.java
@@ -107,11 +107,9 @@ public class DisplayPolicyTestsBase extends WindowTestsBase {
}
void addWindow(WindowState win) {
- final int callingPid = Binder.getCallingPid();
- final int callingUid = Binder.getCallingUid();
- mDisplayPolicy.adjustWindowParamsLw(win, win.mAttrs, callingPid, callingUid);
- assertEquals(WindowManagerGlobal.ADD_OKAY,
- mDisplayPolicy.validateAddingWindowLw(win.mAttrs, callingPid, callingUid));
+ mDisplayPolicy.adjustWindowParamsLw(win, win.mAttrs);
+ assertEquals(WindowManagerGlobal.ADD_OKAY, mDisplayPolicy.validateAddingWindowLw(
+ win.mAttrs, Binder.getCallingPid(), Binder.getCallingUid()));
mDisplayPolicy.addWindowLw(win, win.mAttrs);
win.mHasSurface = true;
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsProviderTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsProviderTests.java
index eaedd58001c1..7c4f7db48022 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsProviderTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsProviderTests.java
@@ -16,7 +16,9 @@
package com.android.server.wm;
+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.view.WindowManager.DISPLAY_IME_POLICY_LOCAL;
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
@@ -27,6 +29,7 @@ import static org.junit.Assert.assertTrue;
import android.annotation.Nullable;
import android.platform.test.annotations.Presubmit;
+import android.util.TypedXmlPullParser;
import android.util.Xml;
import android.view.Display;
import android.view.DisplayAddress;
@@ -67,7 +70,8 @@ public class DisplayWindowSettingsProviderTests extends WindowTestsBase {
private static final File TEST_FOLDER = getInstrumentation().getTargetContext().getCacheDir();
- private TestStorage mBaseSettingsStorage;
+ private TestStorage mDefaultVendorSettingsStorage;
+ private TestStorage mSecondaryVendorSettingsStorage;
private TestStorage mOverrideSettingsStorage;
private DisplayContent mPrimaryDisplay;
@@ -77,7 +81,8 @@ public class DisplayWindowSettingsProviderTests extends WindowTestsBase {
public void setUp() throws Exception {
deleteRecursively(TEST_FOLDER);
- mBaseSettingsStorage = new TestStorage();
+ mDefaultVendorSettingsStorage = new TestStorage();
+ mSecondaryVendorSettingsStorage = new TestStorage();
mOverrideSettingsStorage = new TestStorage();
mPrimaryDisplay = mWm.getDefaultDisplayContentLocked();
@@ -120,7 +125,7 @@ public class DisplayWindowSettingsProviderTests extends WindowTestsBase {
// Update settings with new value, should trigger write to injector.
DisplayWindowSettingsProvider provider = new DisplayWindowSettingsProvider(
- mBaseSettingsStorage, mOverrideSettingsStorage);
+ mDefaultVendorSettingsStorage, mOverrideSettingsStorage);
SettingsEntry overrideSettings = provider.getOverrideSettings(mPrimaryDisplayInfo);
overrideSettings.mForcedDensity = 200;
provider.updateOverrideSettings(mPrimaryDisplayInfo, overrideSettings);
@@ -160,12 +165,55 @@ public class DisplayWindowSettingsProviderTests extends WindowTestsBase {
}
@Test
+ public void testReadingDisplaySettingsFromStorage_secondayVendorDisplaySettingsLocation() {
+ final String displayIdentifier = mSecondaryDisplay.getDisplayInfo().uniqueId;
+ prepareSecondaryDisplaySettings(displayIdentifier);
+
+ final DisplayWindowSettingsProvider provider =
+ new DisplayWindowSettingsProvider(mDefaultVendorSettingsStorage,
+ mOverrideSettingsStorage);
+
+ // Expected settings should be empty because the default is to read from the primary vendor
+ // settings location.
+ SettingsEntry expectedSettings = new SettingsEntry();
+ assertEquals(expectedSettings, provider.getSettings(mPrimaryDisplay.getDisplayInfo()));
+
+ // Now switch to secondary vendor settings and assert proper settings.
+ provider.setBaseSettingsStorage(mSecondaryVendorSettingsStorage);
+ expectedSettings.mWindowingMode = WINDOWING_MODE_FULLSCREEN;
+ assertEquals(expectedSettings, provider.getSettings(mPrimaryDisplay.getDisplayInfo()));
+
+ // Switch back to primary and assert settings are empty again.
+ provider.setBaseSettingsStorage(mDefaultVendorSettingsStorage);
+ expectedSettings.mWindowingMode = WINDOWING_MODE_UNDEFINED;
+ assertEquals(expectedSettings, provider.getSettings(mPrimaryDisplay.getDisplayInfo()));
+ }
+
+ @Test
+ public void testReadingDisplaySettingsFromStorage_overrideSettingsTakePrecedenceOverVendor() {
+ final String displayIdentifier = mSecondaryDisplay.getDisplayInfo().uniqueId;
+ prepareOverrideDisplaySettings(displayIdentifier);
+ prepareSecondaryDisplaySettings(displayIdentifier);
+
+ final DisplayWindowSettingsProvider provider =
+ new DisplayWindowSettingsProvider(mDefaultVendorSettingsStorage,
+ mOverrideSettingsStorage);
+ provider.setBaseSettingsStorage(mSecondaryVendorSettingsStorage);
+
+ // The windowing mode should be set to WINDOWING_MODE_PINNED because the override settings
+ // take precedence over the vendor provided settings.
+ SettingsEntry expectedSettings = new SettingsEntry();
+ expectedSettings.mWindowingMode = WINDOWING_MODE_PINNED;
+ assertEquals(expectedSettings, provider.getSettings(mPrimaryDisplay.getDisplayInfo()));
+ }
+
+ @Test
public void testWritingDisplaySettingsToStorage() throws Exception {
final DisplayInfo secondaryDisplayInfo = mSecondaryDisplay.getDisplayInfo();
// Write some settings to storage.
DisplayWindowSettingsProvider provider = new DisplayWindowSettingsProvider(
- mBaseSettingsStorage, mOverrideSettingsStorage);
+ mDefaultVendorSettingsStorage, mOverrideSettingsStorage);
SettingsEntry overrideSettings = provider.getOverrideSettings(secondaryDisplayInfo);
overrideSettings.mShouldShowSystemDecors = true;
overrideSettings.mImePolicy = DISPLAY_IME_POLICY_LOCAL;
@@ -193,7 +241,7 @@ public class DisplayWindowSettingsProviderTests extends WindowTestsBase {
// Write some settings to storage.
DisplayWindowSettingsProvider provider = new DisplayWindowSettingsProvider(
- mBaseSettingsStorage, mOverrideSettingsStorage);
+ mDefaultVendorSettingsStorage, mOverrideSettingsStorage);
SettingsEntry overrideSettings = provider.getOverrideSettings(secondaryDisplayInfo);
overrideSettings.mShouldShowSystemDecors = true;
overrideSettings.mImePolicy = DISPLAY_IME_POLICY_LOCAL;
@@ -234,10 +282,29 @@ public class DisplayWindowSettingsProviderTests extends WindowTestsBase {
mOverrideSettingsStorage.setReadStream(is);
}
+ /**
+ * Prepares display settings and stores in {@link #mSecondaryVendorSettingsStorage}. Uses
+ * provided display identifier and stores windowingMode=WINDOWING_MODE_FULLSCREEN.
+ */
+ private void prepareSecondaryDisplaySettings(String displayIdentifier) {
+ String contents = "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
+ + "<display-settings>\n";
+ if (displayIdentifier != null) {
+ contents += " <display\n"
+ + " name=\"" + displayIdentifier + "\"\n"
+ + " windowingMode=\"" + WINDOWING_MODE_FULLSCREEN + "\"/>\n";
+ }
+ contents += "</display-settings>\n";
+
+ final InputStream is = new ByteArrayInputStream(contents.getBytes(StandardCharsets.UTF_8));
+ mSecondaryVendorSettingsStorage.setReadStream(is);
+ }
+
private void readAndAssertExpectedSettings(DisplayContent displayContent,
SettingsEntry expectedSettings) {
final DisplayWindowSettingsProvider provider =
- new DisplayWindowSettingsProvider(mBaseSettingsStorage, mOverrideSettingsStorage);
+ new DisplayWindowSettingsProvider(mDefaultVendorSettingsStorage,
+ mOverrideSettingsStorage);
assertEquals(expectedSettings, provider.getSettings(displayContent.getDisplayInfo()));
}
@@ -245,7 +312,7 @@ public class DisplayWindowSettingsProviderTests extends WindowTestsBase {
private String getStoredDisplayAttributeValue(TestStorage storage, String attr)
throws Exception {
try (InputStream stream = storage.openRead()) {
- XmlPullParser parser = Xml.newPullParser();
+ TypedXmlPullParser parser = Xml.newFastPullParser();
parser.setInput(stream, StandardCharsets.UTF_8.name());
int type;
while ((type = parser.next()) != XmlPullParser.START_TAG
diff --git a/services/tests/wmtests/src/com/android/server/wm/HighRefreshRateDenylistTest.java b/services/tests/wmtests/src/com/android/server/wm/HighRefreshRateDenylistTest.java
index c3e1922a09cc..dfc2e35ffedf 100644
--- a/services/tests/wmtests/src/com/android/server/wm/HighRefreshRateDenylistTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/HighRefreshRateDenylistTest.java
@@ -31,7 +31,7 @@ import androidx.test.filters.SmallTest;
import com.android.internal.R;
import com.android.internal.util.Preconditions;
-import com.android.server.wm.utils.FakeDeviceConfigInterface;
+import com.android.server.testutils.FakeDeviceConfigInterface;
import org.junit.After;
import org.junit.Test;
diff --git a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java
index cd428e10a437..a99e40cc19ec 100644
--- a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java
@@ -294,11 +294,11 @@ public class LaunchParamsControllerTests extends WindowTestsBase {
mController.registerModifier(positioner);
- doNothing().when(mRootWindowContainer).moveStackToTaskDisplayArea(anyInt(), any(),
+ doNothing().when(mRootWindowContainer).moveRootTaskToTaskDisplayArea(anyInt(), any(),
anyBoolean());
mController.layoutTask(task, null /* windowLayout */);
- verify(mRootWindowContainer, times(1)).moveStackToTaskDisplayArea(eq(task.getRootTaskId()),
- eq(preferredTaskDisplayArea), anyBoolean());
+ verify(mRootWindowContainer, times(1)).moveRootTaskToTaskDisplayArea(
+ eq(task.getRootTaskId()), eq(preferredTaskDisplayArea), anyBoolean());
}
/**
diff --git a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java
index d701a9df7cb8..b7d8638f06a8 100644
--- a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java
@@ -115,7 +115,7 @@ public class LaunchParamsPersisterTests extends WindowTestsBase {
.thenReturn(mTestDisplay);
Task stack = mTestDisplay.getDefaultTaskDisplayArea()
- .createStack(TEST_WINDOWING_MODE, ACTIVITY_TYPE_STANDARD, /* onTop */ true);
+ .createRootTask(TEST_WINDOWING_MODE, ACTIVITY_TYPE_STANDARD, /* onTop */ true);
mTestTask = new TaskBuilder(mSupervisor).setComponent(TEST_COMPONENT).setParentTask(stack)
.build();
mTestTask.mUserId = TEST_USER_ID;
@@ -337,7 +337,7 @@ public class LaunchParamsPersisterTests extends WindowTestsBase {
public void testClearsRecordsOfTheUserOnUserCleanUp() {
mTarget.saveTask(mTestTask);
- Task stack = mTestDisplay.getDefaultTaskDisplayArea().createStack(
+ Task stack = mTestDisplay.getDefaultTaskDisplayArea().createRootTask(
TEST_WINDOWING_MODE, ACTIVITY_TYPE_STANDARD, /* onTop */ true);
final Task anotherTaskOfTheSameUser = new TaskBuilder(mSupervisor)
.setComponent(ALTERNATIVE_COMPONENT)
@@ -349,7 +349,7 @@ public class LaunchParamsPersisterTests extends WindowTestsBase {
anotherTaskOfTheSameUser.setHasBeenVisible(true);
mTarget.saveTask(anotherTaskOfTheSameUser);
- stack = mTestDisplay.getDefaultTaskDisplayArea().createStack(TEST_WINDOWING_MODE,
+ stack = mTestDisplay.getDefaultTaskDisplayArea().createRootTask(TEST_WINDOWING_MODE,
ACTIVITY_TYPE_STANDARD, /* onTop */ true);
final Task anotherTaskOfDifferentUser = new TaskBuilder(mSupervisor)
.setComponent(TEST_COMPONENT)
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
index 7812934bb52f..4892ef3b6322 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
@@ -724,7 +724,7 @@ public class RecentTasksTest extends WindowTestsBase {
mRecentTasks.setParameters(-1 /* min */, 3 /* max */, -1 /* ms */);
final TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea();
- final Task alwaysOnTopTask = taskDisplayArea.createStack(WINDOWING_MODE_MULTI_WINDOW,
+ final Task alwaysOnTopTask = taskDisplayArea.createRootTask(WINDOWING_MODE_MULTI_WINDOW,
ACTIVITY_TYPE_STANDARD, true /* onTop */);
alwaysOnTopTask.setAlwaysOnTop(true);
@@ -838,7 +838,7 @@ public class RecentTasksTest extends WindowTestsBase {
Task stack = mTasks.get(2).getRootTask();
stack.moveToFront("", mTasks.get(2));
- doReturn(stack).when(mAtm.mRootWindowContainer).getTopDisplayFocusedStack();
+ doReturn(stack).when(mAtm.mRootWindowContainer).getTopDisplayFocusedRootTask();
// Simulate the reset from the timeout
mRecentTasks.resetFreezeTaskListReorderingOnTimeout();
@@ -858,7 +858,7 @@ public class RecentTasksTest extends WindowTestsBase {
mRecentTasks.setParameters(-1 /* min */, 1 /* max */, -1 /* ms */);
final Task homeStack = mTaskContainer.getRootHomeTask();
- final Task aboveHomeStack = mTaskContainer.createStack(
+ final Task aboveHomeStack = mTaskContainer.createRootTask(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
// Add a number of tasks (beyond the max) but ensure that nothing is trimmed because all
@@ -875,10 +875,10 @@ public class RecentTasksTest extends WindowTestsBase {
public void testBehindHomeStackTasks_expectTaskTrimmed() {
mRecentTasks.setParameters(-1 /* min */, 1 /* max */, -1 /* ms */);
- final Task behindHomeStack = mTaskContainer.createStack(
+ final Task behindHomeStack = mTaskContainer.createRootTask(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
final Task homeStack = mTaskContainer.getRootHomeTask();
- final Task aboveHomeStack = mTaskContainer.createStack(
+ final Task aboveHomeStack = mTaskContainer.createRootTask(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
// Add a number of tasks (beyond the max) but ensure that only the task in the stack behind
@@ -897,17 +897,17 @@ public class RecentTasksTest extends WindowTestsBase {
public void testOtherDisplayTasks_expectNoTrim() {
mRecentTasks.setParameters(-1 /* min */, 1 /* max */, -1 /* ms */);
- final Task homeStack = mTaskContainer.getRootHomeTask();
+ final Task homeTask = mTaskContainer.getRootHomeTask();
final DisplayContent otherDisplay = addNewDisplayContentAt(DisplayContent.POSITION_TOP);
- final Task otherDisplayStack = otherDisplay.getDefaultTaskDisplayArea()
- .createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
+ final Task otherDisplayRootTask = otherDisplay.getDefaultTaskDisplayArea().createRootTask(
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
// Add a number of tasks (beyond the max) on each display, ensure that the tasks are not
// removed
- mRecentTasks.add(createTaskBuilder(".HomeTask1").setParentTask(homeStack).build());
- mRecentTasks.add(createTaskBuilder(".Task1").setParentTask(otherDisplayStack).build());
- mRecentTasks.add(createTaskBuilder(".Task2").setParentTask(otherDisplayStack).build());
- mRecentTasks.add(createTaskBuilder(".HomeTask2").setParentTask(homeStack).build());
+ mRecentTasks.add(createTaskBuilder(".HomeTask1").setParentTask(homeTask).build());
+ mRecentTasks.add(createTaskBuilder(".Task1").setParentTask(otherDisplayRootTask).build());
+ mRecentTasks.add(createTaskBuilder(".Task2").setParentTask(otherDisplayRootTask).build());
+ mRecentTasks.add(createTaskBuilder(".HomeTask2").setParentTask(homeTask).build());
triggerTrimAndAssertNoTasksTrimmed();
}
@@ -1103,9 +1103,9 @@ public class RecentTasksTest extends WindowTestsBase {
private void assertNotRestoreTask(Runnable action) {
// Verify stack count doesn't change because task with fullscreen mode and standard type
// would have its own stack.
- final int originalStackCount = mTaskContainer.getStackCount();
+ final int originalStackCount = mTaskContainer.getRootTaskCount();
action.run();
- assertEquals(originalStackCount, mTaskContainer.getStackCount());
+ assertEquals(originalStackCount, mTaskContainer.getRootTaskCount());
}
@Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
index 40f73b12f805..5c39bd0a316b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
@@ -322,7 +322,7 @@ public class RecentsAnimationControllerTest extends WindowTestsBase {
assertEquals(landActivity.findMainWindow(), win1);
// Ensure that the display is in Landscape
- landActivity.onDescendantOrientationChanged(landActivity.token, landActivity);
+ landActivity.onDescendantOrientationChanged(landActivity);
assertEquals(Configuration.ORIENTATION_LANDSCAPE,
mDefaultDisplay.getConfiguration().orientation);
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java
index 5ff3ff5a6e0c..63ee5d05fada 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java
@@ -89,7 +89,7 @@ public class RecentsAnimationTest extends WindowTestsBase {
@Test
public void testRecentsActivityVisiblility() {
TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea();
- Task recentsStack = taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN,
+ Task recentsStack = taskDisplayArea.createRootTask(WINDOWING_MODE_FULLSCREEN,
ACTIVITY_TYPE_RECENTS, true /* onTop */);
ActivityRecord recentActivity = new ActivityBuilder(mAtm)
.setComponent(mRecentsComponent)
@@ -118,7 +118,7 @@ public class RecentsAnimationTest extends WindowTestsBase {
public void testPreloadRecentsActivity() {
TaskDisplayArea defaultTaskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea();
final Task homeStack =
- defaultTaskDisplayArea.getStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME);
+ defaultTaskDisplayArea.getRootTask(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME);
defaultTaskDisplayArea.positionChildAt(POSITION_TOP, homeStack,
false /* includingParents */);
ActivityRecord topRunningHomeActivity = homeStack.topRunningActivity();
@@ -150,7 +150,7 @@ public class RecentsAnimationTest extends WindowTestsBase {
mAtm.startRecentsActivity(recentsIntent, 0 /* eventTime */,
null /* recentsAnimationRunner */);
- Task recentsStack = defaultTaskDisplayArea.getStack(WINDOWING_MODE_FULLSCREEN,
+ Task recentsStack = defaultTaskDisplayArea.getRootTask(WINDOWING_MODE_FULLSCREEN,
ACTIVITY_TYPE_RECENTS);
assertThat(recentsStack).isNotNull();
@@ -179,7 +179,7 @@ public class RecentsAnimationTest extends WindowTestsBase {
public void testRestartRecentsActivity() throws Exception {
// Have a recents activity that is not attached to its process (ActivityRecord.app = null).
TaskDisplayArea defaultTaskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea();
- Task recentsStack = defaultTaskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN,
+ Task recentsStack = defaultTaskDisplayArea.createRootTask(WINDOWING_MODE_FULLSCREEN,
ACTIVITY_TYPE_RECENTS, true /* onTop */);
ActivityRecord recentActivity = new ActivityBuilder(mAtm).setComponent(
mRecentsComponent).setCreateTask(true).setParentTask(recentsStack).build();
@@ -251,21 +251,21 @@ public class RecentsAnimationTest extends WindowTestsBase {
@Test
public void testCancelAnimationOnVisibleStackOrderChange() {
TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea();
- Task fullscreenStack = taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN,
+ Task fullscreenStack = taskDisplayArea.createRootTask(WINDOWING_MODE_FULLSCREEN,
ACTIVITY_TYPE_STANDARD, true /* onTop */);
new ActivityBuilder(mAtm)
.setComponent(new ComponentName(mContext.getPackageName(), "App1"))
.setCreateTask(true)
.setParentTask(fullscreenStack)
.build();
- Task recentsStack = taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN,
+ Task recentsStack = taskDisplayArea.createRootTask(WINDOWING_MODE_FULLSCREEN,
ACTIVITY_TYPE_RECENTS, true /* onTop */);
new ActivityBuilder(mAtm)
.setComponent(mRecentsComponent)
.setCreateTask(true)
.setParentTask(recentsStack)
.build();
- Task fullscreenStack2 = taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN,
+ Task fullscreenStack2 = taskDisplayArea.createRootTask(WINDOWING_MODE_FULLSCREEN,
ACTIVITY_TYPE_STANDARD, true /* onTop */);
new ActivityBuilder(mAtm)
.setComponent(new ComponentName(mContext.getPackageName(), "App2"))
@@ -292,21 +292,21 @@ public class RecentsAnimationTest extends WindowTestsBase {
@Test
public void testKeepAnimationOnHiddenStackOrderChange() {
TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea();
- Task fullscreenStack = taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN,
+ Task fullscreenStack = taskDisplayArea.createRootTask(WINDOWING_MODE_FULLSCREEN,
ACTIVITY_TYPE_STANDARD, true /* onTop */);
new ActivityBuilder(mAtm)
.setComponent(new ComponentName(mContext.getPackageName(), "App1"))
.setCreateTask(true)
.setParentTask(fullscreenStack)
.build();
- Task recentsStack = taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN,
+ Task recentsStack = taskDisplayArea.createRootTask(WINDOWING_MODE_FULLSCREEN,
ACTIVITY_TYPE_RECENTS, true /* onTop */);
new ActivityBuilder(mAtm)
.setComponent(mRecentsComponent)
.setCreateTask(true)
.setParentTask(recentsStack)
.build();
- Task fullscreenStack2 = taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN,
+ Task fullscreenStack2 = taskDisplayArea.createRootTask(WINDOWING_MODE_FULLSCREEN,
ACTIVITY_TYPE_STANDARD, true /* onTop */);
new ActivityBuilder(mAtm)
.setComponent(new ComponentName(mContext.getPackageName(), "App2"))
@@ -329,7 +329,7 @@ public class RecentsAnimationTest extends WindowTestsBase {
public void testMultipleUserHomeActivity_findUserHomeTask() {
TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultDisplay()
.getDefaultTaskDisplayArea();
- Task homeStack = taskDisplayArea.getStack(WINDOWING_MODE_UNDEFINED,
+ Task homeStack = taskDisplayArea.getRootTask(WINDOWING_MODE_UNDEFINED,
ACTIVITY_TYPE_HOME);
ActivityRecord otherUserHomeActivity = new ActivityBuilder(mAtm)
.setParentTask(homeStack)
@@ -338,7 +338,7 @@ public class RecentsAnimationTest extends WindowTestsBase {
.build();
otherUserHomeActivity.getTask().mUserId = TEST_USER_ID;
- Task fullscreenStack = taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN,
+ Task fullscreenStack = taskDisplayArea.createRootTask(WINDOWING_MODE_FULLSCREEN,
ACTIVITY_TYPE_STANDARD, true /* onTop */);
new ActivityBuilder(mAtm)
.setComponent(new ComponentName(mContext.getPackageName(), "App1"))
diff --git a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
index 7ca364cf096f..f79e4cc9fa10 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
@@ -94,7 +94,7 @@ public class RootActivityContainerTests extends WindowTestsBase {
@Before
public void setUp() throws Exception {
- mFullscreenStack = mRootWindowContainer.getDefaultTaskDisplayArea().createStack(
+ mFullscreenStack = mRootWindowContainer.getDefaultTaskDisplayArea().createRootTask(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
doNothing().when(mAtm).updateSleepIfNeededLocked();
}
@@ -128,7 +128,7 @@ public class RootActivityContainerTests extends WindowTestsBase {
ensureStackPlacement(mFullscreenStack, firstActivity, secondActivity);
// Move first activity to pinned stack.
- mRootWindowContainer.moveActivityToPinnedStack(firstActivity, "initialMove");
+ mRootWindowContainer.moveActivityToPinnedRootTask(firstActivity, "initialMove");
final TaskDisplayArea taskDisplayArea = mFullscreenStack.getDisplayArea();
Task pinnedStack = taskDisplayArea.getRootPinnedTask();
@@ -137,11 +137,11 @@ public class RootActivityContainerTests extends WindowTestsBase {
ensureStackPlacement(mFullscreenStack, secondActivity);
// Move second activity to pinned stack.
- mRootWindowContainer.moveActivityToPinnedStack(secondActivity, "secondMove");
+ mRootWindowContainer.moveActivityToPinnedRootTask(secondActivity, "secondMove");
// Need to get stacks again as a new instance might have been created.
pinnedStack = taskDisplayArea.getRootPinnedTask();
- mFullscreenStack = taskDisplayArea.getStack(WINDOWING_MODE_FULLSCREEN,
+ mFullscreenStack = taskDisplayArea.getRootTask(WINDOWING_MODE_FULLSCREEN,
ACTIVITY_TYPE_STANDARD);
// Ensure stacks have swapped tasks.
ensureStackPlacement(pinnedStack, secondActivity);
@@ -166,7 +166,7 @@ public class RootActivityContainerTests extends WindowTestsBase {
// Move first activity to pinned stack.
- mRootWindowContainer.moveActivityToPinnedStack(secondActivity, "initialMove");
+ mRootWindowContainer.moveActivityToPinnedRootTask(secondActivity, "initialMove");
assertTrue(firstActivity.mRequestForceTransition);
}
@@ -237,9 +237,9 @@ public class RootActivityContainerTests extends WindowTestsBase {
doReturn(keyguardShowing).when(keyguard).isKeyguardOrAodShowing(anyInt());
doReturn(isFocusedStack).when(stack).isFocusedStackOnDisplay();
- doReturn(isFocusedStack ? stack : null).when(display).getFocusedStack();
+ doReturn(isFocusedStack ? stack : null).when(display).getFocusedRootTask();
TaskDisplayArea defaultTaskDisplayArea = display.getDefaultTaskDisplayArea();
- doReturn(isFocusedStack ? stack : null).when(defaultTaskDisplayArea).getFocusedStack();
+ doReturn(isFocusedStack ? stack : null).when(defaultTaskDisplayArea).getFocusedRootTask();
mRootWindowContainer.applySleepTokens(true);
verify(stack, times(expectWakeFromSleep ? 1 : 0)).awakeFromSleepingLocked();
verify(stack, times(expectResumeTopActivity ? 1 : 0)).resumeTopActivityUncheckedLocked(
@@ -282,19 +282,19 @@ public class RootActivityContainerTests extends WindowTestsBase {
public void testRemovingStackOnAppCrash() {
final TaskDisplayArea defaultTaskDisplayArea = mRootWindowContainer
.getDefaultTaskDisplayArea();
- final int originalStackCount = defaultTaskDisplayArea.getStackCount();
- final Task stack = defaultTaskDisplayArea.createStack(
+ final int originalStackCount = defaultTaskDisplayArea.getRootTaskCount();
+ final Task stack = defaultTaskDisplayArea.createRootTask(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */);
final ActivityRecord firstActivity = new ActivityBuilder(mAtm).setTask(stack).build();
- assertEquals(originalStackCount + 1, defaultTaskDisplayArea.getStackCount());
+ assertEquals(originalStackCount + 1, defaultTaskDisplayArea.getRootTaskCount());
// Let's pretend that the app has crashed.
firstActivity.app.setThread(null);
mRootWindowContainer.finishTopCrashedActivities(firstActivity.app, "test");
// Verify that the stack was removed.
- assertEquals(originalStackCount, defaultTaskDisplayArea.getStackCount());
+ assertEquals(originalStackCount, defaultTaskDisplayArea.getRootTaskCount());
}
/**
@@ -305,34 +305,34 @@ public class RootActivityContainerTests extends WindowTestsBase {
public void testRemovingStackOnAppCrash_multipleDisplayAreas() {
final TaskDisplayArea defaultTaskDisplayArea = mRootWindowContainer
.getDefaultTaskDisplayArea();
- final int originalStackCount = defaultTaskDisplayArea.getStackCount();
- final Task stack = defaultTaskDisplayArea.createStack(
+ final int originalStackCount = defaultTaskDisplayArea.getRootTaskCount();
+ final Task stack = defaultTaskDisplayArea.createRootTask(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */);
final ActivityRecord firstActivity = new ActivityBuilder(mAtm).setTask(stack).build();
- assertEquals(originalStackCount + 1, defaultTaskDisplayArea.getStackCount());
+ assertEquals(originalStackCount + 1, defaultTaskDisplayArea.getRootTaskCount());
final DisplayContent dc = defaultTaskDisplayArea.getDisplayContent();
final TaskDisplayArea secondTaskDisplayArea = createTaskDisplayArea(
dc, mRootWindowContainer.mWmService, "TestTaskDisplayArea", FEATURE_VENDOR_FIRST);
- final Task secondStack = secondTaskDisplayArea.createStack(
+ final Task secondStack = secondTaskDisplayArea.createRootTask(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */);
new ActivityBuilder(mAtm).setTask(secondStack).setUseProcess(firstActivity.app).build();
- assertEquals(1, secondTaskDisplayArea.getStackCount());
+ assertEquals(1, secondTaskDisplayArea.getRootTaskCount());
// Let's pretend that the app has crashed.
firstActivity.app.setThread(null);
mRootWindowContainer.finishTopCrashedActivities(firstActivity.app, "test");
// Verify that the stacks were removed.
- assertEquals(originalStackCount, defaultTaskDisplayArea.getStackCount());
- assertEquals(0, secondTaskDisplayArea.getStackCount());
+ assertEquals(originalStackCount, defaultTaskDisplayArea.getRootTaskCount());
+ assertEquals(0, secondTaskDisplayArea.getRootTaskCount());
}
@Test
public void testFocusability() {
final TaskDisplayArea defaultTaskDisplayArea = mRootWindowContainer
.getDefaultTaskDisplayArea();
- final Task stack = defaultTaskDisplayArea.createStack(
+ final Task stack = defaultTaskDisplayArea.createRootTask(
WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD, true /* onTop */);
final ActivityRecord activity = new ActivityBuilder(mAtm).setTask(stack).build();
@@ -345,7 +345,7 @@ public class RootActivityContainerTests extends WindowTestsBase {
assertFalse(stack.isTopActivityFocusable());
assertFalse(activity.isFocusable());
- final Task pinnedStack = defaultTaskDisplayArea.createStack(
+ final Task pinnedStack = defaultTaskDisplayArea.createRootTask(
WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, true /* onTop */);
final ActivityRecord pinnedActivity = new ActivityBuilder(mAtm)
.setTask(pinnedStack).build();
@@ -371,7 +371,7 @@ public class RootActivityContainerTests extends WindowTestsBase {
public void testSplitScreenPrimaryChosenWhenTopActivityLaunchedToSecondary() {
// Create primary split-screen stack with a task and an activity.
final Task primaryStack = mRootWindowContainer.getDefaultTaskDisplayArea()
- .createStack(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD,
+ .createRootTask(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD,
true /* onTop */);
final Task task = new TaskBuilder(mSupervisor).setParentTask(primaryStack).build();
final ActivityRecord r = new ActivityBuilder(mAtm).setTask(task).build();
@@ -381,7 +381,7 @@ public class RootActivityContainerTests extends WindowTestsBase {
final ActivityOptions options = ActivityOptions.makeBasic();
options.setLaunchWindowingMode(WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY);
final Task result =
- mRootWindowContainer.getLaunchStack(r, options, task, true /* onTop */);
+ mRootWindowContainer.getLaunchRootTask(r, options, task, true /* onTop */);
// Assert that the primary stack is returned.
assertEquals(primaryStack, result);
@@ -410,7 +410,7 @@ public class RootActivityContainerTests extends WindowTestsBase {
false);
final TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea();
- verify(taskDisplayArea).moveHomeStackToFront(contains(reason));
+ verify(taskDisplayArea).moveHomeRootTaskToFront(contains(reason));
}
/**
@@ -421,7 +421,7 @@ public class RootActivityContainerTests extends WindowTestsBase {
public void testFindTaskToMoveToFrontWhenRecentsOnOtherDisplay() {
// Create stack/task on default display.
final TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea();
- final Task targetStack = taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN,
+ final Task targetStack = taskDisplayArea.createRootTask(WINDOWING_MODE_FULLSCREEN,
ACTIVITY_TYPE_STANDARD, false /* onTop */);
final Task targetTask = new TaskBuilder(mSupervisor).setParentTask(targetStack).build();
@@ -429,7 +429,7 @@ public class RootActivityContainerTests extends WindowTestsBase {
final TestDisplayContent secondDisplay = addNewDisplayContentAt(
DisplayContent.POSITION_TOP);
final Task stack = secondDisplay.getDefaultTaskDisplayArea()
- .createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_RECENTS, true /* onTop */);
+ .createRootTask(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_RECENTS, true /* onTop */);
final Task task = new TaskBuilder(mSupervisor).setParentTask(stack).build();
new ActivityBuilder(mAtm).setTask(task).build();
@@ -437,7 +437,7 @@ public class RootActivityContainerTests extends WindowTestsBase {
mSupervisor.findTaskToMoveToFront(targetTask, 0, ActivityOptions.makeBasic(), reason,
false);
- verify(taskDisplayArea, never()).moveHomeStackToFront(contains(reason));
+ verify(taskDisplayArea, never()).moveHomeRootTaskToFront(contains(reason));
}
/**
@@ -448,7 +448,7 @@ public class RootActivityContainerTests extends WindowTestsBase {
public void testResumeActivityWhenNonTopmostStackIsTopFocused() {
// Create a stack at bottom.
final TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea();
- final Task targetStack = spy(taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN,
+ final Task targetStack = spy(taskDisplayArea.createRootTask(WINDOWING_MODE_FULLSCREEN,
ACTIVITY_TYPE_STANDARD, false /* onTop */));
final Task task = new TaskBuilder(mSupervisor).setParentTask(targetStack).build();
final ActivityRecord activity = new ActivityBuilder(mAtm).setTask(task).build();
@@ -457,10 +457,10 @@ public class RootActivityContainerTests extends WindowTestsBase {
// Assume the stack is not at the topmost position (e.g. behind always-on-top stacks) but it
// is the current top focused stack.
assertFalse(targetStack.isTopStackInDisplayArea());
- doReturn(targetStack).when(mRootWindowContainer).getTopDisplayFocusedStack();
+ doReturn(targetStack).when(mRootWindowContainer).getTopDisplayFocusedRootTask();
// Use the stack as target to resume.
- mRootWindowContainer.resumeFocusedStacksTopActivities(
+ mRootWindowContainer.resumeFocusedTasksTopActivities(
targetStack, activity, null /* targetOptions */);
// Verify the target stack should resume its activity.
@@ -477,14 +477,14 @@ public class RootActivityContainerTests extends WindowTestsBase {
mFullscreenStack.removeIfPossible();
final TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea();
taskDisplayArea.getRootHomeTask().removeIfPossible();
- taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, ON_TOP);
+ taskDisplayArea.createRootTask(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, ON_TOP);
doReturn(true).when(mRootWindowContainer).resumeHomeActivity(any(), any(), any());
mAtm.setBooted(true);
// Trigger resume on all displays
- mRootWindowContainer.resumeFocusedStacksTopActivities();
+ mRootWindowContainer.resumeFocusedTasksTopActivities();
// Verify that home activity was started on the default display
verify(mRootWindowContainer).resumeHomeActivity(any(), any(), eq(taskDisplayArea));
@@ -499,14 +499,14 @@ public class RootActivityContainerTests extends WindowTestsBase {
mFullscreenStack.removeIfPossible();
final TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea();
taskDisplayArea.getRootHomeTask().removeIfPossible();
- taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, ON_TOP);
+ taskDisplayArea.createRootTask(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, ON_TOP);
// Create an activity on secondary display.
final TestDisplayContent secondDisplay = addNewDisplayContentAt(
DisplayContent.POSITION_TOP);
- final Task stack = secondDisplay.getDefaultTaskDisplayArea()
- .createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
- final Task task = new TaskBuilder(mSupervisor).setParentTask(stack).build();
+ final Task rootTask = secondDisplay.getDefaultTaskDisplayArea().createRootTask(
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
+ final Task task = new TaskBuilder(mSupervisor).setParentTask(rootTask).build();
new ActivityBuilder(mAtm).setTask(task).build();
doReturn(true).when(mRootWindowContainer).resumeHomeActivity(any(), any(), any());
@@ -514,7 +514,7 @@ public class RootActivityContainerTests extends WindowTestsBase {
mAtm.setBooted(true);
// Trigger resume on all displays
- mRootWindowContainer.resumeFocusedStacksTopActivities();
+ mRootWindowContainer.resumeFocusedTasksTopActivities();
// Verify that home activity was started on the default display
verify(mRootWindowContainer).resumeHomeActivity(any(), any(), eq(taskDisplayArea));
@@ -528,7 +528,7 @@ public class RootActivityContainerTests extends WindowTestsBase {
public void testResumeActivityLingeringTransition() {
// Create a stack at top.
final TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea();
- final Task targetStack = spy(taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN,
+ final Task targetStack = spy(taskDisplayArea.createRootTask(WINDOWING_MODE_FULLSCREEN,
ACTIVITY_TYPE_STANDARD, false /* onTop */));
final Task task = new TaskBuilder(mSupervisor).setParentTask(targetStack).build();
final ActivityRecord activity = new ActivityBuilder(mAtm).setTask(task).build();
@@ -538,7 +538,7 @@ public class RootActivityContainerTests extends WindowTestsBase {
assertTrue(targetStack.isTopStackInDisplayArea());
// Use the stack as target to resume.
- mRootWindowContainer.resumeFocusedStacksTopActivities();
+ mRootWindowContainer.resumeFocusedTasksTopActivities();
// Verify the lingering app transition is being executed because it's already resumed
verify(targetStack, times(1)).executeAppTransition(any());
@@ -548,7 +548,7 @@ public class RootActivityContainerTests extends WindowTestsBase {
public void testResumeActivityLingeringTransition_notExecuted() {
// Create a stack at bottom.
final TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea();
- final Task targetStack = spy(taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN,
+ final Task targetStack = spy(taskDisplayArea.createRootTask(WINDOWING_MODE_FULLSCREEN,
ACTIVITY_TYPE_STANDARD, false /* onTop */));
final Task task = new TaskBuilder(mSupervisor).setParentTask(targetStack).build();
final ActivityRecord activity = new ActivityBuilder(mAtm).setTask(task).build();
@@ -557,10 +557,10 @@ public class RootActivityContainerTests extends WindowTestsBase {
// Assume the stack is at the topmost position
assertFalse(targetStack.isTopStackInDisplayArea());
- doReturn(targetStack).when(mRootWindowContainer).getTopDisplayFocusedStack();
+ doReturn(targetStack).when(mRootWindowContainer).getTopDisplayFocusedRootTask();
// Use the stack as target to resume.
- mRootWindowContainer.resumeFocusedStacksTopActivities();
+ mRootWindowContainer.resumeFocusedTasksTopActivities();
// Verify the lingering app transition is being executed because it's already resumed
verify(targetStack, never()).executeAppTransition(any());
@@ -586,9 +586,9 @@ public class RootActivityContainerTests extends WindowTestsBase {
mRootWindowContainer.startHomeOnAllDisplays(0, "testStartHome");
- assertTrue(mRootWindowContainer.getDefaultDisplay().getTopStack().isActivityTypeHome());
- assertNotNull(secondDisplay.getTopStack());
- assertTrue(secondDisplay.getTopStack().isActivityTypeHome());
+ assertTrue(mRootWindowContainer.getDefaultDisplay().getTopRootTask().isActivityTypeHome());
+ assertNotNull(secondDisplay.getTopRootTask());
+ assertTrue(secondDisplay.getTopRootTask().isActivityTypeHome());
}
/**
@@ -840,7 +840,7 @@ public class RootActivityContainerTests extends WindowTestsBase {
}
/**
- * Test that {@link RootWindowContainer#getLaunchStack} with the real caller id will get the
+ * Test that {@link RootWindowContainer#getLaunchRootTask} with the real caller id will get the
* expected stack when requesting the activity launch on the secondary display.
*/
@Test
@@ -861,7 +861,7 @@ public class RootActivityContainerTests extends WindowTestsBase {
options.setLaunchWindowingMode(WINDOWING_MODE_FULLSCREEN);
doReturn(true).when(mSupervisor).canPlaceEntityOnDisplay(secondaryDisplay.mDisplayId,
300 /* test realCallerPid */, 300 /* test realCallerUid */, r.info);
- final Task result = mRootWindowContainer.getLaunchStack(r, options,
+ final Task result = mRootWindowContainer.getLaunchRootTask(r, options,
null /* task */, true /* onTop */, null, 300 /* test realCallerPid */,
300 /* test realCallerUid */);
@@ -881,7 +881,7 @@ public class RootActivityContainerTests extends WindowTestsBase {
final ActivityRecord activity = new ActivityBuilder(mAtm).setTask(task).build();
// Make sure the root task is valid and can be reused on default display.
- final Task stack = mRootWindowContainer.getValidLaunchStackInTaskDisplayArea(
+ final Task stack = mRootWindowContainer.getValidLaunchRootTaskInTaskDisplayArea(
mRootWindowContainer.getDefaultTaskDisplayArea(), activity, task,
null /* options */, null /* launchParams */);
assertEquals(task, stack);
@@ -889,7 +889,7 @@ public class RootActivityContainerTests extends WindowTestsBase {
@Test
public void testSwitchUser_missingHomeRootTask() {
- doReturn(mFullscreenStack).when(mRootWindowContainer).getTopDisplayFocusedStack();
+ doReturn(mFullscreenStack).when(mRootWindowContainer).getTopDisplayFocusedRootTask();
final TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea();
Task homeStack = taskDisplayArea.getRootHomeTask();
@@ -904,7 +904,7 @@ public class RootActivityContainerTests extends WindowTestsBase {
mRootWindowContainer.switchUser(otherUser, null);
assertNotNull(taskDisplayArea.getRootHomeTask());
- assertEquals(taskDisplayArea.getTopStack(), taskDisplayArea.getRootHomeTask());
+ assertEquals(taskDisplayArea.getTopRootTask(), taskDisplayArea.getRootHomeTask());
}
/**
diff --git a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
index 42193c8fce78..9af2b96f3f78 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
@@ -92,7 +92,7 @@ public class RootWindowContainerTests extends WindowTestsBase {
public void testAllPausedActivitiesComplete() {
DisplayContent displayContent = mWm.mRoot.getDisplayContent(DEFAULT_DISPLAY);
TaskDisplayArea taskDisplayArea = displayContent.getDefaultTaskDisplayArea();
- Task stack = taskDisplayArea.getStackAt(0);
+ Task stack = taskDisplayArea.getRootTaskAt(0);
ActivityRecord activity = createActivityRecord(displayContent);
stack.mPausingActivity = activity;
diff --git a/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java
index 95e344d5c184..6821d47d5b1a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java
@@ -71,7 +71,7 @@ public class RunningTasksTest extends WindowTestsBase {
final int numTasks = 10;
int activeTime = 0;
for (int i = 0; i < numTasks; i++) {
- createTask(display.getDefaultTaskDisplayArea().getStackAt(i % numStacks),
+ createTask(display.getDefaultTaskDisplayArea().getRootTaskAt(i % numStacks),
".Task" + i, i, activeTime++, null);
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/ScreenDecorWindowTests.java b/services/tests/wmtests/src/com/android/server/wm/ScreenDecorWindowTests.java
deleted file mode 100644
index 25ba6db38e05..000000000000
--- a/services/tests/wmtests/src/com/android/server/wm/ScreenDecorWindowTests.java
+++ /dev/null
@@ -1,382 +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.wm;
-
-import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
-import static android.graphics.Color.RED;
-import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY;
-import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_PRESENTATION;
-import static android.view.Display.DEFAULT_DISPLAY;
-import static android.view.Gravity.BOTTOM;
-import static android.view.Gravity.LEFT;
-import static android.view.Gravity.RIGHT;
-import static android.view.Gravity.TOP;
-import static android.view.InsetsState.ITYPE_CLIMATE_BAR;
-import static android.view.InsetsState.ITYPE_EXTRA_NAVIGATION_BAR;
-import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
-import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
-import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
-import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
-import static android.view.WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_IS_SCREEN_DECOR;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
-
-import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.junit.Assert.assertEquals;
-
-import android.app.Activity;
-import android.app.ActivityOptions;
-import android.app.Instrumentation;
-import android.content.Context;
-import android.content.Intent;
-import android.graphics.PixelFormat;
-import android.graphics.Point;
-import android.hardware.display.DisplayManager;
-import android.hardware.display.VirtualDisplay;
-import android.media.ImageReader;
-import android.os.Handler;
-import android.os.SystemClock;
-import android.platform.test.annotations.Presubmit;
-import android.util.Pair;
-import android.view.Display;
-import android.view.DisplayInfo;
-import android.view.View;
-import android.view.WindowInsets;
-import android.view.WindowManager;
-import android.widget.TextView;
-
-import androidx.test.filters.SmallTest;
-
-import com.android.compatibility.common.util.SystemUtil;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Ignore;
-import org.junit.Test;
-
-import java.util.ArrayList;
-import java.util.function.BooleanSupplier;
-
-/**
- * Tests for the {@link android.view.WindowManager.LayoutParams#PRIVATE_FLAG_IS_SCREEN_DECOR} flag.
- *
- * Build/Install/Run:
- * atest WmTests:ScreenDecorWindowTests
- */
-// TODO: Add test for FLAG_FULLSCREEN which hides the status bar and also other flags.
-// TODO: Test non-Activity windows.
-@SmallTest
-@Presubmit
-public class ScreenDecorWindowTests {
-
- private final Context mContext = getInstrumentation().getTargetContext();
- private final Instrumentation mInstrumentation = getInstrumentation();
-
- private WindowManager mWm;
- private ArrayList<View> mWindows = new ArrayList<>();
-
- private Activity mTestActivity;
- private VirtualDisplay mDisplay;
- private ImageReader mImageReader;
-
- private int mDecorThickness;
- private int mHalfDecorThickness;
-
- @Before
- public void setUp() {
- final Pair<VirtualDisplay, ImageReader> result = createDisplay();
- mDisplay = result.first;
- mImageReader = result.second;
- final Display display = mDisplay.getDisplay();
- final Context dContext = mContext.createDisplayContext(display);
- mWm = dContext.getSystemService(WindowManager.class);
- mTestActivity = startActivityOnDisplay(TestActivity.class, display.getDisplayId());
- final Point size = new Point();
- mDisplay.getDisplay().getRealSize(size);
- mDecorThickness = Math.min(size.x, size.y) / 3;
- mHalfDecorThickness = mDecorThickness / 2;
- }
-
- @After
- public void tearDown() {
- while (!mWindows.isEmpty()) {
- removeWindow(mWindows.get(0));
- }
- finishActivity(mTestActivity);
- mDisplay.release();
- mImageReader.close();
- }
-
- @Test
- public void testScreenSides() {
- // Decor on top
- final View decorWindow = createDecorWindow(TOP, MATCH_PARENT, mDecorThickness);
- assertInsetGreaterOrEqual(mTestActivity, TOP, mDecorThickness);
-
- // Decor at the bottom
- updateWindow(decorWindow, BOTTOM, MATCH_PARENT, mDecorThickness, 0, 0);
- assertInsetGreaterOrEqual(mTestActivity, BOTTOM, mDecorThickness);
-
- // Decor to the left
- updateWindow(decorWindow, LEFT, mDecorThickness, MATCH_PARENT, 0, 0);
- assertInsetGreaterOrEqual(mTestActivity, LEFT, mDecorThickness);
-
- // Decor to the right
- updateWindow(decorWindow, RIGHT, mDecorThickness, MATCH_PARENT, 0, 0);
- assertInsetGreaterOrEqual(mTestActivity, RIGHT, mDecorThickness);
- }
-
- // Decor windows (i.e windows using PRIVATE_FLAG_IS_SCREEN_DECOR) are no longer supported.
- // PRIVATE_FLAG_IS_SCREEN_DECOR and related code will be deprecated/removed soon.
- @Ignore
- @Test
- public void testMultipleDecors() {
- // Test 2 decor windows on-top.
- createDecorWindow(TOP, MATCH_PARENT, mHalfDecorThickness);
- assertInsetGreaterOrEqual(mTestActivity, TOP, mHalfDecorThickness);
- createDecorWindow(TOP, MATCH_PARENT, mDecorThickness);
- assertInsetGreaterOrEqual(mTestActivity, TOP, mDecorThickness);
-
- // And one at the bottom.
- createDecorWindow(BOTTOM, MATCH_PARENT, mHalfDecorThickness);
- assertInsetGreaterOrEqual(mTestActivity, TOP, mDecorThickness);
- assertInsetGreaterOrEqual(mTestActivity, BOTTOM, mHalfDecorThickness);
- }
-
- @Test
- public void testFlagChange() {
- WindowInsets initialInsets = getInsets(mTestActivity);
-
- final View decorWindow = createDecorWindow(TOP, MATCH_PARENT, mDecorThickness);
- assertTopInsetEquals(mTestActivity, mDecorThickness);
-
- updateWindow(decorWindow, TOP, MATCH_PARENT, mDecorThickness,
- 0, PRIVATE_FLAG_IS_SCREEN_DECOR);
-
- // TODO: fix test and re-enable assertion.
- // initialInsets was not actually immutable and just updated to the current insets,
- // meaning this assertion never actually tested anything. Now that WindowInsets actually is
- // immutable, it turns out the test was broken.
- // assertTopInsetEquals(mTestActivity, initialInsets.getSystemWindowInsetTop());
-
- updateWindow(decorWindow, TOP, MATCH_PARENT, mDecorThickness,
- PRIVATE_FLAG_IS_SCREEN_DECOR, PRIVATE_FLAG_IS_SCREEN_DECOR);
- assertTopInsetEquals(mTestActivity, mDecorThickness);
- }
-
- @Test
- public void testRemoval() {
- WindowInsets initialInsets = getInsets(mTestActivity);
-
- final View decorWindow = createDecorWindow(TOP, MATCH_PARENT, mDecorThickness);
- assertInsetGreaterOrEqual(mTestActivity, TOP, mDecorThickness);
-
- removeWindow(decorWindow);
- assertTopInsetEquals(mTestActivity, initialInsets.getSystemWindowInsetTop());
- }
-
- @Test
- public void testProvidesInsetsTypes() {
- int[] providesInsetsTypes = new int[]{ITYPE_CLIMATE_BAR};
- final View win = createWindow("StatusBarSubPanel", TOP, MATCH_PARENT, mDecorThickness, RED,
- FLAG_LAYOUT_IN_SCREEN, 0, providesInsetsTypes);
-
- assertInsetGreaterOrEqual(mTestActivity, TOP, mDecorThickness);
- }
-
- private View createDecorWindow(int gravity, int width, int height) {
- int[] providesInsetsTypes =
- new int[]{gravity == TOP ? ITYPE_CLIMATE_BAR : ITYPE_EXTRA_NAVIGATION_BAR};
- return createWindow("decorWindow", gravity, width, height, RED,
- FLAG_LAYOUT_IN_SCREEN, PRIVATE_FLAG_IS_SCREEN_DECOR, providesInsetsTypes);
- }
-
- private View createWindow(String name, int gravity, int width, int height, int color, int flags,
- int privateFlags, int[] providesInsetsTypes) {
-
- final View[] viewHolder = new View[1];
- final int finalFlag = flags
- | FLAG_NOT_FOCUSABLE | FLAG_WATCH_OUTSIDE_TOUCH | FLAG_NOT_TOUCHABLE;
-
- // Needs to run on the UI thread.
- Handler.getMain().runWithScissors(() -> {
- final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
- width, height, TYPE_APPLICATION_OVERLAY, finalFlag, PixelFormat.OPAQUE);
- lp.gravity = gravity;
- lp.privateFlags |= privateFlags;
- lp.providesInsetsTypes = providesInsetsTypes;
-
- final TextView view = new TextView(mContext);
- view.setText("ScreenDecorWindowTests - " + name);
- view.setBackgroundColor(color);
- mWm.addView(view, lp);
- mWindows.add(view);
- viewHolder[0] = view;
- }, 0);
-
- waitForIdle();
- return viewHolder[0];
- }
-
- private void updateWindow(View v, int gravity, int width, int height,
- int privateFlags, int privateFlagsMask) {
- // Needs to run on the UI thread.
- Handler.getMain().runWithScissors(() -> {
- final WindowManager.LayoutParams lp = (WindowManager.LayoutParams) v.getLayoutParams();
- lp.gravity = gravity;
- lp.width = width;
- lp.height = height;
- setPrivateFlags(lp, privateFlags, privateFlagsMask);
-
- mWm.updateViewLayout(v, lp);
- }, 0);
-
- waitForIdle();
- }
-
- private void removeWindow(View v) {
- Handler.getMain().runWithScissors(() -> mWm.removeView(v), 0);
- mWindows.remove(v);
- waitForIdle();
- }
-
- private WindowInsets getInsets(Activity a) {
- return new WindowInsets(a.getWindow().getDecorView().getRootWindowInsets());
- }
-
- /**
- * Set the flags of the window, as per the
- * {@link WindowManager.LayoutParams WindowManager.LayoutParams}
- * flags.
- *
- * @param flags The new window flags (see WindowManager.LayoutParams).
- * @param mask Which of the window flag bits to modify.
- */
- public void setPrivateFlags(WindowManager.LayoutParams lp, int flags, int mask) {
- lp.flags = (lp.flags & ~mask) | (flags & mask);
- }
-
- /**
- * Asserts the top inset of {@param activity} is equal to {@param expected} waiting as needed.
- */
- private void assertTopInsetEquals(Activity activity, int expected) {
- waitForTopInsetEqual(activity, expected);
- assertEquals(expected, getInsets(activity).getSystemWindowInsetTop());
- }
-
- private void waitForTopInsetEqual(Activity activity, int expected) {
- waitFor(() -> getInsets(activity).getSystemWindowInsetTop() == expected);
- }
-
- /**
- * Asserts the inset at {@param side} of {@param activity} is equal to {@param expected}
- * waiting as needed.
- */
- private void assertInsetGreaterOrEqual(Activity activity, int side, int expected) {
- waitForInsetGreaterOrEqual(activity, side, expected);
-
- final WindowInsets insets = getInsets(activity);
- switch (side) {
- case TOP:
- assertThat(insets.getSystemWindowInsetTop()).isAtLeast(expected);
- break;
- case BOTTOM:
- assertThat(insets.getSystemWindowInsetBottom()).isAtLeast(expected);
- break;
- case LEFT:
- assertThat(insets.getSystemWindowInsetLeft()).isAtLeast(expected);
- break;
- case RIGHT:
- assertThat(insets.getSystemWindowInsetRight()).isAtLeast(expected);
- break;
- }
- }
-
- private void waitForInsetGreaterOrEqual(Activity activity, int side, int expected) {
- waitFor(() -> {
- final WindowInsets insets = getInsets(activity);
- switch (side) {
- case TOP: return insets.getSystemWindowInsetTop() >= expected;
- case BOTTOM: return insets.getSystemWindowInsetBottom() >= expected;
- case LEFT: return insets.getSystemWindowInsetLeft() >= expected;
- case RIGHT: return insets.getSystemWindowInsetRight() >= expected;
- default: return true;
- }
- });
- }
-
- private void waitFor(BooleanSupplier waitCondition) {
- int retriesLeft = 5;
- do {
- if (waitCondition.getAsBoolean()) {
- break;
- }
- SystemClock.sleep(500);
- } while (retriesLeft-- > 0);
- }
-
- private void finishActivity(Activity a) {
- if (a == null) {
- return;
- }
- a.finish();
- waitForIdle();
- }
-
- private void waitForIdle() {
- mInstrumentation.waitForIdleSync();
- }
-
- private Activity startActivityOnDisplay(Class<?> cls, int displayId) {
- final Intent intent = new Intent(mContext, cls);
- intent.addFlags(FLAG_ACTIVITY_NEW_TASK);
- final ActivityOptions options = ActivityOptions.makeBasic();
- options.setLaunchDisplayId(displayId);
-
- final Activity activity = SystemUtil.runWithShellPermissionIdentity(
- () -> mInstrumentation.startActivitySync(intent, options.toBundle()),
- "android.permission.ACTIVITY_EMBEDDING");
- waitForIdle();
-
- assertEquals(displayId, activity.getDisplayId());
- return activity;
- }
-
- private Pair<VirtualDisplay, ImageReader> createDisplay() {
- final DisplayManager dm = mContext.getSystemService(DisplayManager.class);
- final DisplayInfo displayInfo = new DisplayInfo();
- final Display defaultDisplay = dm.getDisplay(DEFAULT_DISPLAY);
- defaultDisplay.getDisplayInfo(displayInfo);
- final String name = "ScreenDecorWindowTests";
- int flags = VIRTUAL_DISPLAY_FLAG_PRESENTATION | VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY;
-
- final ImageReader imageReader = ImageReader.newInstance(
- displayInfo.logicalWidth, displayInfo.logicalHeight, PixelFormat.RGBA_8888, 2);
-
- final VirtualDisplay display = dm.createVirtualDisplay(name, displayInfo.logicalWidth,
- displayInfo.logicalHeight, displayInfo.logicalDensityDpi, imageReader.getSurface(),
- flags);
-
- return Pair.create(display, imageReader);
- }
-
- public static class TestActivity extends Activity {
- }
-}
diff --git a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
index a4bf5948c6a3..da00198030e4 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
@@ -698,7 +698,7 @@ public class SizeCompatTests extends WindowTestsBase {
// Update with new activity requested orientation and recompute bounds with no previous
// size compat cache.
- verify(mTask).onDescendantOrientationChanged(any(), same(newActivity));
+ verify(mTask).onDescendantOrientationChanged(same(newActivity));
verify(mTask).computeFullscreenBounds(any(), any(), any(), anyInt());
final Rect displayBounds = display.getBounds();
@@ -739,7 +739,7 @@ public class SizeCompatTests extends WindowTestsBase {
// Update with new activity requested orientation and recompute bounds with no previous
// size compat cache.
- verify(mTask).onDescendantOrientationChanged(any(), same(newActivity));
+ verify(mTask).onDescendantOrientationChanged(same(newActivity));
verify(mTask).computeFullscreenBounds(any(), any(), any(), anyInt());
final Rect displayBounds = display.getBounds();
diff --git a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
index 2db736e63391..83e3d22345e1 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
@@ -299,6 +299,7 @@ public class SystemServicesTestRule implements TestRule {
doNothing().when(mWmService.mRoot).ensureActivitiesVisible(any(),
anyInt(), anyBoolean(), anyBoolean(), anyBoolean());
spyOn(mWmService.mDisplayWindowSettings);
+ spyOn(mWmService.mDisplayWindowSettingsProvider);
// Setup factory classes to prevent calls to native code.
mTransaction = spy(StubTransaction.class);
@@ -326,7 +327,7 @@ public class SystemServicesTestRule implements TestRule {
// Set the default focused TDA.
display.setLastFocusedTaskDisplayArea(taskDisplayArea);
spyOn(taskDisplayArea);
- final Task homeStack = taskDisplayArea.getStack(
+ final Task homeStack = taskDisplayArea.getRootTask(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME);
spyOn(homeStack);
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java
index 28ba710797c9..d80f81642474 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java
@@ -181,33 +181,33 @@ public class TaskDisplayAreaTests extends WindowTestsBase {
final Task newStack = createTaskStackOnDisplay(WINDOWING_MODE_FULLSCREEN,
ACTIVITY_TYPE_STANDARD, mDisplayContent);
final TaskDisplayArea taskDisplayArea = candidateTask.getDisplayArea();
- doReturn(newStack).when(taskDisplayArea).createStack(anyInt(), anyInt(), anyBoolean(),
+ doReturn(newStack).when(taskDisplayArea).createRootTask(anyInt(), anyInt(), anyBoolean(),
any(), any(), anyBoolean());
final int type = ACTIVITY_TYPE_STANDARD;
- assertGetOrCreateStack(WINDOWING_MODE_FULLSCREEN, type, candidateTask,
+ assertGetOrCreateRootTask(WINDOWING_MODE_FULLSCREEN, type, candidateTask,
true /* reuseCandidate */);
- assertGetOrCreateStack(WINDOWING_MODE_UNDEFINED, type, candidateTask,
+ assertGetOrCreateRootTask(WINDOWING_MODE_UNDEFINED, type, candidateTask,
true /* reuseCandidate */);
- assertGetOrCreateStack(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, type, candidateTask,
+ assertGetOrCreateRootTask(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, type, candidateTask,
true /* reuseCandidate */);
- assertGetOrCreateStack(WINDOWING_MODE_FREEFORM, type, candidateTask,
+ assertGetOrCreateRootTask(WINDOWING_MODE_FREEFORM, type, candidateTask,
true /* reuseCandidate */);
- assertGetOrCreateStack(WINDOWING_MODE_MULTI_WINDOW, type, candidateTask,
+ assertGetOrCreateRootTask(WINDOWING_MODE_MULTI_WINDOW, type, candidateTask,
true /* reuseCandidate */);
- assertGetOrCreateStack(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, type, candidateTask,
+ assertGetOrCreateRootTask(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, type, candidateTask,
false /* reuseCandidate */);
- assertGetOrCreateStack(WINDOWING_MODE_PINNED, type, candidateTask,
+ assertGetOrCreateRootTask(WINDOWING_MODE_PINNED, type, candidateTask,
true /* reuseCandidate */);
final int windowingMode = WINDOWING_MODE_FULLSCREEN;
- assertGetOrCreateStack(windowingMode, ACTIVITY_TYPE_HOME, candidateTask,
+ assertGetOrCreateRootTask(windowingMode, ACTIVITY_TYPE_HOME, candidateTask,
false /* reuseCandidate */);
- assertGetOrCreateStack(windowingMode, ACTIVITY_TYPE_RECENTS, candidateTask,
+ assertGetOrCreateRootTask(windowingMode, ACTIVITY_TYPE_RECENTS, candidateTask,
false /* reuseCandidate */);
- assertGetOrCreateStack(windowingMode, ACTIVITY_TYPE_ASSISTANT, candidateTask,
+ assertGetOrCreateRootTask(windowingMode, ACTIVITY_TYPE_ASSISTANT, candidateTask,
false /* reuseCandidate */);
- assertGetOrCreateStack(windowingMode, ACTIVITY_TYPE_DREAM, candidateTask,
+ assertGetOrCreateRootTask(windowingMode, ACTIVITY_TYPE_DREAM, candidateTask,
false /* reuseCandidate */);
}
@@ -250,9 +250,9 @@ public class TaskDisplayAreaTests extends WindowTestsBase {
final TaskDisplayArea secondTaskDisplayArea = createTaskDisplayArea(
mDisplayContent, mRootWindowContainer.mWmService, "TestTaskDisplayArea",
FEATURE_VENDOR_FIRST);
- final Task firstStack = firstTaskDisplayArea.createStack(
+ final Task firstStack = firstTaskDisplayArea.createRootTask(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */);
- final Task secondStack = secondTaskDisplayArea.createStack(
+ final Task secondStack = secondTaskDisplayArea.createRootTask(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */);
final ActivityRecord firstActivity = new ActivityBuilder(mAtm)
.setTask(firstStack).build();
@@ -281,7 +281,7 @@ public class TaskDisplayAreaTests extends WindowTestsBase {
@Test
public void testIgnoreOrientationRequest() {
final TaskDisplayArea taskDisplayArea = mDisplayContent.getDefaultTaskDisplayArea();
- final Task stack = taskDisplayArea.createStack(
+ final Task stack = taskDisplayArea.createRootTask(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */);
final ActivityRecord activity = new ActivityBuilder(mAtm).setTask(stack).build();
@@ -326,10 +326,10 @@ public class TaskDisplayAreaTests extends WindowTestsBase {
assertFalse(defaultTaskDisplayArea.mChildren.contains(task));
}
- private void assertGetOrCreateStack(int windowingMode, int activityType, Task candidateTask,
+ private void assertGetOrCreateRootTask(int windowingMode, int activityType, Task candidateTask,
boolean reuseCandidate) {
final TaskDisplayArea taskDisplayArea = candidateTask.getDisplayArea();
- final Task stack = taskDisplayArea.getOrCreateStack(windowingMode, activityType,
+ final Task stack = taskDisplayArea.getOrCreateRootTask(windowingMode, activityType,
false /* onTop */, null /* intent */, candidateTask /* candidateTask */);
assertEquals(reuseCandidate, stack == candidateTask);
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
index 4f55322e2085..269ce5d833f2 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
@@ -1566,13 +1566,13 @@ public class TaskLaunchParamsModifierTests extends WindowTestsBase {
private ActivityRecord createSourceActivity(TestDisplayContent display) {
final Task stack = display.getDefaultTaskDisplayArea()
- .createStack(display.getWindowingMode(), ACTIVITY_TYPE_STANDARD, true);
+ .createRootTask(display.getWindowingMode(), ACTIVITY_TYPE_STANDARD, true);
return new ActivityBuilder(mAtm).setTask(stack).build();
}
private void addFreeformTaskTo(TestDisplayContent display, Rect bounds) {
final Task stack = display.getDefaultTaskDisplayArea()
- .createStack(display.getWindowingMode(), ACTIVITY_TYPE_STANDARD, true);
+ .createRootTask(display.getWindowingMode(), ACTIVITY_TYPE_STANDARD, true);
stack.setWindowingMode(WINDOWING_MODE_FREEFORM);
final Task task = new TaskBuilder(mSupervisor).setParentTask(stack).build();
// Just work around the unnecessary adjustments for bounds.
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
index d080fa0445ef..4a5ff58fca3c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
@@ -70,6 +70,8 @@ import android.graphics.Rect;
import android.os.IBinder;
import android.platform.test.annotations.Presubmit;
import android.util.DisplayMetrics;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
import android.util.Xml;
import android.view.DisplayInfo;
@@ -175,7 +177,7 @@ public class TaskRecordTests extends WindowTestsBase {
public void testFitWithinBounds() {
final Rect parentBounds = new Rect(10, 10, 200, 200);
TaskDisplayArea taskDisplayArea = mAtm.mRootWindowContainer.getDefaultTaskDisplayArea();
- Task stack = taskDisplayArea.createStack(WINDOWING_MODE_FREEFORM,
+ Task stack = taskDisplayArea.createRootTask(WINDOWING_MODE_FREEFORM,
ACTIVITY_TYPE_STANDARD, true /* onTop */);
Task task = new TaskBuilder(mSupervisor).setParentTask(stack).build();
final Configuration parentConfig = stack.getConfiguration();
@@ -495,7 +497,7 @@ public class TaskRecordTests extends WindowTestsBase {
@Test
public void testInsetDisregardedWhenFreeformOverlapsNavBar() {
TaskDisplayArea taskDisplayArea = mAtm.mRootWindowContainer.getDefaultTaskDisplayArea();
- Task stack = taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN,
+ Task stack = taskDisplayArea.createRootTask(WINDOWING_MODE_FULLSCREEN,
ACTIVITY_TYPE_STANDARD, true /* onTop */);
DisplayInfo displayInfo = new DisplayInfo();
mAtm.mContext.getDisplay().getDisplayInfo(displayInfo);
@@ -1025,9 +1027,9 @@ public class TaskRecordTests extends WindowTestsBase {
final TaskDisplayArea secondTaskDisplayArea = createTaskDisplayArea(
mDisplayContent, mRootWindowContainer.mWmService, "TestTaskDisplayArea",
FEATURE_VENDOR_FIRST);
- final Task firstStack = firstTaskDisplayArea.createStack(
+ final Task firstStack = firstTaskDisplayArea.createRootTask(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */);
- final Task secondStack = secondTaskDisplayArea.createStack(
+ final Task secondStack = secondTaskDisplayArea.createRootTask(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */);
final ActivityRecord firstActivity = new ActivityBuilder(mAtm)
.setTask(firstStack).build();
@@ -1064,12 +1066,12 @@ public class TaskRecordTests extends WindowTestsBase {
activity.setRequestedOrientation(SCREEN_ORIENTATION_LANDSCAPE);
assertEquals(SCREEN_ORIENTATION_UNSET, task.getOrientation());
- verify(display).onDescendantOrientationChanged(any(), same(task));
+ verify(display).onDescendantOrientationChanged(same(task));
reset(display);
display.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
assertEquals(SCREEN_ORIENTATION_LANDSCAPE, task.getOrientation());
- verify(display).onDescendantOrientationChanged(any(), same(task));
+ verify(display).onDescendantOrientationChanged(same(task));
}
private Task getTestTask() {
@@ -1081,7 +1083,7 @@ public class TaskRecordTests extends WindowTestsBase {
Rect expectedConfigBounds) {
TaskDisplayArea taskDisplayArea = mAtm.mRootWindowContainer.getDefaultTaskDisplayArea();
- Task stack = taskDisplayArea.createStack(windowingMode, ACTIVITY_TYPE_STANDARD,
+ Task stack = taskDisplayArea.createRootTask(windowingMode, ACTIVITY_TYPE_STANDARD,
true /* onTop */);
Task task = new TaskBuilder(mSupervisor).setParentTask(stack).build();
@@ -1097,7 +1099,7 @@ public class TaskRecordTests extends WindowTestsBase {
private byte[] serializeToBytes(Task r) throws Exception {
try (ByteArrayOutputStream os = new ByteArrayOutputStream()) {
- final XmlSerializer serializer = Xml.newSerializer();
+ final TypedXmlSerializer serializer = Xml.newFastSerializer();
serializer.setOutput(os, "UTF-8");
serializer.startDocument(null, true);
serializer.startTag(null, TASK_TAG);
@@ -1112,7 +1114,7 @@ public class TaskRecordTests extends WindowTestsBase {
private Task restoreFromBytes(byte[] in) throws IOException, XmlPullParserException {
try (Reader reader = new InputStreamReader(new ByteArrayInputStream(in))) {
- final XmlPullParser parser = Xml.newPullParser();
+ final TypedXmlPullParser parser = Xml.newFastPullParser();
parser.setInput(reader);
assertEquals(XmlPullParser.START_TAG, parser.next());
assertEquals(TASK_TAG, parser.getName());
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
index 3d8adbd215bd..c4bcfdbcf89d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
@@ -56,7 +56,6 @@ import static org.junit.Assert.assertTrue;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.graphics.Rect;
-import android.os.IBinder;
import android.os.RemoteException;
import android.platform.test.annotations.Presubmit;
import android.view.IRemoteAnimationFinishedCallback;
@@ -787,12 +786,11 @@ public class WindowContainerTests extends WindowTestsBase {
final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
final TestWindowContainer root = spy(builder.build());
- final IBinder binder = mock(IBinder.class);
final ActivityRecord activityRecord = mock(ActivityRecord.class);
final TestWindowContainer child = root.addChildWindow();
- child.setOrientation(ActivityInfo.SCREEN_ORIENTATION_LOCKED, binder, activityRecord);
- verify(root).onDescendantOrientationChanged(binder, activityRecord);
+ child.setOrientation(ActivityInfo.SCREEN_ORIENTATION_LOCKED, activityRecord);
+ verify(root).onDescendantOrientationChanged(activityRecord);
}
@Test
@@ -814,7 +812,7 @@ public class WindowContainerTests extends WindowTestsBase {
final ActivityRecord activity = createActivityRecord(mDisplayContent, task);
final DisplayContent newDc = createNewDisplay();
- stack.getDisplayArea().removeStack(stack);
+ stack.getDisplayArea().removeRootTask(stack);
newDc.getDefaultTaskDisplayArea().addChild(stack, POSITION_TOP);
verify(stack).onDisplayChanged(newDc);
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowManagerConstantsTest.java b/services/tests/wmtests/src/com/android/server/wm/WindowManagerConstantsTest.java
index 52100116df53..7a0ef0d7d7a9 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowManagerConstantsTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowManagerConstantsTest.java
@@ -32,7 +32,7 @@ import android.platform.test.annotations.Presubmit;
import androidx.test.filters.SmallTest;
-import com.android.server.wm.utils.FakeDeviceConfigInterface;
+import com.android.server.testutils.FakeDeviceConfigInterface;
import org.junit.After;
import org.junit.Before;
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowManagerSettingsTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowManagerSettingsTests.java
index ba144dd367d9..4e1b3510bdaa 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowManagerSettingsTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowManagerSettingsTests.java
@@ -20,7 +20,7 @@ import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDO
import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_SIZECOMPAT_FREEFORM;
import static android.provider.Settings.Global.DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS;
import static android.provider.Settings.Global.DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES;
-import static android.provider.Settings.Global.DEVELOPMENT_IGNORE_VENDOR_DISPLAY_SETTINGS;
+import static android.provider.Settings.Global.DEVELOPMENT_WM_DISPLAY_SETTINGS_PATH;
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
@@ -58,8 +58,8 @@ public class WindowManagerSettingsTests extends WindowTestsBase {
@Test
public void testForceDesktopModeOnExternalDisplays() {
- try (SettingsSession forceDesktopModeSession = new
- SettingsSession(DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS)) {
+ try (BoolSettingsSession forceDesktopModeSession = new
+ BoolSettingsSession(DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS)) {
final boolean forceDesktopMode = !forceDesktopModeSession.getSetting();
final Uri forceDesktopModeUri = forceDesktopModeSession.setSetting(forceDesktopMode);
mWm.mSettingsObserver.onChange(false, forceDesktopModeUri);
@@ -70,8 +70,8 @@ public class WindowManagerSettingsTests extends WindowTestsBase {
@Test
public void testFreeformWindow() {
- try (SettingsSession freeformWindowSession = new
- SettingsSession(DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT)) {
+ try (BoolSettingsSession freeformWindowSession = new
+ BoolSettingsSession(DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT)) {
final boolean curFreeformWindow = freeformWindowSession.getSetting();
final boolean newFreeformWindow = !curFreeformWindow;
final Uri freeformWindowUri = freeformWindowSession.setSetting(newFreeformWindow);
@@ -84,8 +84,8 @@ public class WindowManagerSettingsTests extends WindowTestsBase {
@Test
public void testFreeformWindow_valueChanged_updatesDisplaySettings() {
- try (SettingsSession freeformWindowSession = new
- SettingsSession(DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT)) {
+ try (BoolSettingsSession freeformWindowSession = new
+ BoolSettingsSession(DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT)) {
final boolean curFreeformWindow = freeformWindowSession.getSetting();
final boolean newFreeformWindow = !curFreeformWindow;
final Uri freeformWindowUri = freeformWindowSession.setSetting(newFreeformWindow);
@@ -106,8 +106,8 @@ public class WindowManagerSettingsTests extends WindowTestsBase {
@Test
public void testForceResizableMode() {
- try (SettingsSession forceResizableSession = new
- SettingsSession(DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES)) {
+ try (BoolSettingsSession forceResizableSession = new
+ BoolSettingsSession(DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES)) {
final boolean forceResizableMode = !forceResizableSession.getSetting();
final Uri forceResizableUri = forceResizableSession.setSetting(forceResizableMode);
@@ -119,8 +119,8 @@ public class WindowManagerSettingsTests extends WindowTestsBase {
@Test
public void testEnableSizeCompatFreeform() {
- try (SettingsSession enableSizeCompatFreeformSession = new
- SettingsSession(DEVELOPMENT_ENABLE_SIZECOMPAT_FREEFORM)) {
+ try (BoolSettingsSession enableSizeCompatFreeformSession = new
+ BoolSettingsSession(DEVELOPMENT_ENABLE_SIZECOMPAT_FREEFORM)) {
final boolean enableSizeCompatFreeform =
!enableSizeCompatFreeformSession.getSetting();
final Uri enableSizeCompatFreeformUri =
@@ -132,21 +132,22 @@ public class WindowManagerSettingsTests extends WindowTestsBase {
}
@Test
- public void testEnabledIgnoreVendorDisplaySettings() {
- try (SettingsSession ignoreVendorDisplaySettingsSession = new
- SettingsSession(DEVELOPMENT_IGNORE_VENDOR_DISPLAY_SETTINGS)) {
- final boolean ignoreVendorDisplaySettings =
- !ignoreVendorDisplaySettingsSession.getSetting();
- final Uri ignoreVendorDisplaySettingUri =
- ignoreVendorDisplaySettingsSession.setSetting(ignoreVendorDisplaySettings);
+ public void testChangeBaseDisplaySettingsPath() {
+ try (StringSettingsSession baseDisplaySettingsPathSession = new
+ StringSettingsSession(DEVELOPMENT_WM_DISPLAY_SETTINGS_PATH)) {
+ final String path = baseDisplaySettingsPathSession.getSetting() + "-test";
+ final Uri baseDisplaySettingsPathUri = baseDisplaySettingsPathSession.setSetting(path);
clearInvocations(mWm.mRoot);
clearInvocations(mWm.mDisplayWindowSettings);
+ clearInvocations(mWm.mDisplayWindowSettingsProvider);
- mWm.mSettingsObserver.onChange(false /* selfChange */, ignoreVendorDisplaySettingUri);
+ mWm.mSettingsObserver.onChange(false /* selfChange */, baseDisplaySettingsPathUri);
- assertEquals(mWm.mDisplayWindowSettingsProvider.getVendorSettingsIgnored(),
- ignoreVendorDisplaySettings);
+ ArgumentCaptor<String> pathCaptor = ArgumentCaptor.forClass(String.class);
+ verify(mWm.mDisplayWindowSettingsProvider).setBaseSettingsFilePath(
+ pathCaptor.capture());
+ assertEquals(path, pathCaptor.getValue());
ArgumentCaptor<DisplayContent> captor =
ArgumentCaptor.forClass(DisplayContent.class);
@@ -161,14 +162,14 @@ public class WindowManagerSettingsTests extends WindowTestsBase {
}
}
- private class SettingsSession implements AutoCloseable {
+ private class BoolSettingsSession implements AutoCloseable {
private static final int SETTING_VALUE_OFF = 0;
private static final int SETTING_VALUE_ON = 1;
private final String mSettingName;
private final int mInitialValue;
- SettingsSession(String name) {
+ BoolSettingsSession(String name) {
mSettingName = name;
mInitialValue = getSetting() ? SETTING_VALUE_ON : SETTING_VALUE_OFF;
}
@@ -192,4 +193,32 @@ public class WindowManagerSettingsTests extends WindowTestsBase {
setSetting(mInitialValue == SETTING_VALUE_ON);
}
}
+
+ private class StringSettingsSession implements AutoCloseable {
+ private final String mSettingName;
+ private final String mInitialValue;
+
+ StringSettingsSession(String name) {
+ mSettingName = name;
+ mInitialValue = getSetting();
+ }
+
+ String getSetting() {
+ return Settings.Global.getString(getContentResolver(), mSettingName);
+ }
+
+ Uri setSetting(String value) {
+ Settings.Global.putString(getContentResolver(), mSettingName, value);
+ return Settings.Global.getUriFor(mSettingName);
+ }
+
+ private ContentResolver getContentResolver() {
+ return getInstrumentation().getTargetContext().getContentResolver();
+ }
+
+ @Override
+ public void close() {
+ setSetting(mInitialValue);
+ }
+ }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
index 8fe65eb2747d..dba157e6ce06 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
@@ -387,7 +387,7 @@ public class WindowOrganizerTests extends WindowTestsBase {
public void testSetIgnoreOrientationRequest_taskDisplayArea() {
removeGlobalMinSizeRestriction();
final TaskDisplayArea taskDisplayArea = mDisplayContent.getDefaultTaskDisplayArea();
- final Task stack = taskDisplayArea.createStack(
+ final Task stack = taskDisplayArea.createRootTask(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */);
final ActivityRecord activity = new ActivityBuilder(mAtm).setTask(stack).build();
taskDisplayArea.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
@@ -425,7 +425,7 @@ public class WindowOrganizerTests extends WindowTestsBase {
public void testSetIgnoreOrientationRequest_displayContent() {
removeGlobalMinSizeRestriction();
final TaskDisplayArea taskDisplayArea = mDisplayContent.getDefaultTaskDisplayArea();
- final Task stack = taskDisplayArea.createStack(
+ final Task stack = taskDisplayArea.createRootTask(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */);
final ActivityRecord activity = new ActivityBuilder(mAtm).setTask(stack).build();
mDisplayContent.setFocusedApp(activity);
@@ -743,8 +743,8 @@ public class WindowOrganizerTests extends WindowTestsBase {
private List<Task> getTasksCreatedByOrganizer(DisplayContent dc) {
ArrayList<Task> out = new ArrayList<>();
dc.forAllTaskDisplayAreas(taskDisplayArea -> {
- for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {
- final Task t = taskDisplayArea.getStackAt(sNdx);
+ for (int sNdx = taskDisplayArea.getRootTaskCount() - 1; sNdx >= 0; --sNdx) {
+ final Task t = taskDisplayArea.getRootTaskAt(sNdx);
if (t.mCreatedByOrganizer) out.add(t);
}
});
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
index 6c046bda1444..14a62d1a4ff0 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -27,6 +27,8 @@ import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
import static android.os.Process.SYSTEM_UID;
import static android.view.View.VISIBLE;
+import static android.view.WindowManager.DISPLAY_IME_POLICY_FALLBACK_DISPLAY;
+import static android.view.WindowManager.DISPLAY_IME_POLICY_LOCAL;
import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
@@ -40,8 +42,6 @@ import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
import static android.view.WindowManager.LayoutParams.TYPE_NOTIFICATION_SHADE;
import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
-import static android.view.WindowManager.DISPLAY_IME_POLICY_LOCAL;
-import static android.view.WindowManager.DISPLAY_IME_POLICY_FALLBACK_DISPLAY;
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
@@ -64,7 +64,6 @@ import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
-import android.content.res.Configuration;
import android.hardware.display.DisplayManager;
import android.os.Build;
import android.os.Bundle;
@@ -797,7 +796,7 @@ class WindowTestsBase extends SystemServiceTestsBase {
mTask = new TaskBuilder(mService.mTaskSupervisor)
.setComponent(mComponent)
.setParentTask(mParentTask).build();
- } else if (mTask == null && mParentTask != null && DisplayContent.alwaysCreateStack(
+ } else if (mTask == null && mParentTask != null && DisplayContent.alwaysCreateRootTask(
mParentTask.getWindowingMode(), mParentTask.getActivityType())) {
// The stack can be the task root.
mTask = mParentTask;
@@ -831,13 +830,14 @@ class WindowTestsBase extends SystemServiceTestsBase {
if (mLaunchTaskBehind) {
options = ActivityOptions.makeTaskLaunchBehind();
}
+ final ActivityRecord activity = new ActivityRecord.Builder(mService)
+ .setLaunchedFromPid(mLaunchedFromPid)
+ .setLaunchedFromUid(mLaunchedFromUid)
+ .setIntent(intent)
+ .setActivityInfo(aInfo)
+ .setActivityOptions(options)
+ .build();
- final ActivityRecord activity = new ActivityRecord(mService, null /* caller */,
- mLaunchedFromPid /* launchedFromPid */, mLaunchedFromUid /* launchedFromUid */,
- null, null, intent, null, aInfo /*aInfo*/, new Configuration(),
- null /* resultTo */, null /* resultWho */, 0 /* reqCode */,
- false /*componentSpecified*/, false /* rootVoiceInteraction */,
- mService.mTaskSupervisor, options, null /* sourceRecord */);
spyOn(activity);
if (mTask != null) {
// fullscreen value is normally read from resources in ctor, so for testing we need
@@ -871,7 +871,7 @@ class WindowTestsBase extends SystemServiceTestsBase {
activity.processName, activity.info.applicationInfo.uid);
// Resume top activities to make sure all other signals in the system are connected.
- mService.mRootWindowContainer.resumeFocusedStacksTopActivities();
+ mService.mRootWindowContainer.resumeFocusedTasksTopActivities();
return activity;
}
}
@@ -995,7 +995,7 @@ class WindowTestsBase extends SystemServiceTestsBase {
// Create parent task.
if (mParentTask == null && mCreateParentTask) {
- mParentTask = mTaskDisplayArea.createStack(
+ mParentTask = mTaskDisplayArea.createRootTask(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
}
if (mParentTask != null && !Mockito.mockingDetails(mParentTask).isSpy()) {
@@ -1020,9 +1020,9 @@ class WindowTestsBase extends SystemServiceTestsBase {
}
Task task;
- final int taskId = mTaskId >= 0 ? mTaskId : mTaskDisplayArea.getNextStackId();
+ final int taskId = mTaskId >= 0 ? mTaskId : mTaskDisplayArea.getNextRootTaskId();
if (mParentTask == null) {
- task = mTaskDisplayArea.createStackUnchecked(
+ task = mTaskDisplayArea.createRootTaskUnchecked(
mWindowingMode, mActivityType, taskId, mOnTop, mActivityInfo, mIntent,
false /* createdByOrganizer */, false /* deferTaskAppear */,
null /* launchCookie */);
@@ -1114,8 +1114,8 @@ class WindowTestsBase extends SystemServiceTestsBase {
mSecondary.mRemoteToken.toWindowContainerToken());
DisplayContent dc = mService.mRootWindowContainer.getDisplayContent(mDisplayId);
dc.forAllTaskDisplayAreas(taskDisplayArea -> {
- for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {
- final Task stack = taskDisplayArea.getStackAt(sNdx);
+ for (int sNdx = taskDisplayArea.getRootTaskCount() - 1; sNdx >= 0; --sNdx) {
+ final Task stack = taskDisplayArea.getRootTaskAt(sNdx);
if (!WindowConfiguration.isSplitScreenWindowingMode(stack.getWindowingMode())) {
stack.reparent(mSecondary, POSITION_BOTTOM);
}
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index 3af88e1c6354..d585b2374783 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -1213,9 +1213,11 @@ public class UsbDeviceManager implements ActivityTaskManagerInternal.ScreenObser
Slog.d(TAG, "Clear notification");
mUsbNotificationId = 0;
}
- // Not relevant for automotive.
- if (mContext.getPackageManager().hasSystemFeature(
+ // Not relevant for automotive and watch.
+ if ((mContext.getPackageManager().hasSystemFeature(
PackageManager.FEATURE_AUTOMOTIVE)
+ || mContext.getPackageManager().hasSystemFeature(
+ PackageManager.FEATURE_WATCH))
&& id == SystemMessage.NOTE_USB_CHARGING) {
mUsbNotificationId = 0;
return;
diff --git a/telephony/java/android/telephony/CallForwardingInfo.java b/telephony/java/android/telephony/CallForwardingInfo.java
index 6ae6d002d990..aeac36e3a5f5 100644
--- a/telephony/java/android/telephony/CallForwardingInfo.java
+++ b/telephony/java/android/telephony/CallForwardingInfo.java
@@ -86,7 +86,7 @@ public final class CallForwardingInfo implements Parcelable {
* Call forwarding reason types
* @hide
*/
- @IntDef(flag = true, prefix = { "REASON_" }, value = {
+ @IntDef(prefix = { "REASON_" }, value = {
REASON_UNCONDITIONAL,
REASON_BUSY,
REASON_NO_REPLY,
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index dad18ffe4fa7..0939bf02a039 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -53,9 +53,13 @@ public class CarrierConfigManager {
public static final String EXTRA_SLOT_INDEX = "android.telephony.extra.SLOT_INDEX";
/**
- * Extra included in {@link #ACTION_CARRIER_CONFIG_CHANGED} to indicate whether this is a
- * rebroadcast on unlock. Defaults to {@code false} if not specified.
- * @hide
+ * {@link #ACTION_CARRIER_CONFIG_CHANGED} is broadcast once on device bootup and then again when
+ * the device is unlocked. Direct-Boot-aware applications may use the first broadcast as an
+ * early signal that the carrier config has been loaded, but other applications will only
+ * receive the second broadcast, when the device is unlocked.
+ *
+ * This extra is included in {@link #ACTION_CARRIER_CONFIG_CHANGED} to indicate whether this is
+ * a rebroadcast on unlock.
*/
public static final String EXTRA_REBROADCAST_ON_UNLOCK =
"android.telephony.extra.REBROADCAST_ON_UNLOCK";
@@ -2029,8 +2033,16 @@ public class CarrierConfigManager {
"allow_hold_call_during_emergency_bool";
/**
- * Flag indicating whether the carrier supports RCS presence indication for
- * User Capability Exchange (UCE). When presence is supported, the device should use the
+ * Flag indicating whether or not the carrier supports the periodic exchange of phone numbers
+ * in the user's address book with the carrier's presence server in order to retrieve the RCS
+ * capabilities for each contact used in the RCS User Capability Exchange (UCE) procedure. See
+ * RCC.71, section 3 for more information.
+ * <p>
+ * The flag {@link Ims#KEY_ENABLE_PRESENCE_PUBLISH_BOOL} must also be enabled if this flag is
+ * enabled, as sending a periodic SIP PUBLISH with this device's RCS capabilities is a
+ * requirement for capability exchange to begin.
+ * <p>
+ * When presence is supported, the device should use the
* {@link android.provider.ContactsContract.Data#CARRIER_PRESENCE} bit mask and set the
* {@link android.provider.ContactsContract.Data#CARRIER_PRESENCE_VT_CAPABLE} bit to indicate
* whether each contact supports video calling. The UI is made aware that presence is enabled
@@ -3846,12 +3858,27 @@ public class CarrierConfigManager {
public static final String KEY_IMS_SINGLE_REGISTRATION_REQUIRED_BOOL =
KEY_PREFIX + "ims_single_registration_required_bool";
+ /**
+ * A boolean flag specifying whether or not this carrier supports the device notifying the
+ * network of its RCS capabilities using the SIP PUBLISH procedure defined for User
+ * Capability Exchange (UCE). See RCC.71, section 3 for more information.
+ * <p>
+ * If this key's value is set to false, the procedure for RCS contact capability exchange
+ * via SIP SUBSCRIBE/NOTIFY will also be disabled internally, and
+ * {@link #KEY_USE_RCS_PRESENCE_BOOL} must also be set to false to ensure apps do not
+ * improperly think that capability exchange via SIP PUBLISH is enabled.
+ * <p> The default value for this key is {@code false}.
+ */
+ public static final String KEY_ENABLE_PRESENCE_PUBLISH_BOOL =
+ KEY_PREFIX + "enable_presence_publish_bool";
+
private Ims() {}
private static PersistableBundle getDefaults() {
PersistableBundle defaults = new PersistableBundle();
defaults.putInt(KEY_WIFI_OFF_DEFERRING_TIME_MILLIS_INT, 4000);
defaults.putBoolean(KEY_IMS_SINGLE_REGISTRATION_REQUIRED_BOOL, false);
+ defaults.putBoolean(KEY_ENABLE_PRESENCE_PUBLISH_BOOL, false);
return defaults;
}
}
@@ -3985,6 +4012,17 @@ public class CarrierConfigManager {
"default_preferred_apn_name_string";
/**
+ * Indicates if the carrier supports call composer.
+ */
+ public static final String KEY_SUPPORTS_CALL_COMPOSER_BOOL = "supports_call_composer_bool";
+
+ /**
+ * Indicates the carrier server url that serves the call composer picture.
+ */
+ public static final String KEY_CALL_COMPOSER_PICTURE_SERVER_URL_STRING =
+ "call_composer_picture_server_url_string";
+
+ /**
* For Android 11, provide a temporary solution for OEMs to use the lower of the two MTU values
* for IPv4 and IPv6 if both are sent.
* TODO: remove in later release
@@ -4536,6 +4574,8 @@ public class CarrierConfigManager {
sDefaults.putStringArray(KEY_MISSED_INCOMING_CALL_SMS_PATTERN_STRING_ARRAY, new String[0]);
sDefaults.putBoolean(KEY_DISABLE_DUN_APN_WHILE_ROAMING_WITH_PRESET_APN_BOOL, false);
sDefaults.putString(KEY_DEFAULT_PREFERRED_APN_NAME_STRING, "");
+ sDefaults.putBoolean(KEY_SUPPORTS_CALL_COMPOSER_BOOL, false);
+ sDefaults.putString(KEY_CALL_COMPOSER_PICTURE_SERVER_URL_STRING, "");
sDefaults.putBoolean(KEY_USE_LOWER_MTU_VALUE_IF_BOTH_RECEIVED, false);
}
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 9b51e4a52b9e..886ec33af2b8 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -8105,6 +8105,7 @@ public class TelephonyManager {
*
* @hide
*/
+ @SystemApi
@RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public boolean isInEmergencySmsMode() {
try {
@@ -9463,7 +9464,7 @@ public class TelephonyManager {
}
/** @hide */
- @IntDef(flag = true, prefix = { "CDMA_SUBSCRIPTION_" }, value = {
+ @IntDef(prefix = { "CDMA_SUBSCRIPTION_" }, value = {
CDMA_SUBSCRIPTION_UNKNOWN,
CDMA_SUBSCRIPTION_RUIM_SIM,
CDMA_SUBSCRIPTION_NV
diff --git a/telephony/java/android/telephony/ims/DelegateMessageCallback.java b/telephony/java/android/telephony/ims/DelegateMessageCallback.java
index beec4a680d78..0d82a54a0f32 100644
--- a/telephony/java/android/telephony/ims/DelegateMessageCallback.java
+++ b/telephony/java/android/telephony/ims/DelegateMessageCallback.java
@@ -17,6 +17,7 @@
package android.telephony.ims;
import android.annotation.NonNull;
+import android.annotation.SystemApi;
import android.telephony.ims.stub.SipDelegate;
/**
@@ -30,6 +31,7 @@ import android.telephony.ims.stub.SipDelegate;
* </ul>
* @hide
*/
+@SystemApi
public interface DelegateMessageCallback {
/**
diff --git a/telephony/java/android/telephony/ims/DelegateRegistrationState.java b/telephony/java/android/telephony/ims/DelegateRegistrationState.java
index 4facfa77de21..3558a9b79ce0 100644
--- a/telephony/java/android/telephony/ims/DelegateRegistrationState.java
+++ b/telephony/java/android/telephony/ims/DelegateRegistrationState.java
@@ -18,14 +18,14 @@ package android.telephony.ims;
import android.annotation.IntDef;
import android.annotation.NonNull;
+import android.annotation.SuppressLint;
+import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.ArraySet;
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.Set;
@@ -34,6 +34,7 @@ import java.util.Set;
* ImsService.
* @hide
*/
+@SystemApi
public final class DelegateRegistrationState implements Parcelable {
/**
@@ -114,14 +115,14 @@ public final class DelegateRegistrationState implements Parcelable {
})
public @interface DeregisteringReason {}
- private final ArrayList<String> mRegisteredTags = new ArrayList<>();
- private final ArrayList<FeatureTagState> mDeregisteringTags = new ArrayList<>();
- private final ArrayList<FeatureTagState> mDeregisteredTags = new ArrayList<>();
+ private ArraySet<String> mRegisteredTags = new ArraySet<>();
+ private final ArraySet<FeatureTagState> mDeregisteringTags = new ArraySet<>();
+ private final ArraySet<FeatureTagState> mDeregisteredTags = new ArraySet<>();
/**
* Builder used to create new instances of {@link DelegateRegistrationState}.
*/
- public static class Builder {
+ public static final class Builder {
private final DelegateRegistrationState mState;
@@ -135,10 +136,8 @@ public final class DelegateRegistrationState implements Parcelable {
* @param featureTag The IMS media feature tag included in the current IMS registration.
* @return The in-progress Builder instance for RegistrationState.
*/
- public Builder addRegisteredFeatureTag(@NonNull String featureTag) {
- if (!mState.mRegisteredTags.contains(featureTag)) {
- mState.mRegisteredTags.add(featureTag);
- }
+ public @NonNull Builder addRegisteredFeatureTag(@NonNull String featureTag) {
+ mState.mRegisteredTags.add(featureTag);
return this;
}
@@ -148,7 +147,8 @@ public final class DelegateRegistrationState implements Parcelable {
* @param featureTags The IMS media feature tags included in the current IMS registration.
* @return The in-progress Builder instance for RegistrationState.
*/
- public Builder addRegisteredFeatureTags(@NonNull Set<String> featureTags) {
+ @SuppressLint("MissingGetterMatchingBuilder")
+ public @NonNull Builder addRegisteredFeatureTags(@NonNull Set<String> featureTags) {
mState.mRegisteredTags.addAll(featureTags);
return this;
}
@@ -167,13 +167,9 @@ public final class DelegateRegistrationState implements Parcelable {
* The availability of the feature tag depends on the {@link DeregisteringReason}.
* @return The in-progress Builder instance for RegistrationState.
*/
- public Builder addDeregisteringFeatureTag(@NonNull String featureTag,
+ public @NonNull Builder addDeregisteringFeatureTag(@NonNull String featureTag,
@DeregisteringReason int reason) {
- boolean ftExists = mState.mDeregisteringTags.stream().anyMatch(
- f -> f.getFeatureTag().equals(featureTag));
- if (!ftExists) {
- mState.mDeregisteringTags.add(new FeatureTagState(featureTag, reason));
- }
+ mState.mDeregisteringTags.add(new FeatureTagState(featureTag, reason));
return this;
}
@@ -185,20 +181,16 @@ public final class DelegateRegistrationState implements Parcelable {
* @param reason The reason why the media feature tag has been deregistered.
* @return The in-progress Builder instance for RegistrationState.
*/
- public Builder addDeregisteredFeatureTag(@NonNull String featureTag,
+ public @NonNull Builder addDeregisteredFeatureTag(@NonNull String featureTag,
@DeregisteredReason int reason) {
- boolean ftExists = mState.mDeregisteredTags.stream().anyMatch(
- f -> f.getFeatureTag().equals(featureTag));
- if (!ftExists) {
- mState.mDeregisteredTags.add(new FeatureTagState(featureTag, reason));
- }
+ mState.mDeregisteredTags.add(new FeatureTagState(featureTag, reason));
return this;
}
/**
* @return the finalized instance.
*/
- public DelegateRegistrationState build() {
+ public @NonNull DelegateRegistrationState build() {
return mState;
}
}
@@ -212,7 +204,7 @@ public final class DelegateRegistrationState implements Parcelable {
* Used for unparcelling only.
*/
private DelegateRegistrationState(Parcel source) {
- source.readList(mRegisteredTags, null /*classloader*/);
+ mRegisteredTags = (ArraySet<String>) source.readArraySet(null);
readStateFromParcel(source, mDeregisteringTags);
readStateFromParcel(source, mDeregisteredTags);
}
@@ -268,7 +260,8 @@ public final class DelegateRegistrationState implements Parcelable {
return new ArraySet<>(mDeregisteredTags);
}
- public static final Creator<DelegateRegistrationState> CREATOR =
+
+ public static final @NonNull Creator<DelegateRegistrationState> CREATOR =
new Creator<DelegateRegistrationState>() {
@Override
public DelegateRegistrationState createFromParcel(Parcel source) {
@@ -287,13 +280,13 @@ public final class DelegateRegistrationState implements Parcelable {
}
@Override
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeList(mRegisteredTags);
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeArraySet(mRegisteredTags);
writeStateToParcel(dest, mDeregisteringTags);
writeStateToParcel(dest, mDeregisteredTags);
}
- private void writeStateToParcel(Parcel dest, List<FeatureTagState> state) {
+ private void writeStateToParcel(Parcel dest, Set<FeatureTagState> state) {
dest.writeInt(state.size());
for (FeatureTagState s : state) {
dest.writeString(s.getFeatureTag());
@@ -301,11 +294,12 @@ public final class DelegateRegistrationState implements Parcelable {
}
}
- private void readStateFromParcel(Parcel source, List<FeatureTagState> emptyState) {
+ private void readStateFromParcel(Parcel source, Set<FeatureTagState> emptyState) {
int len = source.readInt();
for (int i = 0; i < len; i++) {
String ft = source.readString();
int reason = source.readInt();
+
emptyState.add(new FeatureTagState(ft, reason));
}
}
diff --git a/telephony/java/android/telephony/ims/DelegateRequest.java b/telephony/java/android/telephony/ims/DelegateRequest.java
index 73d0840177dd..c322d924182a 100644
--- a/telephony/java/android/telephony/ims/DelegateRequest.java
+++ b/telephony/java/android/telephony/ims/DelegateRequest.java
@@ -17,6 +17,7 @@
package android.telephony.ims;
import android.annotation.NonNull;
+import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
import android.telephony.ims.stub.SipDelegate;
@@ -31,6 +32,7 @@ import java.util.Set;
* SipDelegateConnection given back to the requesting application.
* @hide
*/
+@SystemApi
public final class DelegateRequest implements Parcelable {
private final ArrayList<String> mFeatureTags;
@@ -52,7 +54,7 @@ public final class DelegateRequest implements Parcelable {
* @return the list of IMS feature tag associated with this DelegateRequest in the format
* defined in RCC.07 section 2.6.1.3.
*/
- public Set<String> getFeatureTags() {
+ public @NonNull Set<String> getFeatureTags() {
return new ArraySet<>(mFeatureTags);
}
@@ -70,7 +72,7 @@ public final class DelegateRequest implements Parcelable {
}
@Override
- public void writeToParcel(Parcel dest, int flags) {
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeList(mFeatureTags);
}
diff --git a/telephony/java/android/telephony/ims/DelegateStateCallback.java b/telephony/java/android/telephony/ims/DelegateStateCallback.java
index 0f1afc42249e..fb659490d546 100644
--- a/telephony/java/android/telephony/ims/DelegateStateCallback.java
+++ b/telephony/java/android/telephony/ims/DelegateStateCallback.java
@@ -18,10 +18,11 @@ package android.telephony.ims;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.SystemApi;
import android.telephony.ims.stub.SipDelegate;
import android.telephony.ims.stub.SipTransportImplBase;
-import java.util.List;
+import java.util.Set;
/**
* Callback interface to notify a remote application of the following:
@@ -34,26 +35,24 @@ import java.util.List;
* </ul>
* @hide
*/
+@SystemApi
public interface DelegateStateCallback {
/**
* This must be called by the ImsService after {@link SipTransportImplBase#createSipDelegate} is
* called by the framework to notify the framework and remote application that the
* {@link SipDelegate} has been successfully created.
- *
- * @param delegate The SipDelegate created to service the DelegateRequest.
- * @param deniedTags A List of {@link FeatureTagState}, which contains the feature tags
+ * @param delegate The SipDelegate created to service the DelegateRequest.
+ * @param deniedTags A Set of {@link FeatureTagState}s, which contain the feature tags
* associated with this {@link SipDelegate} that have no access to send/receive SIP messages
* as well as a reason for why the feature tag is denied. For more information on the reason
* why the feature tag was denied access, see the
* {@link SipDelegateManager.DeniedReason} reasons. This is considered a permanent denial due
* to this {@link SipDelegate} not supporting a feature or this ImsService already
* implementing this feature elsewhere. If all features of this {@link SipDelegate} are
- * denied, {@link #onCreated(SipDelegate, List)} should still be called as the framework will
- * later call {@link SipTransportImplBase#destroySipDelegate(SipDelegate, int)} to clean the
- * delegate up.
+ * denied, this method should still be called.
*/
- void onCreated(@NonNull SipDelegate delegate, @Nullable List<FeatureTagState> deniedTags);
+ void onCreated(@NonNull SipDelegate delegate, @Nullable Set<FeatureTagState> deniedTags);
/**
* This must be called by the ImsService after the framework calls
diff --git a/telephony/java/android/telephony/ims/FeatureTagState.java b/telephony/java/android/telephony/ims/FeatureTagState.java
index 060be6f2510d..3622065c5fe8 100644
--- a/telephony/java/android/telephony/ims/FeatureTagState.java
+++ b/telephony/java/android/telephony/ims/FeatureTagState.java
@@ -17,6 +17,7 @@
package android.telephony.ims;
import android.annotation.NonNull;
+import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
import android.telephony.ims.stub.DelegateConnectionStateCallback;
@@ -39,6 +40,7 @@ import java.util.Objects;
* currently available.
* @hide
*/
+@SystemApi
public final class FeatureTagState implements Parcelable {
private final String mFeatureTag;
@@ -48,8 +50,8 @@ public final class FeatureTagState implements Parcelable {
* Associate an IMS feature tag with its current state. See {@link DelegateRegistrationState}
* and {@link DelegateConnectionStateCallback#onFeatureTagStatusChanged(
* DelegateRegistrationState, List)} and
- * {@link DelegateStateCallback#onCreated(SipDelegate, List)} for examples on how and when this
- * is used.
+ * {@link DelegateStateCallback#onCreated(SipDelegate, java.util.Set)} for examples on how and
+ * when this is used.
*
* @param featureTag The IMS feature tag that is deregistered, in the process of
* deregistering, or denied.
@@ -93,12 +95,12 @@ public final class FeatureTagState implements Parcelable {
}
@Override
- public void writeToParcel(Parcel dest, int flags) {
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeString(mFeatureTag);
dest.writeInt(mState);
}
- public static final Creator<FeatureTagState> CREATOR = new Creator<FeatureTagState>() {
+ public static final @NonNull Creator<FeatureTagState> CREATOR = new Creator<FeatureTagState>() {
@Override
public FeatureTagState createFromParcel(Parcel source) {
return new FeatureTagState(source);
diff --git a/telephony/java/android/telephony/ims/ImsCallProfile.java b/telephony/java/android/telephony/ims/ImsCallProfile.java
index 1b51936e873b..aaa68d6f7d57 100644
--- a/telephony/java/android/telephony/ims/ImsCallProfile.java
+++ b/telephony/java/android/telephony/ims/ImsCallProfile.java
@@ -18,6 +18,7 @@ package android.telephony.ims;
import android.annotation.IntDef;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.compat.annotation.UnsupportedAppUsage;
@@ -207,6 +208,42 @@ public final class ImsCallProfile implements Parcelable {
"android.telephony.ims.extra.RETRY_CALL_FAIL_NETWORKTYPE";
/**
+ * Extra for the call composer call priority, either {@link ImsCallProfile#PRIORITY_NORMAL} or
+ * {@link ImsCallProfile#PRIORITY_URGENT}. It can be set via
+ * {@link #setCallExtraInt(String, int)}.
+ *
+ * Reference: RCC.20 Section 2.4.4.2
+ */
+ public static final String EXTRA_PRIORITY = "android.telephony.ims.extra.PRIORITY";
+
+ // TODO(hallliu) remove the reference to the maximum length and update it later.
+ /**
+ * Extra for the call composer call subject, a string of maximum length 60 characters.
+ * It can be set via {@link #setCallExtra(String, String)}.
+ *
+ * Reference: RCC.20 Section 2.4.3.2
+ */
+ public static final String EXTRA_CALL_SUBJECT = "android.telephony.ims.extra.CALL_SUBJECT";
+
+ /**
+ * Extra for the call composer call location, an {@Link android.location.Location} parcelable
+ * class to represent the geolocation as a latitude and longitude pair. It can be set via
+ * {@link #setCallExtraParcelable(String, Parcelable)}.
+ *
+ * Reference: RCC.20 Section 2.4.3.2
+ */
+ public static final String EXTRA_LOCATION = "android.telephony.ims.extra.LOCATION";
+
+ /**
+ * Extra for the call composer picture URL, a String that indicates the URL on the carrier’s
+ * server infrastructure to get the picture. It can be set via
+ * {@link #setCallExtra(String, String)}.
+ *
+ * Reference: RCC.20 Section 2.4.3.2
+ */
+ public static final String EXTRA_PICTURE_URL = "android.telephony.ims.extra.PICTURE_URL";
+
+ /**
* Values for EXTRA_OIR / EXTRA_CNAP
*/
/**
@@ -244,6 +281,21 @@ public final class ImsCallProfile implements Parcelable {
*/
public static final int DIALSTRING_USSD = 2;
+ // Values for EXTRA_PRIORITY
+ /**
+ * Indicates the call composer call priority is normal.
+ *
+ * Reference: RCC.20 Section 2.4.4.2
+ */
+ public static final int PRIORITY_NORMAL = 0;
+
+ /**
+ * Indicates the call composer call priority is urgent.
+ *
+ * Reference: RCC.20 Section 2.4.4.2
+ */
+ public static final int PRIORITY_URGENT = 1;
+
/**
* Call is not restricted on peer side and High Definition media is supported
*/
@@ -588,6 +640,19 @@ public final class ImsCallProfile implements Parcelable {
return mCallExtras.getInt(name, defaultValue);
}
+ /**
+ * Get the call extras (Parcelable), given the extra name.
+ * @param name call extra name
+ * @return the corresponding call extra Parcelable or null if not applicable
+ */
+ @Nullable
+ public <T extends Parcelable> T getCallExtraParcelable(@Nullable String name) {
+ if (mCallExtras != null) {
+ return mCallExtras.getParcelable(name);
+ }
+ return null;
+ }
+
public void setCallExtra(String name, String value) {
if (mCallExtras != null) {
mCallExtras.putString(name, value);
@@ -607,6 +672,17 @@ public final class ImsCallProfile implements Parcelable {
}
/**
+ * Set the call extra value (Parcelable), given the call extra name.
+ * @param name call extra name
+ * @param parcelable call extra value
+ */
+ public void setCallExtraParcelable(@NonNull String name, @NonNull Parcelable parcelable) {
+ if (mCallExtras != null) {
+ mCallExtras.putParcelable(name, parcelable);
+ }
+ }
+
+ /**
* Set the call restrict cause, which provides the reason why a call has been restricted from
* using High Definition media.
*/
diff --git a/telephony/java/android/telephony/ims/ImsExternalCallState.java b/telephony/java/android/telephony/ims/ImsExternalCallState.java
index fdf636c323b6..c663e393fe06 100644
--- a/telephony/java/android/telephony/ims/ImsExternalCallState.java
+++ b/telephony/java/android/telephony/ims/ImsExternalCallState.java
@@ -49,8 +49,7 @@ public final class ImsExternalCallState implements Parcelable {
public static final int CALL_STATE_TERMINATED = 2;
/**@hide*/
- @IntDef(flag = true,
- value = {
+ @IntDef(value = {
CALL_STATE_CONFIRMED,
CALL_STATE_TERMINATED
},
@@ -59,8 +58,7 @@ public final class ImsExternalCallState implements Parcelable {
public @interface ExternalCallState {}
/**@hide*/
- @IntDef(flag = true,
- value = {
+ @IntDef(value = {
ImsCallProfile.CALL_TYPE_VOICE,
ImsCallProfile.CALL_TYPE_VT_TX,
ImsCallProfile.CALL_TYPE_VT_RX,
diff --git a/telephony/java/android/telephony/ims/ImsSsData.java b/telephony/java/android/telephony/ims/ImsSsData.java
index fb8e5d37875b..868dea6a3121 100644
--- a/telephony/java/android/telephony/ims/ImsSsData.java
+++ b/telephony/java/android/telephony/ims/ImsSsData.java
@@ -72,7 +72,7 @@ public final class ImsSsData implements Parcelable {
/**@hide*/
- @IntDef(flag = true, prefix = {"SS_"}, value = {
+ @IntDef(prefix = {"SS_"}, value = {
SS_ACTIVATION,
SS_DEACTIVATION,
SS_INTERROGATION,
@@ -89,7 +89,7 @@ public final class ImsSsData implements Parcelable {
public static final int SS_ERASURE = 4;
/**@hide*/
- @IntDef(flag = true, prefix = {"SS_"}, value = {
+ @IntDef(prefix = {"SS_"}, value = {
SS_ALL_TELE_AND_BEARER_SERVICES,
SS_ALL_TELESEVICES,
SS_TELEPHONY,
@@ -190,7 +190,7 @@ public final class ImsSsData implements Parcelable {
public static final int RESULT_SUCCESS = 0;
/** @hide */
- @IntDef(flag = true, prefix = { "SS_" }, value = {
+ @IntDef(prefix = { "SS_" }, value = {
SS_CFU,
SS_CF_BUSY,
SS_CF_NO_REPLY,
diff --git a/telephony/java/android/telephony/ims/RcsContactUceCapability.java b/telephony/java/android/telephony/ims/RcsContactUceCapability.java
index d12a6aef5186..5848be8b0bf2 100644
--- a/telephony/java/android/telephony/ims/RcsContactUceCapability.java
+++ b/telephony/java/android/telephony/ims/RcsContactUceCapability.java
@@ -105,10 +105,17 @@ public final class RcsContactUceCapability implements Parcelable {
public @interface RequestResult {}
/**
+ * The base class of {@link OptionsBuilder} and {@link PresenceBuilder}
+ */
+ public static abstract class RcsUcsCapabilityBuilder {
+ public abstract @NonNull RcsContactUceCapability build();
+ }
+
+ /**
* Builder to help construct {@link RcsContactUceCapability} instances when capabilities were
* queried through SIP OPTIONS.
*/
- public static class OptionsBuilder {
+ public static class OptionsBuilder extends RcsUcsCapabilityBuilder {
private final RcsContactUceCapability mCapabilities;
@@ -155,6 +162,7 @@ public final class RcsContactUceCapability implements Parcelable {
/**
* @return the constructed instance.
*/
+ @Override
public @NonNull RcsContactUceCapability build() {
return mCapabilities;
}
@@ -164,7 +172,7 @@ public final class RcsContactUceCapability implements Parcelable {
* Builder to help construct {@link RcsContactUceCapability} instances when capabilities were
* queried through a presence server.
*/
- public static class PresenceBuilder {
+ public static class PresenceBuilder extends RcsUcsCapabilityBuilder {
private final RcsContactUceCapability mCapabilities;
@@ -205,6 +213,7 @@ public final class RcsContactUceCapability implements Parcelable {
/**
* @return the RcsContactUceCapability instance.
*/
+ @Override
public @NonNull RcsContactUceCapability build() {
return mCapabilities;
}
diff --git a/telephony/java/android/telephony/ims/SipDelegateConnection.java b/telephony/java/android/telephony/ims/SipDelegateConnection.java
index 6bfdc2c6d48a..c3cc1edf590b 100644
--- a/telephony/java/android/telephony/ims/SipDelegateConnection.java
+++ b/telephony/java/android/telephony/ims/SipDelegateConnection.java
@@ -17,6 +17,7 @@
package android.telephony.ims;
import android.annotation.NonNull;
+import android.annotation.SystemApi;
import android.telephony.ims.stub.SipDelegate;
/**
@@ -36,6 +37,7 @@ import android.telephony.ims.stub.SipDelegate;
* @see SipDelegateManager#createSipDelegate
* @hide
*/
+@SystemApi
public interface SipDelegateConnection {
/**
@@ -47,9 +49,8 @@ public interface SipDelegateConnection {
* @param sipMessage The SipMessage to be sent.
* @param configVersion The SipDelegateImsConfiguration version used to construct the
* SipMessage. See {@link SipDelegateImsConfiguration#getVersion} for more
- * information on this parameter and why it is used.
*/
- void sendMessage(@NonNull SipMessage sipMessage, int configVersion);
+ void sendMessage(@NonNull SipMessage sipMessage, long configVersion);
/**
* Notify the {@link SipDelegate} that a SIP message received from
diff --git a/telephony/java/android/telephony/ims/SipDelegateImsConfiguration.java b/telephony/java/android/telephony/ims/SipDelegateImsConfiguration.java
index 8abd0ee94865..eddbb1002f20 100644
--- a/telephony/java/android/telephony/ims/SipDelegateImsConfiguration.java
+++ b/telephony/java/android/telephony/ims/SipDelegateImsConfiguration.java
@@ -17,7 +17,10 @@
package android.telephony.ims;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.StringDef;
+import android.annotation.SuppressLint;
+import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.PersistableBundle;
@@ -47,7 +50,8 @@ import java.lang.annotation.RetentionPolicy;
* update.
* @hide
*/
-public class SipDelegateImsConfiguration implements Parcelable {
+@SystemApi
+public final class SipDelegateImsConfiguration implements Parcelable {
/**
* IPV4 Address type.
@@ -354,7 +358,7 @@ public class SipDelegateImsConfiguration implements Parcelable {
/**
* Builder class to be used when constructing a new SipDelegateImsConfiguration.
*/
- public static class Builder {
+ public static final class Builder {
private final long mVersion;
private final PersistableBundle mBundle;
@@ -381,7 +385,10 @@ public class SipDelegateImsConfiguration implements Parcelable {
/**
* Put a string value into this configuration bundle for the given key.
*/
- public Builder putString(@StringConfigKey String key, String value) {
+ // getString is available below.
+ @SuppressLint("MissingGetterMatchingBuilder")
+ public @NonNull Builder addString(@NonNull @StringConfigKey String key,
+ @NonNull String value) {
mBundle.putString(key, value);
return this;
}
@@ -389,7 +396,9 @@ public class SipDelegateImsConfiguration implements Parcelable {
/**
* Replace the existing default value with a new value for a given key.
*/
- public Builder putInt(@IntConfigKey String key, int value) {
+ // getInt is available below.
+ @SuppressLint("MissingGetterMatchingBuilder")
+ public @NonNull Builder addInt(@NonNull @IntConfigKey String key, int value) {
mBundle.putInt(key, value);
return this;
}
@@ -397,7 +406,9 @@ public class SipDelegateImsConfiguration implements Parcelable {
/**
* Replace the existing default value with a new value for a given key.
*/
- public Builder putBoolean(@BooleanConfigKey String key, boolean value) {
+ // getBoolean is available below.
+ @SuppressLint("MissingGetterMatchingBuilder")
+ public @NonNull Builder addBoolean(@NonNull @BooleanConfigKey String key, boolean value) {
mBundle.putBoolean(key, value);
return this;
}
@@ -405,7 +416,7 @@ public class SipDelegateImsConfiguration implements Parcelable {
/**
* @return a new SipDelegateImsConfiguration from this Builder.
*/
- public SipDelegateImsConfiguration build() {
+ public @NonNull SipDelegateImsConfiguration build() {
return new SipDelegateImsConfiguration(mVersion, mBundle);
}
}
@@ -424,30 +435,38 @@ public class SipDelegateImsConfiguration implements Parcelable {
}
/**
+ * @return {@code true} if this configuration object has a an entry for the key specified,
+ * {@code false} if it does not.
+ */
+ public boolean containsKey(@NonNull String key) {
+ return mBundle.containsKey(key);
+ }
+
+ /**
* @return the string value associated with a given key or {@code null} if it doesn't exist.
*/
- public @StringConfigKey String getString(String key) {
+ public @Nullable @StringConfigKey String getString(@NonNull String key) {
return mBundle.getString(key);
}
/**
- * @return the Integer value associated with a given key or {@code null} if the value doesn't
- * exist.
+ * @return the integer value associated with a given key if it exists or the supplied default
+ * value if it does not.
*/
- public @IntConfigKey Integer getInt(String key) {
+ public @IntConfigKey int getInt(@NonNull String key, int defaultValue) {
if (!mBundle.containsKey(key)) {
- return null;
+ return defaultValue;
}
return mBundle.getInt(key);
}
/**
- * @return the Integer value associated with a given key or {@code null} if the value doesn't
- * exist.
+ * @return the boolean value associated with a given key or the supplied default value if the
+ * value doesn't exist in the bundle.
*/
- public @BooleanConfigKey Boolean getBoolen(String key) {
+ public @BooleanConfigKey boolean getBoolean(@NonNull String key, boolean defaultValue) {
if (!mBundle.containsKey(key)) {
- return null;
+ return defaultValue;
}
return mBundle.getBoolean(key);
}
@@ -455,7 +474,7 @@ public class SipDelegateImsConfiguration implements Parcelable {
/**
* @return a shallow copy of the full configuration.
*/
- public PersistableBundle copyBundle() {
+ public @NonNull PersistableBundle copyBundle() {
return new PersistableBundle(mBundle);
}
@@ -479,12 +498,12 @@ public class SipDelegateImsConfiguration implements Parcelable {
}
@Override
- public void writeToParcel(Parcel dest, int flags) {
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeLong(mVersion);
dest.writePersistableBundle(mBundle);
}
- public static final Creator<SipDelegateImsConfiguration> CREATOR =
+ public static final @NonNull Creator<SipDelegateImsConfiguration> CREATOR =
new Creator<SipDelegateImsConfiguration>() {
@Override
public SipDelegateImsConfiguration createFromParcel(Parcel source) {
diff --git a/telephony/java/android/telephony/ims/SipDelegateManager.java b/telephony/java/android/telephony/ims/SipDelegateManager.java
index 190a792b5a9a..2ec88ff27f93 100644
--- a/telephony/java/android/telephony/ims/SipDelegateManager.java
+++ b/telephony/java/android/telephony/ims/SipDelegateManager.java
@@ -54,7 +54,6 @@ public class SipDelegateManager {
* The SIP message has failed being sent or received for an unknown reason.
* <p>
* The caller should retry a message that failed with this response.
- * @hide
*/
public static final int MESSAGE_FAILURE_REASON_UNKNOWN = 0;
@@ -64,47 +63,40 @@ public class SipDelegateManager {
* <p>
* This is considered a permanent error and the system will automatically begin the teardown and
* destruction of the SipDelegate. No further messages should be sent on this transport.
- * @hide
*/
public static final int MESSAGE_FAILURE_REASON_DELEGATE_DEAD = 1;
/**
* The message has not been sent/received because the delegate is in the process of closing and
* has become unavailable. No further messages should be sent/received on this delegate.
- * @hide
*/
public static final int MESSAGE_FAILURE_REASON_DELEGATE_CLOSED = 2;
/**
* The SIP message has an invalid start line and the message can not be sent.
- * @hide
*/
public static final int MESSAGE_FAILURE_REASON_INVALID_START_LINE = 3;
/**
* One or more of the header fields in the header section of the outgoing SIP message is invalid
* and the SIP message can not be sent.
- * @hide
*/
public static final int MESSAGE_FAILURE_REASON_INVALID_HEADER_FIELDS = 4;
/**
* The body content of the SIP message is invalid and the message can not be sent.
- * @hide
*/
public static final int MESSAGE_FAILURE_REASON_INVALID_BODY_CONTENT = 5;
/**
* The feature tag associated with the outgoing message does not match any known feature tags
* and this message can not be sent.
- * @hide
*/
public static final int MESSAGE_FAILURE_REASON_INVALID_FEATURE_TAG = 6;
/**
* The feature tag associated with the outgoing message is not enabled for the associated
* SipDelegateConnection and can not be sent.
- * @hide
*/
public static final int MESSAGE_FAILURE_REASON_TAG_NOT_ENABLED_FOR_DELEGATE = 7;
@@ -113,7 +105,6 @@ public class SipDelegateManager {
* <p>
* This message should be retried when connectivity to the network is re-established. See
* {@link android.net.ConnectivityManager.NetworkCallback} for how this can be determined.
- * @hide
*/
public static final int MESSAGE_FAILURE_REASON_NETWORK_NOT_AVAILABLE = 8;
@@ -124,7 +115,6 @@ public class SipDelegateManager {
* This is considered a temporary failure, the message should not be retried until an IMS
* registration change callback is received via
* {@link DelegateConnectionStateCallback#onFeatureTagStatusChanged}
- * @hide
*/
public static final int MESSAGE_FAILURE_REASON_NOT_REGISTERED = 9;
@@ -135,7 +125,6 @@ public class SipDelegateManager {
* <p>
* The @link SipMessage} should be recreated using the newest
* {@link SipDelegateImsConfiguration} and sent again.
- * @hide
*/
public static final int MESSAGE_FAILURE_REASON_STALE_IMS_CONFIGURATION = 10;
@@ -146,7 +135,6 @@ public class SipDelegateManager {
* This is considered a temporary error and the {@link SipDelegateConnection} should resend the
* message once {@link DelegateRegistrationState#DEREGISTERING_REASON_FEATURE_TAGS_CHANGING} is
* no longer reported.
- * @hide
*/
public static final int MESSAGE_FAILURE_REASON_INTERNAL_DELEGATE_STATE_TRANSITION = 11;
@@ -171,7 +159,6 @@ public class SipDelegateManager {
/**
* Access to use this feature tag has been denied for an unknown reason.
- * @hide
*/
public static final int DENIED_REASON_UNKNOWN = 0;
@@ -179,14 +166,12 @@ public class SipDelegateManager {
* This feature tag is allowed to be used by this SipDelegateConnection, but it is in use by
* another SipDelegateConnection and can not be associated with this delegate. The feature tag
* will stay in this state until the feature tag is release by the other application.
- * @hide
*/
public static final int DENIED_REASON_IN_USE_BY_ANOTHER_DELEGATE = 1;
/**
* Access to use this feature tag has been denied because this application does not have the
* permissions required to access this feature tag.
- * @hide
*/
public static final int DENIED_REASON_NOT_ALLOWED = 2;
@@ -194,14 +179,12 @@ public class SipDelegateManager {
* Access to use this feature tag has been denied because single registration is not allowed by
* the carrier at this time. The application should fall back to dual registration if
* applicable.
- * @hide
*/
public static final int DENIED_REASON_SINGLE_REGISTRATION_NOT_ALLOWED = 3;
/**
* This feature tag is not recognized as a valid feature tag by the SipDelegate and has been
* denied.
- * @hide
*/
public static final int DENIED_REASON_INVALID = 4;
@@ -218,33 +201,28 @@ public class SipDelegateManager {
/**
* The SipDelegate has closed due to an unknown reason.
- * @hide
*/
public static final int SIP_DELEGATE_DESTROY_REASON_UNKNOWN = 0;
/**
* The SipDelegate has closed because the IMS service has died unexpectedly.
- * @hide
*/
public static final int SIP_DELEGATE_DESTROY_REASON_SERVICE_DEAD = 1;
/**
* The SipDelegate has closed because the IMS application has requested that the connection be
* destroyed.
- * @hide
*/
public static final int SIP_DELEGATE_DESTROY_REASON_REQUESTED_BY_APP = 2;
/**
* The SipDelegate has been closed due to the user disabling RCS.
- * @hide
*/
public static final int SIP_DELEGATE_DESTROY_REASON_USER_DISABLED_RCS = 3;
/**
* The SipDelegate has been closed due to the subscription associated with this delegate being
* torn down.
- * @hide
*/
public static final int SIP_DELEGATE_DESTROY_REASON_SUBSCRIPTION_TORN_DOWN = 4;
@@ -331,7 +309,6 @@ public class SipDelegateManager {
* SipDelegateConnection.
* @throws ImsException Thrown if there was a problem communicating with the ImsService
* associated with this SipDelegateManager. See {@link ImsException#getCode()}.
- * @hide
*/
@RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
public void createSipDelegate(@NonNull DelegateRequest request, @NonNull Executor executor,
@@ -366,7 +343,6 @@ public class SipDelegateManager {
* This will also clean up all related callbacks in the associated ImsService.
* @param delegateConnection The SipDelegateConnection to destroy.
* @param reason The reason for why this SipDelegateConnection was destroyed.
- * @hide
*/
@RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
public void destroySipDelegate(@NonNull SipDelegateConnection delegateConnection,
diff --git a/telephony/java/android/telephony/ims/SipMessage.java b/telephony/java/android/telephony/ims/SipMessage.java
index c3b1be2d7fc8..1539224dedcf 100644
--- a/telephony/java/android/telephony/ims/SipMessage.java
+++ b/telephony/java/android/telephony/ims/SipMessage.java
@@ -17,10 +17,14 @@
package android.telephony.ims;
import android.annotation.NonNull;
+import android.annotation.SystemApi;
import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
+import java.util.Arrays;
+import java.util.Objects;
+
/**
* Represents a partially encoded SIP message. See RFC 3261 for more information on how SIP
* messages are structured and used.
@@ -29,6 +33,7 @@ import android.os.Parcelable;
* verification and should not be used as a generic SIP message container.
* @hide
*/
+@SystemApi
public final class SipMessage implements Parcelable {
// Should not be set to true for production!
private static final boolean IS_DEBUGGING = Build.IS_ENG;
@@ -95,14 +100,14 @@ public final class SipMessage implements Parcelable {
}
@Override
- public void writeToParcel(Parcel dest, int flags) {
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeString(mStartLine);
dest.writeString(mHeaderSection);
dest.writeInt(mContent.length);
dest.writeByteArray(mContent);
}
- public static final Creator<SipMessage> CREATOR = new Creator<SipMessage>() {
+ public static final @NonNull Creator<SipMessage> CREATOR = new Creator<SipMessage>() {
@Override
public SipMessage createFromParcel(Parcel source) {
return new SipMessage(source);
@@ -152,4 +157,21 @@ public final class SipMessage implements Parcelable {
}
return startLine;
}
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ SipMessage that = (SipMessage) o;
+ return mStartLine.equals(that.mStartLine)
+ && mHeaderSection.equals(that.mHeaderSection)
+ && Arrays.equals(mContent, that.mContent);
+ }
+
+ @Override
+ public int hashCode() {
+ int result = Objects.hash(mStartLine, mHeaderSection);
+ result = 31 * result + Arrays.hashCode(mContent);
+ return result;
+ }
}
diff --git a/telephony/java/android/telephony/ims/aidl/ISipDelegate.aidl b/telephony/java/android/telephony/ims/aidl/ISipDelegate.aidl
index 477ee958e1e8..5d6766a65155 100644
--- a/telephony/java/android/telephony/ims/aidl/ISipDelegate.aidl
+++ b/telephony/java/android/telephony/ims/aidl/ISipDelegate.aidl
@@ -23,7 +23,7 @@ import android.telephony.ims.SipMessage;
* {@hide}
*/
oneway interface ISipDelegate {
- void sendMessage(in SipMessage sipMessage, int configVersion);
+ void sendMessage(in SipMessage sipMessage, long configVersion);
void notifyMessageReceived(in String viaTransactionId);
void notifyMessageReceiveError(in String viaTransactionId, int reason);
diff --git a/telephony/java/android/telephony/ims/aidl/ISubscribeResponseCallback.aidl b/telephony/java/android/telephony/ims/aidl/ISubscribeResponseCallback.aidl
index 4deaba1b7a49..a14199365b07 100644
--- a/telephony/java/android/telephony/ims/aidl/ISubscribeResponseCallback.aidl
+++ b/telephony/java/android/telephony/ims/aidl/ISubscribeResponseCallback.aidl
@@ -32,5 +32,5 @@ oneway interface ISubscribeResponseCallback {
void onNetworkResponse(int code, in String reason);
void onNotifyCapabilitiesUpdate(in List<String> pidfXmls);
void onResourceTerminated(in List<RcsContactTerminatedReason> uriTerminatedReason);
- void onTerminated(in String reason, in String retryAfter);
+ void onTerminated(in String reason, long retryAfterMilliseconds);
}
diff --git a/telephony/java/android/telephony/ims/aidl/RcsSubscribeResponseAidlWrapper.java b/telephony/java/android/telephony/ims/aidl/RcsSubscribeResponseAidlWrapper.java
index 37588ed98585..1fb339c0cf89 100644
--- a/telephony/java/android/telephony/ims/aidl/RcsSubscribeResponseAidlWrapper.java
+++ b/telephony/java/android/telephony/ims/aidl/RcsSubscribeResponseAidlWrapper.java
@@ -86,9 +86,9 @@ public class RcsSubscribeResponseAidlWrapper implements SubscribeResponseCallbac
}
@Override
- public void onTerminated(String reason, String retryAfter) throws ImsException {
+ public void onTerminated(String reason, long retryAfterMilliseconds) throws ImsException {
try {
- mResponseBinder.onTerminated(reason, retryAfter);
+ mResponseBinder.onTerminated(reason, retryAfterMilliseconds);
} catch (RemoteException e) {
}
}
diff --git a/telephony/java/android/telephony/ims/aidl/SipDelegateAidlWrapper.java b/telephony/java/android/telephony/ims/aidl/SipDelegateAidlWrapper.java
index a7f62cc32be1..522ad8160870 100644
--- a/telephony/java/android/telephony/ims/aidl/SipDelegateAidlWrapper.java
+++ b/telephony/java/android/telephony/ims/aidl/SipDelegateAidlWrapper.java
@@ -29,12 +29,13 @@ import android.telephony.ims.SipDelegateManager;
import android.telephony.ims.SipMessage;
import android.telephony.ims.stub.SipDelegate;
-import java.util.List;
+import java.util.ArrayList;
+import java.util.Set;
import java.util.concurrent.Executor;
/**
* Implementation of callbacks by wrapping the internal AIDL from telephony. Also implements
- * ISipDelegate internally when {@link DelegateStateCallback#onCreated(SipDelegate, List)} is called
+ * ISipDelegate internally when {@link DelegateStateCallback#onCreated(SipDelegate, Set)} is called
* in order to trampoline events back to telephony.
* @hide
*/
@@ -42,7 +43,7 @@ public class SipDelegateAidlWrapper implements DelegateStateCallback, DelegateMe
private final ISipDelegate.Stub mDelegateBinder = new ISipDelegate.Stub() {
@Override
- public void sendMessage(SipMessage sipMessage, int configVersion) {
+ public void sendMessage(SipMessage sipMessage, long configVersion) {
SipDelegate d = mDelegate;
final long token = Binder.clearCallingIdentity();
try {
@@ -136,10 +137,10 @@ public class SipDelegateAidlWrapper implements DelegateStateCallback, DelegateMe
@Override
public void onCreated(@NonNull SipDelegate delegate,
- @Nullable List<FeatureTagState> deniedTags) {
+ @Nullable Set<FeatureTagState> deniedTags) {
mDelegate = delegate;
try {
- mStateBinder.onCreated(mDelegateBinder, deniedTags);
+ mStateBinder.onCreated(mDelegateBinder, new ArrayList<>(deniedTags));
} catch (RemoteException e) {
// BinderDied will trigger destroySipDelegate, so just ignore this locally.
}
diff --git a/telephony/java/android/telephony/ims/aidl/SipDelegateConnectionAidlWrapper.java b/telephony/java/android/telephony/ims/aidl/SipDelegateConnectionAidlWrapper.java
index 3bd1a462b31a..29ba8e2d50c4 100644
--- a/telephony/java/android/telephony/ims/aidl/SipDelegateConnectionAidlWrapper.java
+++ b/telephony/java/android/telephony/ims/aidl/SipDelegateConnectionAidlWrapper.java
@@ -158,7 +158,7 @@ public class SipDelegateConnectionAidlWrapper implements SipDelegateConnection,
}
@Override
- public void sendMessage(SipMessage sipMessage, int configVersion) {
+ public void sendMessage(SipMessage sipMessage, long configVersion) {
try {
ISipDelegate conn = getSipDelegateBinder();
if (conn == null) {
diff --git a/telephony/java/android/telephony/ims/stub/DelegateConnectionMessageCallback.java b/telephony/java/android/telephony/ims/stub/DelegateConnectionMessageCallback.java
index 59f9601299b2..eefe8493aef1 100644
--- a/telephony/java/android/telephony/ims/stub/DelegateConnectionMessageCallback.java
+++ b/telephony/java/android/telephony/ims/stub/DelegateConnectionMessageCallback.java
@@ -17,6 +17,7 @@
package android.telephony.ims.stub;
import android.annotation.NonNull;
+import android.annotation.SystemApi;
import android.telephony.ims.SipDelegateConnection;
import android.telephony.ims.SipDelegateManager;
import android.telephony.ims.SipMessage;
@@ -26,6 +27,7 @@ import android.telephony.ims.SipMessage;
* messages as well as the result of sending a SIP message.
* @hide
*/
+@SystemApi
public interface DelegateConnectionMessageCallback {
/**
@@ -49,6 +51,6 @@ public interface DelegateConnectionMessageCallback {
* previously sent {@link SipMessage}.
* @param reason The reason for the failure.
*/
- void onMessageSendFailure(String viaTransactionId,
+ void onMessageSendFailure(@NonNull String viaTransactionId,
@SipDelegateManager.MessageFailureReason int reason);
}
diff --git a/telephony/java/android/telephony/ims/stub/DelegateConnectionStateCallback.java b/telephony/java/android/telephony/ims/stub/DelegateConnectionStateCallback.java
index 976180538b18..02218ead0ad7 100644
--- a/telephony/java/android/telephony/ims/stub/DelegateConnectionStateCallback.java
+++ b/telephony/java/android/telephony/ims/stub/DelegateConnectionStateCallback.java
@@ -17,6 +17,7 @@
package android.telephony.ims.stub;
import android.annotation.NonNull;
+import android.annotation.SystemApi;
import android.telephony.ims.DelegateRegistrationState;
import android.telephony.ims.DelegateRequest;
import android.telephony.ims.FeatureTagState;
@@ -58,6 +59,7 @@ import java.util.Set;
*
* @hide
*/
+@SystemApi
public interface DelegateConnectionStateCallback {
/**
diff --git a/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java b/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java
index a6f5c45445f5..153d687dd84f 100644
--- a/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java
@@ -49,8 +49,7 @@ public class ImsRegistrationImplBase {
* @hide
*/
// Defines the underlying radio technology type that we have registered for IMS over.
- @IntDef(flag = true,
- value = {
+ @IntDef(value = {
REGISTRATION_TECH_NONE,
REGISTRATION_TECH_LTE,
REGISTRATION_TECH_IWLAN
diff --git a/telephony/java/android/telephony/ims/stub/RcsCapabilityExchangeImplBase.java b/telephony/java/android/telephony/ims/stub/RcsCapabilityExchangeImplBase.java
index b5704bfb3569..3a0fb6edb2fb 100644
--- a/telephony/java/android/telephony/ims/stub/RcsCapabilityExchangeImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/RcsCapabilityExchangeImplBase.java
@@ -250,7 +250,7 @@ public class RcsCapabilityExchangeImplBase {
* This allows the framework to know that there will no longer be any
* capability updates for the requested operationToken.
*/
- void onTerminated(String reason, String retryAfter) throws ImsException;
+ void onTerminated(String reason, long retryAfterMilliseconds) throws ImsException;
}
diff --git a/telephony/java/android/telephony/ims/stub/SipDelegate.java b/telephony/java/android/telephony/ims/stub/SipDelegate.java
index 3ec97095eb00..d7e7b62dd550 100644
--- a/telephony/java/android/telephony/ims/stub/SipDelegate.java
+++ b/telephony/java/android/telephony/ims/stub/SipDelegate.java
@@ -17,6 +17,7 @@
package android.telephony.ims.stub;
import android.annotation.NonNull;
+import android.annotation.SystemApi;
import android.telephony.ims.DelegateMessageCallback;
import android.telephony.ims.ImsService;
import android.telephony.ims.SipDelegateImsConfiguration;
@@ -40,6 +41,7 @@ import android.telephony.ims.SipMessage;
* {@link android.telephony.ims.DelegateStateCallback} for more information.
* @hide
*/
+@SystemApi
public interface SipDelegate {
/**
@@ -57,7 +59,7 @@ public interface SipDelegate {
* {@link DelegateMessageCallback#onMessageSendFailure} should be called with code
* {@link SipDelegateManager#MESSAGE_FAILURE_REASON_STALE_IMS_CONFIGURATION}.
*/
- void sendMessage(@NonNull SipMessage message, int configVersion);
+ void sendMessage(@NonNull SipMessage message, long configVersion);
/**
* The framework is requesting that routing resources associated with the SIP dialog using the
diff --git a/telephony/java/android/telephony/ims/stub/SipTransportImplBase.java b/telephony/java/android/telephony/ims/stub/SipTransportImplBase.java
index 93d438cf7f4d..1f74c09af0f6 100644
--- a/telephony/java/android/telephony/ims/stub/SipTransportImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/SipTransportImplBase.java
@@ -17,6 +17,7 @@
package android.telephony.ims.stub;
import android.annotation.NonNull;
+import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.os.Binder;
import android.os.IBinder;
@@ -32,7 +33,6 @@ import android.telephony.ims.aidl.SipDelegateAidlWrapper;
import android.util.Log;
import java.util.ArrayList;
-import java.util.List;
import java.util.Objects;
import java.util.concurrent.Executor;
@@ -99,7 +99,8 @@ public class SipTransportImplBase {
/**
* Called by the Telephony framework to request the creation of a new {@link SipDelegate}.
* <p>
- * The implementation must call {@link DelegateStateCallback#onCreated(SipDelegate, List)} with
+ * The implementation must call
+ * {@link DelegateStateCallback#onCreated(SipDelegate, java.util.Set)} with
* the {@link SipDelegate} that is associated with the {@link DelegateRequest}.
* <p>
* This method will be called on the Executor specified in
@@ -112,8 +113,9 @@ public class SipTransportImplBase {
* for the SipDelegate.
* @param mc A callback back to the remote application to be used to send SIP messages to the
* remote application and acknowledge the sending of outgoing SIP messages.
- * @hide
*/
+ // executor used is defined in the constructor.
+ @SuppressLint("ExecutorRegistration")
public void createSipDelegate(int subscriptionId, @NonNull DelegateRequest request,
@NonNull DelegateStateCallback dc, @NonNull DelegateMessageCallback mc) {
throw new UnsupportedOperationException("createSipDelegate not implemented!");
@@ -130,7 +132,6 @@ public class SipTransportImplBase {
* @param delegate The delegate to be destroyed.
* @param reason The reason the remote connection to this {@link SipDelegate} is being
* destroyed.
- * @hide
*/
public void destroySipDelegate(@NonNull SipDelegate delegate,
@SipDelegateManager.SipDelegateDestroyReason int reason) {
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index b524549440da..5d4fdd0ff556 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -857,6 +857,11 @@ interface ITelephony {
in int[] featureTypes, in String packageName);
/**
+ * @return true if the ImsService cleared any carrier ImsService overrides, false otherwise.
+ */
+ boolean clearCarrierImsServiceOverride(int slotIndex);
+
+ /**
* @return the package name of the carrier/device ImsService associated with this slot.
*/
String getBoundImsServicePackage(int slotIndex, boolean isCarrierImsService, int featureType);
diff --git a/tests/BootImageProfileTest/TEST_MAPPING b/tests/BootImageProfileTest/TEST_MAPPING
new file mode 100644
index 000000000000..1b569f9455bf
--- /dev/null
+++ b/tests/BootImageProfileTest/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "presubmit": [
+ {
+ "name": "BootImageProfileTest"
+ }
+ ]
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt
index a20f96d17278..67deca4fe387 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt
@@ -16,6 +16,7 @@
package com.android.server.wm.flicker.close
+import androidx.test.filters.FlakyTest
import android.view.Surface
import androidx.test.filters.RequiresDevice
import androidx.test.platform.app.InstrumentationRegistry
@@ -54,6 +55,7 @@ import org.junit.runners.Parameterized
@RequiresDevice
@RunWith(Parameterized::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@FlakyTest(bugId = 174635878)
class CloseAppBackButtonTest(
testName: String,
flickerSpec: Flicker
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt
index 4bbb38c4d71a..252ce2a32bf0 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt
@@ -16,6 +16,7 @@
package com.android.server.wm.flicker.close
+import androidx.test.filters.FlakyTest
import android.view.Surface
import androidx.test.filters.RequiresDevice
import androidx.test.platform.app.InstrumentationRegistry
@@ -54,6 +55,7 @@ import org.junit.runners.Parameterized
@RequiresDevice
@RunWith(Parameterized::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@FlakyTest(bugId = 174635878)
class CloseAppHomeButtonTest(
testName: String,
flickerSpec: Flicker
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt
index 1f03c4dc056d..686ddcbd66bd 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt
@@ -105,8 +105,7 @@ class OpenAppColdTest(
configuration.endRotation)
navBarLayerIsAlwaysVisible(enabled = false)
statusBarLayerIsAlwaysVisible(enabled = false)
- visibleLayersShownMoreThanOneConsecutiveEntry(
- enabled = Surface.ROTATION_0 == configuration.endRotation)
+ visibleLayersShownMoreThanOneConsecutiveEntry(bugId = 174541970)
appLayerReplacesWallpaperLayer(testApp)
}
diff --git a/tests/RollbackTest/RollbackTest/AndroidManifest.xml b/tests/RollbackTest/RollbackTest/AndroidManifest.xml
index 9274da268735..590105b3209f 100644
--- a/tests/RollbackTest/RollbackTest/AndroidManifest.xml
+++ b/tests/RollbackTest/RollbackTest/AndroidManifest.xml
@@ -19,8 +19,6 @@
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
<application>
- <receiver android:name="com.android.cts.install.lib.LocalIntentSender"
- android:exported="true" />
<uses-library android:name="android.test.runner" />
</application>
diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
index 52718bec9148..3d8deb5cfc8d 100644
--- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
+++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
@@ -34,7 +34,6 @@ import androidx.test.platform.app.InstrumentationRegistry;
import com.android.cts.install.lib.Install;
import com.android.cts.install.lib.InstallUtils;
-import com.android.cts.install.lib.LocalIntentSender;
import com.android.cts.install.lib.TestApp;
import com.android.cts.install.lib.Uninstall;
import com.android.cts.rollback.lib.Rollback;
@@ -258,10 +257,6 @@ public class StagedRollbackTest {
.getPackageManager().getPackageInstaller();
pi.abandonSession(sessionId);
- // Remove the first intent sender result, so that the next staged install session does not
- // erroneously think that it has itself been abandoned.
- // TODO(b/136260017): Restructure LocalIntentSender to negate the need for this step.
- LocalIntentSender.getIntentSenderResult();
Install.single(TestApp.A2).setStaged().setEnableRollback().commit();
}
diff --git a/tests/StagedInstallTest/app/AndroidManifest.xml b/tests/StagedInstallTest/app/AndroidManifest.xml
index a678f1ec3691..d7ac9d0f9ce4 100644
--- a/tests/StagedInstallTest/app/AndroidManifest.xml
+++ b/tests/StagedInstallTest/app/AndroidManifest.xml
@@ -20,8 +20,6 @@
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
<application>
- <receiver android:name="com.android.cts.install.lib.LocalIntentSender"
- android:exported="true" />
<uses-library android:name="android.test.runner" />
</application>
diff --git a/tests/net/common/java/android/net/OemNetworkPreferencesTest.java b/tests/net/common/java/android/net/OemNetworkPreferencesTest.java
index b77ed6ab5a29..cade5ba3771f 100644
--- a/tests/net/common/java/android/net/OemNetworkPreferencesTest.java
+++ b/tests/net/common/java/android/net/OemNetworkPreferencesTest.java
@@ -22,10 +22,13 @@ import static com.android.testutils.ParcelUtils.assertParcelSane;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
+import android.os.Build;
import android.util.SparseArray;
import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
+
+import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
+import com.android.testutils.DevSdkIgnoreRunner;
import org.junit.Before;
import org.junit.Test;
@@ -34,7 +37,8 @@ import org.junit.runner.RunWith;
import java.util.ArrayList;
import java.util.List;
-@RunWith(AndroidJUnit4.class)
+@IgnoreUpTo(Build.VERSION_CODES.R)
+@RunWith(DevSdkIgnoreRunner.class)
@SmallTest
public class OemNetworkPreferencesTest {
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 3619937d76ed..5d4573716145 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -56,8 +56,10 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_IA;
import static android.net.NetworkCapabilities.NET_CAPABILITY_IMS;
import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
import static android.net.NetworkCapabilities.NET_CAPABILITY_MMS;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING;
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_PARTIAL_CONNECTIVITY;
@@ -1058,7 +1060,9 @@ public class ConnectivityServiceTest {
public void setUids(Set<UidRange> uids) {
mNetworkCapabilities.setUids(uids);
- updateCapabilitiesInternal(null /* defaultNetwork */, true);
+ if (mAgentRegistered) {
+ mMockNetworkAgent.setNetworkCapabilities(mNetworkCapabilities, true);
+ }
}
public void setVpnType(int vpnType) {
@@ -1089,6 +1093,10 @@ public class ConnectivityServiceTest {
mMockNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_VPN, lp,
mNetworkCapabilities);
mMockNetworkAgent.waitForIdle(TIMEOUT_MS);
+ verify(mNetworkManagementService, times(1))
+ .addVpnUidRanges(eq(mMockVpn.getNetId()), eq(uids.toArray(new UidRange[0])));
+ verify(mNetworkManagementService, never())
+ .removeVpnUidRanges(eq(mMockVpn.getNetId()), any());
mAgentRegistered = true;
mNetworkCapabilities.set(mMockNetworkAgent.getNetworkCapabilities());
mNetworkAgent = mMockNetworkAgent.getNetworkAgent();
@@ -1143,28 +1151,6 @@ public class ConnectivityServiceTest {
mMockNetworkAgent.sendLinkProperties(lp);
}
- private NetworkCapabilities updateCapabilitiesInternal(Network defaultNetwork,
- boolean sendToConnectivityService) {
- if (!mAgentRegistered) return null;
- super.updateCapabilities(defaultNetwork);
- // Because super.updateCapabilities will update the capabilities of the agent but
- // not the mock agent, the mock agent needs to know about them.
- copyCapabilitiesToNetworkAgent(sendToConnectivityService);
- return new NetworkCapabilities(mNetworkCapabilities);
- }
-
- private void copyCapabilitiesToNetworkAgent(boolean sendToConnectivityService) {
- if (null != mMockNetworkAgent) {
- mMockNetworkAgent.setNetworkCapabilities(mNetworkCapabilities,
- sendToConnectivityService);
- }
- }
-
- @Override
- public NetworkCapabilities updateCapabilities(Network defaultNetwork) {
- return updateCapabilitiesInternal(defaultNetwork, false);
- }
-
public void disconnect() {
if (mMockNetworkAgent != null) mMockNetworkAgent.disconnect();
mAgentRegistered = false;
@@ -5414,6 +5400,106 @@ public class ConnectivityServiceTest {
}
@Test
+ public void testApplyUnderlyingCapabilities() throws Exception {
+ mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
+ mCellNetworkAgent.connect(false /* validated */);
+ mWiFiNetworkAgent.connect(false /* validated */);
+
+ final NetworkCapabilities cellNc = new NetworkCapabilities()
+ .addTransportType(TRANSPORT_CELLULAR)
+ .addCapability(NET_CAPABILITY_INTERNET)
+ .addCapability(NET_CAPABILITY_NOT_CONGESTED)
+ .setLinkDownstreamBandwidthKbps(10);
+ final NetworkCapabilities wifiNc = new NetworkCapabilities()
+ .addTransportType(TRANSPORT_WIFI)
+ .addCapability(NET_CAPABILITY_INTERNET)
+ .addCapability(NET_CAPABILITY_NOT_METERED)
+ .addCapability(NET_CAPABILITY_NOT_ROAMING)
+ .addCapability(NET_CAPABILITY_NOT_CONGESTED)
+ .addCapability(NET_CAPABILITY_NOT_SUSPENDED)
+ .setLinkUpstreamBandwidthKbps(20);
+ mCellNetworkAgent.setNetworkCapabilities(cellNc, true /* sendToConnectivityService */);
+ mWiFiNetworkAgent.setNetworkCapabilities(wifiNc, true /* sendToConnectivityService */);
+ waitForIdle();
+
+ final Network mobile = mCellNetworkAgent.getNetwork();
+ final Network wifi = mWiFiNetworkAgent.getNetwork();
+
+ final NetworkCapabilities initialCaps = new NetworkCapabilities();
+ initialCaps.addCapability(NET_CAPABILITY_INTERNET);
+ initialCaps.removeCapability(NET_CAPABILITY_NOT_VPN);
+
+ final NetworkCapabilities withNoUnderlying = new NetworkCapabilities();
+ withNoUnderlying.addCapability(NET_CAPABILITY_INTERNET);
+ withNoUnderlying.addCapability(NET_CAPABILITY_NOT_CONGESTED);
+ withNoUnderlying.addCapability(NET_CAPABILITY_NOT_ROAMING);
+ withNoUnderlying.addCapability(NET_CAPABILITY_NOT_SUSPENDED);
+ withNoUnderlying.addTransportType(TRANSPORT_VPN);
+ withNoUnderlying.removeCapability(NET_CAPABILITY_NOT_VPN);
+
+ final NetworkCapabilities withMobileUnderlying = new NetworkCapabilities(withNoUnderlying);
+ withMobileUnderlying.addTransportType(TRANSPORT_CELLULAR);
+ withMobileUnderlying.removeCapability(NET_CAPABILITY_NOT_ROAMING);
+ withMobileUnderlying.removeCapability(NET_CAPABILITY_NOT_SUSPENDED);
+ withMobileUnderlying.setLinkDownstreamBandwidthKbps(10);
+
+ final NetworkCapabilities withWifiUnderlying = new NetworkCapabilities(withNoUnderlying);
+ withWifiUnderlying.addTransportType(TRANSPORT_WIFI);
+ withWifiUnderlying.addCapability(NET_CAPABILITY_NOT_METERED);
+ withWifiUnderlying.setLinkUpstreamBandwidthKbps(20);
+
+ final NetworkCapabilities withWifiAndMobileUnderlying =
+ new NetworkCapabilities(withNoUnderlying);
+ withWifiAndMobileUnderlying.addTransportType(TRANSPORT_CELLULAR);
+ withWifiAndMobileUnderlying.addTransportType(TRANSPORT_WIFI);
+ withWifiAndMobileUnderlying.removeCapability(NET_CAPABILITY_NOT_METERED);
+ withWifiAndMobileUnderlying.removeCapability(NET_CAPABILITY_NOT_ROAMING);
+ withWifiAndMobileUnderlying.setLinkDownstreamBandwidthKbps(10);
+ withWifiAndMobileUnderlying.setLinkUpstreamBandwidthKbps(20);
+
+ NetworkCapabilities caps = new NetworkCapabilities(initialCaps);
+ final boolean notDeclaredMetered = false;
+ mService.applyUnderlyingCapabilities(new Network[]{}, caps, notDeclaredMetered);
+ assertEquals(withNoUnderlying, caps);
+
+ caps = new NetworkCapabilities(initialCaps);
+ mService.applyUnderlyingCapabilities(new Network[]{null}, caps, notDeclaredMetered);
+ assertEquals(withNoUnderlying, caps);
+
+ caps = new NetworkCapabilities(initialCaps);
+ mService.applyUnderlyingCapabilities(new Network[]{mobile}, caps, notDeclaredMetered);
+ assertEquals(withMobileUnderlying, caps);
+
+ mService.applyUnderlyingCapabilities(new Network[]{wifi}, caps, notDeclaredMetered);
+ assertEquals(withWifiUnderlying, caps);
+
+ final boolean isDeclaredMetered = true;
+ withWifiUnderlying.removeCapability(NET_CAPABILITY_NOT_METERED);
+ caps = new NetworkCapabilities(initialCaps);
+ mService.applyUnderlyingCapabilities(new Network[]{wifi}, caps, isDeclaredMetered);
+ assertEquals(withWifiUnderlying, caps);
+
+ caps = new NetworkCapabilities(initialCaps);
+ mService.applyUnderlyingCapabilities(new Network[]{mobile, wifi}, caps, isDeclaredMetered);
+ assertEquals(withWifiAndMobileUnderlying, caps);
+
+ withWifiUnderlying.addCapability(NET_CAPABILITY_NOT_METERED);
+ caps = new NetworkCapabilities(initialCaps);
+ mService.applyUnderlyingCapabilities(new Network[]{null, mobile, null, wifi},
+ caps, notDeclaredMetered);
+ assertEquals(withWifiAndMobileUnderlying, caps);
+
+ caps = new NetworkCapabilities(initialCaps);
+ mService.applyUnderlyingCapabilities(new Network[]{null, mobile, null, wifi},
+ caps, notDeclaredMetered);
+ assertEquals(withWifiAndMobileUnderlying, caps);
+
+ mService.applyUnderlyingCapabilities(null, caps, notDeclaredMetered);
+ assertEquals(withWifiUnderlying, caps);
+ }
+
+ @Test
public void testVpnConnectDisconnectUnderlyingNetwork() throws Exception {
final TestNetworkCallback callback = new TestNetworkCallback();
final NetworkRequest request = new NetworkRequest.Builder()
@@ -5963,17 +6049,28 @@ public class ConnectivityServiceTest {
&& caps.hasTransport(TRANSPORT_VPN)
&& caps.hasTransport(TRANSPORT_WIFI));
+ // Change the VPN's capabilities somehow (specifically, disconnect wifi).
+ mWiFiNetworkAgent.disconnect();
+ callback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
+ callback.expectCapabilitiesThat(mMockVpn, (caps)
+ -> caps.getUids().size() == 2
+ && caps.getUids().contains(new UidRange(uid, uid))
+ && caps.getUids().contains(UidRange.createForUser(restrictedUserId))
+ && caps.hasTransport(TRANSPORT_VPN)
+ && !caps.hasTransport(TRANSPORT_WIFI));
+
// Send a USER_REMOVED broadcast and expect to lose the UID range for the restricted user.
final Intent removedIntent = new Intent(ACTION_USER_REMOVED);
removedIntent.putExtra(Intent.EXTRA_USER_HANDLE, restrictedUserId);
handler.post(() -> mServiceContext.sendBroadcast(removedIntent));
- // Expect that the VPN gains the UID range for the restricted user.
+ // Expect that the VPN gains the UID range for the restricted user, and that the capability
+ // change made just before that (i.e., loss of TRANSPORT_WIFI) is preserved.
callback.expectCapabilitiesThat(mMockVpn, (caps)
-> caps.getUids().size() == 1
&& caps.getUids().contains(new UidRange(uid, uid))
&& caps.hasTransport(TRANSPORT_VPN)
- && caps.hasTransport(TRANSPORT_WIFI));
+ && !caps.hasTransport(TRANSPORT_WIFI));
}
@Test
@@ -6922,8 +7019,8 @@ public class ConnectivityServiceTest {
final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(VPN_USER));
mMockVpn.establish(lp, VPN_UID, vpnRange);
- // Connected VPN should have interface rules set up. There are two expected invocations,
- // one during VPN uid update, one during VPN LinkProperties update
+ // A connected VPN should have interface rules set up. There are two expected invocations,
+ // one during the VPN initial connection, one during the VPN LinkProperties update.
ArgumentCaptor<int[]> uidCaptor = ArgumentCaptor.forClass(int[].class);
verify(mMockNetd, times(2)).firewallAddUidInterfaceRules(eq("tun0"), uidCaptor.capture());
assertContainsExactly(uidCaptor.getAllValues().get(0), APP1_UID, APP2_UID);
@@ -7438,20 +7535,14 @@ public class ConnectivityServiceTest {
setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION);
- // setUp() calls mockVpn() which adds a VPN with the Test Runner's uid. Configure it to be
- // active
- final VpnInfo info = new VpnInfo();
- info.ownerUid = Process.myUid();
- info.vpnIface = VPN_IFNAME;
- mMockVpn.setVpnInfo(info);
-
mMockVpn.establishForMyUid();
- waitForIdle();
+ // Wait for networks to connect and broadcasts to be sent before removing permissions.
+ waitForIdle();
mServiceContext.setPermission(android.Manifest.permission.NETWORK_STACK, PERMISSION_DENIED);
-
assertTrue(mService.setUnderlyingNetworksForVpn(new Network[] {network}));
+ waitForIdle();
assertTrue(
"Active VPN permission not applied",
mService.checkConnectivityDiagnosticsPermissions(
@@ -7459,6 +7550,7 @@ public class ConnectivityServiceTest {
mContext.getOpPackageName()));
assertTrue(mService.setUnderlyingNetworksForVpn(null));
+ waitForIdle();
assertFalse(
"VPN shouldn't receive callback on non-underlying network",
mService.checkConnectivityDiagnosticsPermissions(
diff --git a/tests/net/java/com/android/server/connectivity/VpnTest.java b/tests/net/java/com/android/server/connectivity/VpnTest.java
index 1dcc07c6db81..337507ac1d46 100644
--- a/tests/net/java/com/android/server/connectivity/VpnTest.java
+++ b/tests/net/java/com/android/server/connectivity/VpnTest.java
@@ -21,15 +21,6 @@ import static android.content.pm.UserInfo.FLAG_MANAGED_PROFILE;
import static android.content.pm.UserInfo.FLAG_PRIMARY;
import static android.content.pm.UserInfo.FLAG_RESTRICTED;
import static android.net.ConnectivityManager.NetworkCallback;
-import static android.net.NetworkCapabilities.LINK_BANDWIDTH_UNSPECIFIED;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED;
-import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
-import static android.net.NetworkCapabilities.TRANSPORT_VPN;
-import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
@@ -41,6 +32,7 @@ import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.doAnswer;
@@ -86,10 +78,10 @@ import android.os.Build.VERSION_CODES;
import android.os.Bundle;
import android.os.ConditionVariable;
import android.os.INetworkManagementService;
-import android.os.Looper;
import android.os.Process;
import android.os.UserHandle;
import android.os.UserManager;
+import android.os.test.TestLooper;
import android.provider.Settings;
import android.security.Credentials;
import android.security.KeyStore;
@@ -100,6 +92,7 @@ import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import com.android.internal.R;
+import com.android.internal.net.LegacyVpnInfo;
import com.android.internal.net.VpnConfig;
import com.android.internal.net.VpnProfile;
import com.android.server.IpSecService;
@@ -223,6 +216,8 @@ public class VpnTest {
.thenReturn(mNotificationManager);
when(mContext.getSystemService(eq(Context.CONNECTIVITY_SERVICE)))
.thenReturn(mConnectivityManager);
+ when(mContext.getSystemServiceName(eq(ConnectivityManager.class)))
+ .thenReturn(Context.CONNECTIVITY_SERVICE);
when(mContext.getSystemService(eq(Context.IPSEC_SERVICE))).thenReturn(mIpSecManager);
when(mContext.getString(R.string.config_customVpnAlwaysOnDisconnectedDialogComponent))
.thenReturn(Resources.getSystem().getString(
@@ -589,7 +584,7 @@ public class VpnTest {
}
@Test
- public void testNotificationShownForAlwaysOnApp() {
+ public void testNotificationShownForAlwaysOnApp() throws Exception {
final UserHandle userHandle = UserHandle.of(primaryUser.id);
final Vpn vpn = createVpn(primaryUser.id);
setMockedUsers(primaryUser);
@@ -617,103 +612,6 @@ public class VpnTest {
order.verify(mNotificationManager).cancel(anyString(), anyInt());
}
- @Test
- public void testCapabilities() {
- final Vpn vpn = createVpn(primaryUser.id);
- setMockedUsers(primaryUser);
-
- final Network mobile = new Network(1);
- final Network wifi = new Network(2);
-
- final Map<Network, NetworkCapabilities> networks = new HashMap<>();
- networks.put(
- mobile,
- new NetworkCapabilities()
- .addTransportType(TRANSPORT_CELLULAR)
- .addCapability(NET_CAPABILITY_INTERNET)
- .addCapability(NET_CAPABILITY_NOT_CONGESTED)
- .setLinkDownstreamBandwidthKbps(10));
- networks.put(
- wifi,
- new NetworkCapabilities()
- .addTransportType(TRANSPORT_WIFI)
- .addCapability(NET_CAPABILITY_INTERNET)
- .addCapability(NET_CAPABILITY_NOT_METERED)
- .addCapability(NET_CAPABILITY_NOT_ROAMING)
- .addCapability(NET_CAPABILITY_NOT_CONGESTED)
- .addCapability(NET_CAPABILITY_NOT_SUSPENDED)
- .setLinkUpstreamBandwidthKbps(20));
- setMockedNetworks(networks);
-
- final NetworkCapabilities caps = new NetworkCapabilities();
-
- Vpn.applyUnderlyingCapabilities(
- mConnectivityManager, new Network[] {}, caps, false /* isAlwaysMetered */);
- assertTrue(caps.hasTransport(TRANSPORT_VPN));
- assertFalse(caps.hasTransport(TRANSPORT_CELLULAR));
- assertFalse(caps.hasTransport(TRANSPORT_WIFI));
- assertEquals(LINK_BANDWIDTH_UNSPECIFIED, caps.getLinkDownstreamBandwidthKbps());
- assertEquals(LINK_BANDWIDTH_UNSPECIFIED, caps.getLinkUpstreamBandwidthKbps());
- assertFalse(caps.hasCapability(NET_CAPABILITY_NOT_METERED));
- assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_ROAMING));
- assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_CONGESTED));
- assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
-
- Vpn.applyUnderlyingCapabilities(
- mConnectivityManager,
- new Network[] {mobile},
- caps,
- false /* isAlwaysMetered */);
- assertTrue(caps.hasTransport(TRANSPORT_VPN));
- assertTrue(caps.hasTransport(TRANSPORT_CELLULAR));
- assertFalse(caps.hasTransport(TRANSPORT_WIFI));
- assertEquals(10, caps.getLinkDownstreamBandwidthKbps());
- assertEquals(LINK_BANDWIDTH_UNSPECIFIED, caps.getLinkUpstreamBandwidthKbps());
- assertFalse(caps.hasCapability(NET_CAPABILITY_NOT_METERED));
- assertFalse(caps.hasCapability(NET_CAPABILITY_NOT_ROAMING));
- assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_CONGESTED));
- assertFalse(caps.hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
-
- Vpn.applyUnderlyingCapabilities(
- mConnectivityManager, new Network[] {wifi}, caps, false /* isAlwaysMetered */);
- assertTrue(caps.hasTransport(TRANSPORT_VPN));
- assertFalse(caps.hasTransport(TRANSPORT_CELLULAR));
- assertTrue(caps.hasTransport(TRANSPORT_WIFI));
- assertEquals(LINK_BANDWIDTH_UNSPECIFIED, caps.getLinkDownstreamBandwidthKbps());
- assertEquals(20, caps.getLinkUpstreamBandwidthKbps());
- assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_METERED));
- assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_ROAMING));
- assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_CONGESTED));
- assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
-
- Vpn.applyUnderlyingCapabilities(
- mConnectivityManager, new Network[] {wifi}, caps, true /* isAlwaysMetered */);
- assertTrue(caps.hasTransport(TRANSPORT_VPN));
- assertFalse(caps.hasTransport(TRANSPORT_CELLULAR));
- assertTrue(caps.hasTransport(TRANSPORT_WIFI));
- assertEquals(LINK_BANDWIDTH_UNSPECIFIED, caps.getLinkDownstreamBandwidthKbps());
- assertEquals(20, caps.getLinkUpstreamBandwidthKbps());
- assertFalse(caps.hasCapability(NET_CAPABILITY_NOT_METERED));
- assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_ROAMING));
- assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_CONGESTED));
- assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
-
- Vpn.applyUnderlyingCapabilities(
- mConnectivityManager,
- new Network[] {mobile, wifi},
- caps,
- false /* isAlwaysMetered */);
- assertTrue(caps.hasTransport(TRANSPORT_VPN));
- assertTrue(caps.hasTransport(TRANSPORT_CELLULAR));
- assertTrue(caps.hasTransport(TRANSPORT_WIFI));
- assertEquals(10, caps.getLinkDownstreamBandwidthKbps());
- assertEquals(20, caps.getLinkUpstreamBandwidthKbps());
- assertFalse(caps.hasCapability(NET_CAPABILITY_NOT_METERED));
- assertFalse(caps.hasCapability(NET_CAPABILITY_NOT_ROAMING));
- assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_CONGESTED));
- assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
- }
-
/**
* The profile name should NOT change between releases for backwards compatibility
*
@@ -1037,7 +935,7 @@ public class VpnTest {
when(exception.getErrorType())
.thenReturn(IkeProtocolException.ERROR_TYPE_AUTHENTICATION_FAILED);
- final Vpn vpn = startLegacyVpn(mVpnProfile);
+ final Vpn vpn = startLegacyVpn(createVpn(primaryUser.id), (mVpnProfile));
final NetworkCallback cb = triggerOnAvailableAndGetCallback();
// Wait for createIkeSession() to be called before proceeding in order to ensure consistent
@@ -1048,20 +946,20 @@ public class VpnTest {
ikeCb.onClosedExceptionally(exception);
verify(mConnectivityManager, timeout(TEST_TIMEOUT_MS)).unregisterNetworkCallback(eq(cb));
- assertEquals(DetailedState.FAILED, vpn.getNetworkInfo().getDetailedState());
+ assertEquals(LegacyVpnInfo.STATE_FAILED, vpn.getLegacyVpnInfo().state);
}
@Test
public void testStartPlatformVpnIllegalArgumentExceptionInSetup() throws Exception {
when(mIkev2SessionCreator.createIkeSession(any(), any(), any(), any(), any(), any()))
.thenThrow(new IllegalArgumentException());
- final Vpn vpn = startLegacyVpn(mVpnProfile);
+ final Vpn vpn = startLegacyVpn(createVpn(primaryUser.id), mVpnProfile);
final NetworkCallback cb = triggerOnAvailableAndGetCallback();
// Wait for createIkeSession() to be called before proceeding in order to ensure consistent
// state
verify(mConnectivityManager, timeout(TEST_TIMEOUT_MS)).unregisterNetworkCallback(eq(cb));
- assertEquals(DetailedState.FAILED, vpn.getNetworkInfo().getDetailedState());
+ assertEquals(LegacyVpnInfo.STATE_FAILED, vpn.getLegacyVpnInfo().state);
}
private void setAndVerifyAlwaysOnPackage(Vpn vpn, int uid, boolean lockdownEnabled) {
@@ -1100,8 +998,7 @@ public class VpnTest {
// a subsequent CL.
}
- public Vpn startLegacyVpn(final VpnProfile vpnProfile) throws Exception {
- final Vpn vpn = createVpn(primaryUser.id);
+ private Vpn startLegacyVpn(final Vpn vpn, final VpnProfile vpnProfile) throws Exception {
setMockedUsers(primaryUser);
// Dummy egress interface
@@ -1118,7 +1015,7 @@ public class VpnTest {
@Test
public void testStartPlatformVpn() throws Exception {
- startLegacyVpn(mVpnProfile);
+ startLegacyVpn(createVpn(primaryUser.id), mVpnProfile);
// TODO: Test the Ikev2VpnRunner started up properly. Relies on utility methods added in
// a subsequent patch.
}
@@ -1153,7 +1050,7 @@ public class VpnTest {
legacyRunnerReady.open();
return new Network(102);
});
- final Vpn vpn = startLegacyVpn(profile);
+ final Vpn vpn = startLegacyVpn(createVpn(primaryUser.id), profile);
final TestDeps deps = (TestDeps) vpn.mDeps;
try {
// udppsk and 1701 are the values for TYPE_L2TP_IPSEC_PSK
@@ -1287,8 +1184,13 @@ public class VpnTest {
doReturn(UserHandle.of(userId)).when(asUserContext).getUser();
when(mContext.createContextAsUser(eq(UserHandle.of(userId)), anyInt()))
.thenReturn(asUserContext);
- return new Vpn(Looper.myLooper(), mContext, new TestDeps(), mNetService,
+ final TestLooper testLooper = new TestLooper();
+ final Vpn vpn = new Vpn(testLooper.getLooper(), mContext, new TestDeps(), mNetService,
userId, mKeyStore, mSystemServices, mIkev2SessionCreator);
+ verify(mConnectivityManager, times(1)).registerNetworkProvider(argThat(
+ provider -> provider.getName().contains("VpnNetworkProvider")
+ ));
+ return vpn;
}
private static void assertBlocked(Vpn vpn, int... uids) {
diff --git a/tools/aapt2/cmd/Link.h b/tools/aapt2/cmd/Link.h
index 852b1244cd6e..768b4b2c7bfd 100644
--- a/tools/aapt2/cmd/Link.h
+++ b/tools/aapt2/cmd/Link.h
@@ -190,8 +190,11 @@ class LinkCommand : public Command {
AddOptionalFlag("--version-name",
"Version name to inject into the AndroidManifest.xml if none is present.",
&options_.manifest_fixer_options.version_name_default);
+ AddOptionalFlag("--revision-code",
+ "Revision code (integer) to inject into the AndroidManifest.xml if none is\n"
+ "present.", &options_.manifest_fixer_options.revision_code_default);
AddOptionalSwitch("--replace-version",
- "If --version-code and/or --version-name are specified, these\n"
+ "If --version-code, --version-name, and/or --revision-code are specified, these\n"
"values will replace any value already in the manifest. By\n"
"default, nothing is changed if the manifest already defines\n"
"these attributes.",
diff --git a/tools/aapt2/link/ManifestFixer.cpp b/tools/aapt2/link/ManifestFixer.cpp
index c03661ca2366..8abd9dec56be 100644
--- a/tools/aapt2/link/ManifestFixer.cpp
+++ b/tools/aapt2/link/ManifestFixer.cpp
@@ -367,6 +367,16 @@ bool ManifestFixer::BuildRules(xml::XmlActionExecutor* executor,
}
}
+ if (options_.revision_code_default) {
+ if (options_.replace_version) {
+ el->RemoveAttribute(xml::kSchemaAndroid, "revisionCode");
+ }
+ if (el->FindAttribute(xml::kSchemaAndroid, "revisionCode") == nullptr) {
+ el->attributes.push_back(xml::Attribute{xml::kSchemaAndroid, "revisionCode",
+ options_.revision_code_default.value()});
+ }
+ }
+
return true;
});
diff --git a/tools/aapt2/link/ManifestFixer.h b/tools/aapt2/link/ManifestFixer.h
index ec4367b450fb..34ad8d586df1 100644
--- a/tools/aapt2/link/ManifestFixer.h
+++ b/tools/aapt2/link/ManifestFixer.h
@@ -60,6 +60,10 @@ struct ManifestFixerOptions {
// replace_version is set.
Maybe<std::string> version_code_major_default;
+ // The revision code to set if 'android:revisionCode' is not defined in <manifest> or if
+ // replace_version is set.
+ Maybe<std::string> revision_code_default;
+
// The version of the framework being compiled against to set for 'android:compileSdkVersion' in
// the <manifest> tag.
Maybe<std::string> compile_sdk_version;
diff --git a/tools/aapt2/link/ManifestFixer_test.cpp b/tools/aapt2/link/ManifestFixer_test.cpp
index 781ff7b51637..432f10bdab97 100644
--- a/tools/aapt2/link/ManifestFixer_test.cpp
+++ b/tools/aapt2/link/ManifestFixer_test.cpp
@@ -445,6 +445,66 @@ TEST_F(ManifestFixerTest, ReplaceVersionNameAndCode) {
EXPECT_THAT(attr->value, StrEq("0x20000000"));
}
+TEST_F(ManifestFixerTest, UseDefaultRevisionCode) {
+ ManifestFixerOptions options;
+ options.revision_code_default = std::string("0x10000000");
+
+ std::unique_ptr<xml::XmlResource> doc = VerifyWithOptions(R"EOF(
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android"
+ android:versionCode="0x00000001" />)EOF",
+ options);
+ ASSERT_THAT(doc, NotNull());
+
+ xml::Element* manifest_el = doc->root.get();
+ ASSERT_THAT(manifest_el, NotNull());
+
+ xml::Attribute* attr = manifest_el->FindAttribute(xml::kSchemaAndroid, "revisionCode");
+ ASSERT_THAT(attr, NotNull());
+ EXPECT_THAT(attr->value, StrEq("0x10000000"));
+}
+
+TEST_F(ManifestFixerTest, DontUseDefaultRevisionCode) {
+ ManifestFixerOptions options;
+ options.revision_code_default = std::string("0x10000000");
+
+ std::unique_ptr<xml::XmlResource> doc = VerifyWithOptions(R"EOF(
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android"
+ android:versionCode="0x00000001"
+ android:revisionCode="0x00000002" />)EOF",
+ options);
+ ASSERT_THAT(doc, NotNull());
+
+ xml::Element* manifest_el = doc->root.get();
+ ASSERT_THAT(manifest_el, NotNull());
+
+ xml::Attribute* attr = manifest_el->FindAttribute(xml::kSchemaAndroid, "revisionCode");
+ ASSERT_THAT(attr, NotNull());
+ EXPECT_THAT(attr->value, StrEq("0x00000002"));
+}
+
+TEST_F(ManifestFixerTest, ReplaceRevisionCode) {
+ ManifestFixerOptions options;
+ options.replace_version = true;
+ options.revision_code_default = std::string("0x10000000");
+
+ std::unique_ptr<xml::XmlResource> doc = VerifyWithOptions(R"EOF(
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android"
+ android:versionCode="0x00000001"
+ android:revisionCode="0x00000002" />)EOF",
+ options);
+ ASSERT_THAT(doc, NotNull());
+
+ xml::Element* manifest_el = doc->root.get();
+ ASSERT_THAT(manifest_el, NotNull());
+
+ xml::Attribute* attr = manifest_el->FindAttribute(xml::kSchemaAndroid, "revisionCode");
+ ASSERT_THAT(attr, NotNull());
+ EXPECT_THAT(attr->value, StrEq("0x10000000"));
+}
+
TEST_F(ManifestFixerTest, ReplaceVersionName) {
ManifestFixerOptions options;
options.replace_version = true;
diff --git a/tools/codegen/src/com/android/codegen/ClassPrinter.kt b/tools/codegen/src/com/android/codegen/ClassPrinter.kt
index b90e1bb3e7e7..8cae14a2d040 100644
--- a/tools/codegen/src/com/android/codegen/ClassPrinter.kt
+++ b/tools/codegen/src/com/android/codegen/ClassPrinter.kt
@@ -145,7 +145,6 @@ class ClassPrinter(
}
return when {
cliArgs.contains("--hidden-$kebabCase") -> true
- this == FeatureFlag.BUILD_UPON -> FeatureFlag.BUILDER.hidden
else -> false
}
}
diff --git a/tools/codegen/src/com/android/codegen/SharedConstants.kt b/tools/codegen/src/com/android/codegen/SharedConstants.kt
index 6a635d0e6181..d9ad649782bb 100644
--- a/tools/codegen/src/com/android/codegen/SharedConstants.kt
+++ b/tools/codegen/src/com/android/codegen/SharedConstants.kt
@@ -1,7 +1,7 @@
package com.android.codegen
const val CODEGEN_NAME = "codegen"
-const val CODEGEN_VERSION = "1.0.21"
+const val CODEGEN_VERSION = "1.0.22"
const val CANONICAL_BUILDER_CLASS = "Builder"
const val BASE_BUILDER_CLASS = "BaseBuilder"
diff --git a/tools/processors/intdef_mappings/src/android/processor/IntDefProcessor.kt b/tools/processors/intdef_mappings/src/android/processor/IntDefProcessor.kt
index 84faeea36eea..4c1fa6ec40b3 100644
--- a/tools/processors/intdef_mappings/src/android/processor/IntDefProcessor.kt
+++ b/tools/processors/intdef_mappings/src/android/processor/IntDefProcessor.kt
@@ -33,13 +33,12 @@ import javax.tools.Diagnostic.Kind
import javax.tools.StandardLocation.CLASS_OUTPUT
import kotlin.collections.set
-
/**
* The IntDefProcessor is intended to generate a mapping from ints to their respective string
* identifier for each IntDef for use by Winscope or any other tool which requires such a mapping.
*
- * The processor will run when building :frameworks-all and dump all the IntDef mappings found the
- * files the make up :frameworks-all as json to outputPath.
+ * The processor will run when building :framework-minus-apex-intdefs and dump all the IntDef
+ * mappings found in the files that make up the build target as json to outputPath.
*/
class IntDefProcessor : AbstractProcessor() {
private val outputName = "intDefMapping.json"
@@ -72,8 +71,8 @@ class IntDefProcessor : AbstractProcessor() {
}
private fun generateIntDefMapping(
- annotatedElement: TypeElement,
- annotationType: TypeElement
+ annotatedElement: TypeElement,
+ annotationType: TypeElement
): Map<Int, String> {
// LinkedHashMap makes sure ordering is the same as in the code
val mapping = LinkedHashMap<Int, String>()
@@ -151,8 +150,8 @@ class IntDefProcessor : AbstractProcessor() {
companion object {
fun serializeTo(
- annotationTypeToIntDefMapping: Map<String, IntDefMapping>,
- writer: Writer
+ annotationTypeToIntDefMapping: Map<String, IntDefMapping>,
+ writer: Writer
) {
val indent = " "
diff --git a/wifi/Android.bp b/wifi/Android.bp
index 52e3840c126e..7a9ca6012be5 100644
--- a/wifi/Android.bp
+++ b/wifi/Android.bp
@@ -147,7 +147,7 @@ java_sdk_library {
// defaults for tests that need to build against framework-wifi's @hide APIs
java_defaults {
name: "framework-wifi-test-defaults",
- sdk_version: "core_platform", // tests can use @CorePlatformApi's
+ sdk_version: "core_current",
libs: [
// order matters: classes in framework-wifi are resolved before framework, meaning
// @hide APIs in framework-wifi are resolved before @SystemApi stubs in framework
diff --git a/wifi/aidl-export/android/net/wifi/CoexUnsafeChannel.aidl b/wifi/aidl-export/android/net/wifi/CoexUnsafeChannel.aidl
new file mode 100644
index 000000000000..cb359e9b2c1b
--- /dev/null
+++ b/wifi/aidl-export/android/net/wifi/CoexUnsafeChannel.aidl
@@ -0,0 +1,19 @@
+/**
+ * Copyright (c) 2020, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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;
+
+parcelable CoexUnsafeChannel;
diff --git a/wifi/api/current.txt b/wifi/api/current.txt
index 911f2fbc6afa..ce2b8ca4f2cd 100644
--- a/wifi/api/current.txt
+++ b/wifi/api/current.txt
@@ -14,6 +14,7 @@ package android.net.wifi {
field public static final int EASY_CONNECT_EVENT_FAILURE_NOT_COMPATIBLE = -3; // 0xfffffffd
field public static final int EASY_CONNECT_EVENT_FAILURE_NOT_SUPPORTED = -8; // 0xfffffff8
field public static final int EASY_CONNECT_EVENT_FAILURE_TIMEOUT = -6; // 0xfffffffa
+ field public static final int EASY_CONNECT_EVENT_FAILURE_URI_GENERATION = -13; // 0xfffffff3
}
public final class ScanResult implements android.os.Parcelable {
diff --git a/wifi/api/system-current.txt b/wifi/api/system-current.txt
index c4a1766f982c..48d9fd453b05 100644
--- a/wifi/api/system-current.txt
+++ b/wifi/api/system-current.txt
@@ -1,8 +1,20 @@
// Signature format: 2.0
package android.net.wifi {
+ public final class CoexUnsafeChannel implements android.os.Parcelable {
+ ctor public CoexUnsafeChannel(int, int);
+ ctor public CoexUnsafeChannel(int, int, int);
+ method public int getBand();
+ method public int getChannel();
+ method public int getPowerCapDbm();
+ method public boolean isPowerCapAvailable();
+ method public void setPowerCapDbm(int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.CoexUnsafeChannel> CREATOR;
+ }
+
public abstract class EasyConnectStatusCallback {
ctor public EasyConnectStatusCallback();
+ method public void onBootstrapUriGenerated(@NonNull String);
method public abstract void onConfiguratorSuccess(int);
method public abstract void onEnrolleeSuccess(int);
method public void onFailure(int);
@@ -455,6 +467,8 @@ package android.net.wifi {
method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void factoryReset();
method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK}) public void forget(int, @Nullable android.net.wifi.WifiManager.ActionListener);
method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public java.util.List<android.util.Pair<android.net.wifi.WifiConfiguration,java.util.Map<java.lang.Integer,java.util.List<android.net.wifi.ScanResult>>>> getAllMatchingWifiConfigs(@NonNull java.util.List<android.net.wifi.ScanResult>);
+ method @RequiresPermission(android.Manifest.permission.WIFI_ACCESS_COEX_UNSAFE_CHANNELS) public int getCoexRestrictions();
+ method @NonNull @RequiresPermission(android.Manifest.permission.WIFI_ACCESS_COEX_UNSAFE_CHANNELS) public java.util.Set<android.net.wifi.CoexUnsafeChannel> getCoexUnsafeChannels();
method @Nullable @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public String getCountryCode();
method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public android.net.Network getCurrentNetwork();
method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public String[] getFactoryMacAddresses();
@@ -475,6 +489,7 @@ package android.net.wifi {
method public boolean isVerboseLoggingEnabled();
method @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public boolean isWifiApEnabled();
method public boolean isWifiScannerSupported();
+ method @RequiresPermission(android.Manifest.permission.WIFI_ACCESS_COEX_UNSAFE_CHANNELS) public void registerCoexCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.WifiManager.CoexCallback);
method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void registerNetworkRequestMatchCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.WifiManager.NetworkRequestMatchCallback);
method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void registerSoftApCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.WifiManager.SoftApCallback);
method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void registerTrafficStateCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.WifiManager.TrafficStateCallback);
@@ -486,6 +501,7 @@ package android.net.wifi {
method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public byte[] retrieveSoftApBackupData();
method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK}) public void save(@NonNull android.net.wifi.WifiConfiguration, @Nullable android.net.wifi.WifiManager.ActionListener);
method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void setAutoWakeupEnabled(boolean);
+ method @RequiresPermission(android.Manifest.permission.WIFI_UPDATE_COEX_UNSAFE_CHANNELS) public void setCoexUnsafeChannels(@NonNull java.util.Set<android.net.wifi.CoexUnsafeChannel>, int);
method @RequiresPermission(android.Manifest.permission.WIFI_SET_DEVICE_MOBILITY_STATE) public void setDeviceMobilityState(int);
method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void setMacRandomizationSettingPasspointEnabled(@NonNull String, boolean);
method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void setPasspointMeteredOverride(@NonNull String, int);
@@ -497,6 +513,7 @@ package android.net.wifi {
method @RequiresPermission(android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE) public boolean setWifiConnectedNetworkScorer(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.WifiManager.WifiConnectedNetworkScorer);
method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public void startEasyConnectAsConfiguratorInitiator(@NonNull String, int, int, @NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.EasyConnectStatusCallback);
method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public void startEasyConnectAsEnrolleeInitiator(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.EasyConnectStatusCallback);
+ method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public void startEasyConnectAsEnrolleeResponder(@Nullable String, int, @NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.EasyConnectStatusCallback);
method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public void startLocalOnlyHotspot(@NonNull android.net.wifi.SoftApConfiguration, @Nullable java.util.concurrent.Executor, @Nullable android.net.wifi.WifiManager.LocalOnlyHotspotCallback);
method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public boolean startScan(android.os.WorkSource);
method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public void startSubscriptionProvisioning(@NonNull android.net.wifi.hotspot2.OsuProvider, @NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.hotspot2.ProvisioningCallback);
@@ -505,6 +522,7 @@ package android.net.wifi {
method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public void stopEasyConnectSession();
method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public boolean stopSoftAp();
method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void stopTemporarilyDisablingAllNonCarrierMergedWifi();
+ method @RequiresPermission(android.Manifest.permission.WIFI_ACCESS_COEX_UNSAFE_CHANNELS) public void unregisterCoexCallback(@NonNull android.net.wifi.WifiManager.CoexCallback);
method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void unregisterNetworkRequestMatchCallback(@NonNull android.net.wifi.WifiManager.NetworkRequestMatchCallback);
method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void unregisterSoftApCallback(@NonNull android.net.wifi.WifiManager.SoftApCallback);
method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void unregisterTrafficStateCallback(@NonNull android.net.wifi.WifiManager.TrafficStateCallback);
@@ -518,11 +536,22 @@ package android.net.wifi {
field public static final int CHANGE_REASON_ADDED = 0; // 0x0
field public static final int CHANGE_REASON_CONFIG_CHANGE = 2; // 0x2
field public static final int CHANGE_REASON_REMOVED = 1; // 0x1
+ field public static final int COEX_RESTRICTION_SOFTAP = 2; // 0x2
+ field public static final int COEX_RESTRICTION_WIFI_AWARE = 4; // 0x4
+ field public static final int COEX_RESTRICTION_WIFI_DIRECT = 1; // 0x1
field public static final String CONFIGURED_NETWORKS_CHANGED_ACTION = "android.net.wifi.CONFIGURED_NETWORKS_CHANGE";
field public static final int DEVICE_MOBILITY_STATE_HIGH_MVMT = 1; // 0x1
field public static final int DEVICE_MOBILITY_STATE_LOW_MVMT = 2; // 0x2
field public static final int DEVICE_MOBILITY_STATE_STATIONARY = 3; // 0x3
field public static final int DEVICE_MOBILITY_STATE_UNKNOWN = 0; // 0x0
+ field public static final int EASY_CONNECT_CRYPTOGRAPHY_CURVE_BRAINPOOLP256R1 = 3; // 0x3
+ field public static final int EASY_CONNECT_CRYPTOGRAPHY_CURVE_BRAINPOOLP384R1 = 4; // 0x4
+ field public static final int EASY_CONNECT_CRYPTOGRAPHY_CURVE_BRAINPOOLP512R1 = 5; // 0x5
+ field public static final int EASY_CONNECT_CRYPTOGRAPHY_CURVE_DEFAULT = 0; // 0x0
+ field public static final int EASY_CONNECT_CRYPTOGRAPHY_CURVE_PRIME256V1 = 0; // 0x0
+ field public static final int EASY_CONNECT_CRYPTOGRAPHY_CURVE_SECP384R1 = 1; // 0x1
+ field public static final int EASY_CONNECT_CRYPTOGRAPHY_CURVE_SECP521R1 = 2; // 0x2
+ field public static final int EASY_CONNECT_DEVICE_INFO_MAXIMUM_LENGTH = 40; // 0x28
field public static final int EASY_CONNECT_NETWORK_ROLE_AP = 1; // 0x1
field public static final int EASY_CONNECT_NETWORK_ROLE_STA = 0; // 0x0
field public static final String EXTRA_CHANGE_REASON = "changeReason";
@@ -565,6 +594,11 @@ package android.net.wifi {
method public void onSuccess();
}
+ public abstract static class WifiManager.CoexCallback {
+ ctor public WifiManager.CoexCallback();
+ method public abstract void onCoexUnsafeChannelsChanged();
+ }
+
public static interface WifiManager.NetworkRequestMatchCallback {
method public default void onAbort();
method public default void onMatch(@NonNull java.util.List<android.net.wifi.ScanResult>);
diff --git a/wifi/java/android/net/wifi/CoexUnsafeChannel.java b/wifi/java/android/net/wifi/CoexUnsafeChannel.java
new file mode 100644
index 000000000000..3f9efa020d05
--- /dev/null
+++ b/wifi/java/android/net/wifi/CoexUnsafeChannel.java
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 static android.net.wifi.WifiScanner.WIFI_BAND_24_GHZ;
+import static android.net.wifi.WifiScanner.WIFI_BAND_5_GHZ;
+import static android.net.wifi.WifiScanner.WIFI_BAND_6_GHZ;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Objects;
+
+/**
+ * Data structure class representing a Wi-Fi channel that would cause interference to/receive
+ * interference from the active cellular channels and should be avoided.
+ *
+ * If {@link #isPowerCapAvailable()} is {@code true}, then a valid power cap value is available
+ * through {@link #getPowerCapDbm()} to be used if this channel cannot be avoided. If {@code false},
+ * then {@link #getPowerCapDbm()} throws an IllegalStateException and the channel will not need to
+ * cap its power.
+ *
+ * @hide
+ */
+@SystemApi
+public final class CoexUnsafeChannel implements Parcelable {
+ private @WifiAnnotations.WifiBandBasic int mBand;
+ private int mChannel;
+ private boolean mIsPowerCapAvailable = false;
+ private int mPowerCapDbm;
+
+ /**
+ * Constructor for a CoexUnsafeChannel with no power cap specified.
+ * @param band One of {@link WifiAnnotations.WifiBandBasic}
+ * @param channel Channel number
+ */
+ public CoexUnsafeChannel(@WifiAnnotations.WifiBandBasic int band, int channel) {
+ mBand = band;
+ mChannel = channel;
+ }
+
+ /**
+ * Constructor for a CoexUnsafeChannel with power cap specified.
+ * @param band One of {@link WifiAnnotations.WifiBandBasic}
+ * @param channel Channel number
+ * @param powerCapDbm Power cap in dBm
+ */
+ public CoexUnsafeChannel(@WifiAnnotations.WifiBandBasic int band, int channel,
+ int powerCapDbm) {
+ mBand = band;
+ mChannel = channel;
+ setPowerCapDbm(powerCapDbm);
+ }
+
+ /** Returns the Wi-Fi band of this channel as one of {@link WifiAnnotations.WifiBandBasic} */
+ public @WifiAnnotations.WifiBandBasic int getBand() {
+ return mBand;
+ }
+
+ /** Returns the channel number of this channel. */
+ public int getChannel() {
+ return mChannel;
+ }
+
+ /** Returns {@code true} if {@link #getPowerCapDbm()} is a valid value, else {@code false} */
+ public boolean isPowerCapAvailable() {
+ return mIsPowerCapAvailable;
+ }
+
+ /**
+ * Returns the power cap of this channel in dBm. Throws IllegalStateException if
+ * {@link #isPowerCapAvailable()} is {@code false}.
+ */
+ public int getPowerCapDbm() {
+ if (!mIsPowerCapAvailable) {
+ throw new IllegalStateException("getPowerCapDbm called but power cap is unavailable");
+ }
+ return mPowerCapDbm;
+ }
+
+ /** Set the power cap of this channel. */
+ public void setPowerCapDbm(int powerCapDbm) {
+ mIsPowerCapAvailable = true;
+ mPowerCapDbm = powerCapDbm;
+ }
+
+ @Override
+ public boolean equals(@Nullable Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ CoexUnsafeChannel that = (CoexUnsafeChannel) o;
+ return mBand == that.mBand
+ && mChannel == that.mChannel
+ && mIsPowerCapAvailable == that.mIsPowerCapAvailable
+ && mPowerCapDbm == that.mPowerCapDbm;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mBand, mChannel, mIsPowerCapAvailable, mPowerCapDbm);
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sj = new StringBuilder("CoexUnsafeChannel{");
+ sj.append(mChannel);
+ sj.append(", ");
+ if (mBand == WIFI_BAND_24_GHZ) {
+ sj.append("2.4GHz");
+ } else if (mBand == WIFI_BAND_5_GHZ) {
+ sj.append("5GHz");
+ } else if (mBand == WIFI_BAND_6_GHZ) {
+ sj.append("6GHz");
+ } else {
+ sj.append("UNKNOWN BAND");
+ }
+ if (mIsPowerCapAvailable) {
+ sj.append(", ").append(mPowerCapDbm).append("dBm");
+ }
+ sj.append('}');
+ return sj.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(mBand);
+ dest.writeInt(mChannel);
+ dest.writeBoolean(mIsPowerCapAvailable);
+ if (mIsPowerCapAvailable) {
+ dest.writeInt(mPowerCapDbm);
+ }
+ }
+
+ /** Implement the Parcelable interface */
+ public static final @NonNull Creator<CoexUnsafeChannel> CREATOR =
+ new Creator<CoexUnsafeChannel>() {
+ public CoexUnsafeChannel createFromParcel(Parcel in) {
+ final int band = in.readInt();
+ final int channel = in.readInt();
+ final boolean isPowerCapAvailable = in.readBoolean();
+ if (isPowerCapAvailable) {
+ final int powerCapDbm = in.readInt();
+ return new CoexUnsafeChannel(band, channel, powerCapDbm);
+ }
+ return new CoexUnsafeChannel(band, channel);
+ }
+
+ public CoexUnsafeChannel[] newArray(int size) {
+ return new CoexUnsafeChannel[size];
+ }
+ };
+}
diff --git a/wifi/java/android/net/wifi/EasyConnectStatusCallback.java b/wifi/java/android/net/wifi/EasyConnectStatusCallback.java
index 6c2e6ddf5dd2..ee7025594bc6 100644
--- a/wifi/java/android/net/wifi/EasyConnectStatusCallback.java
+++ b/wifi/java/android/net/wifi/EasyConnectStatusCallback.java
@@ -161,6 +161,11 @@ public abstract class EasyConnectStatusCallback {
*/
public static final int EASY_CONNECT_EVENT_FAILURE_ENROLLEE_REJECTED_CONFIGURATION = -12;
+ /**
+ * Easy Connect Failure event: System failed to generate DPP URI.
+ */
+ public static final int EASY_CONNECT_EVENT_FAILURE_URI_GENERATION = -13;
+
/** @hide */
@IntDef(prefix = {"EASY_CONNECT_EVENT_FAILURE_"}, value = {
EASY_CONNECT_EVENT_FAILURE_INVALID_URI,
@@ -175,6 +180,7 @@ public abstract class EasyConnectStatusCallback {
EASY_CONNECT_EVENT_FAILURE_CANNOT_FIND_NETWORK,
EASY_CONNECT_EVENT_FAILURE_ENROLLEE_AUTHENTICATION,
EASY_CONNECT_EVENT_FAILURE_ENROLLEE_REJECTED_CONFIGURATION,
+ EASY_CONNECT_EVENT_FAILURE_URI_GENERATION,
})
@Retention(RetentionPolicy.SOURCE)
public @interface EasyConnectFailureStatusCode {
@@ -264,4 +270,17 @@ public abstract class EasyConnectStatusCallback {
*/
@SystemApi
public abstract void onProgress(@EasyConnectProgressStatusCode int code);
+
+ /**
+ * Called when local Easy Connect Responder successfully generates a DPP URI from
+ * the supplicant. This callback is the first successful outcome
+ * of a Easy Connect Responder flow starting with
+ * {@link WifiManager#startEasyConnectAsEnrolleeResponder(String, int, Executor,
+ * EasyConnectStatusCallback)} .
+ *
+ * @param uri DPP URI from the supplicant.
+ * @hide
+ */
+ @SystemApi
+ public void onBootstrapUriGenerated(@NonNull String uri) {};
}
diff --git a/services/wifi/java/android/net/wifi/WifiApiServiceInfo.aidl b/wifi/java/android/net/wifi/ICoexCallback.aidl
index 45e4c69102f0..89e4c4b93013 100644
--- a/services/wifi/java/android/net/wifi/WifiApiServiceInfo.aidl
+++ b/wifi/java/android/net/wifi/ICoexCallback.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,8 +16,11 @@
package android.net.wifi;
-/** @hide */
-parcelable WifiApiServiceInfo {
- String name;
- IBinder binder;
+/**
+ * Interface for Wi-Fi/cellular coex callback.
+ * @hide
+ */
+oneway interface ICoexCallback
+{
+ void onCoexUnsafeChannelsChanged();
}
diff --git a/wifi/java/android/net/wifi/IDppCallback.aidl b/wifi/java/android/net/wifi/IDppCallback.aidl
index d7a958a5b4b1..dcbe8468de9e 100644
--- a/wifi/java/android/net/wifi/IDppCallback.aidl
+++ b/wifi/java/android/net/wifi/IDppCallback.aidl
@@ -45,4 +45,10 @@ oneway interface IDppCallback
* to show progress.
*/
void onProgress(int status);
+
+ /**
+ * Called when local DPP Responder successfully generates a URI.
+ */
+ void onBootstrapUriGenerated(String uri);
+
}
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index cc864eafcff1..6dee751f5894 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -24,7 +24,9 @@ import android.net.wifi.hotspot2.IProvisioningCallback;
import android.net.DhcpInfo;
import android.net.Network;
+import android.net.wifi.CoexUnsafeChannel;
import android.net.wifi.IActionListener;
+import android.net.wifi.ICoexCallback;
import android.net.wifi.IDppCallback;
import android.net.wifi.ILocalOnlyHotspotCallback;
import android.net.wifi.INetworkRequestMatchCallback;
@@ -144,6 +146,16 @@ interface IWifiManager
void updateInterfaceIpState(String ifaceName, int mode);
+ void setCoexUnsafeChannels(in List<CoexUnsafeChannel> unsafeChannels, int mandatoryRestrictions);
+
+ List<CoexUnsafeChannel> getCoexUnsafeChannels();
+
+ int getCoexRestrictions();
+
+ void registerCoexCallback(in ICoexCallback callback);
+
+ void unregisterCoexCallback(in ICoexCallback callback);
+
boolean startSoftAp(in WifiConfiguration wifiConfig, String packageName);
boolean startTetheredHotspot(in SoftApConfiguration softApConfig, String packageName);
@@ -235,6 +247,9 @@ interface IWifiManager
void startDppAsEnrolleeInitiator(in IBinder binder, in String configuratorUri,
in IDppCallback callback);
+ void startDppAsEnrolleeResponder(in IBinder binder, in String deviceInfo, int curve,
+ in IDppCallback callback);
+
void stopDppSession();
void updateWifiUsabilityScore(int seqNum, int score, int predictionHorizonSec);
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index da7c9c055d65..b8fa1e18ed28 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -72,6 +72,7 @@ import java.net.InetAddress;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@@ -3110,6 +3111,238 @@ public class WifiManager {
}
}
+ /* Wi-Fi/Cellular Coex */
+
+ /**
+ * Mandatory coex restriction flag for Wi-Fi Direct.
+ *
+ * @see #setCoexUnsafeChannels(Set, int)
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final int COEX_RESTRICTION_WIFI_DIRECT = 0x1 << 0;
+
+ /**
+ * Mandatory coex restriction flag for SoftAP
+ *
+ * @see #setCoexUnsafeChannels(Set, int)
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final int COEX_RESTRICTION_SOFTAP = 0x1 << 1;
+
+ /**
+ * Mandatory coex restriction flag for Wi-Fi Aware.
+ *
+ * @see #setCoexUnsafeChannels(Set, int)
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final int COEX_RESTRICTION_WIFI_AWARE = 0x1 << 2;
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(flag = true, prefix = {"COEX_RESTRICTION_"}, value = {
+ COEX_RESTRICTION_WIFI_DIRECT,
+ COEX_RESTRICTION_SOFTAP,
+ COEX_RESTRICTION_WIFI_AWARE
+ })
+ public @interface CoexRestriction {}
+
+ /**
+ * Specify the set of {@link CoexUnsafeChannel} to propagate through the framework for
+ * Wi-Fi/Cellular coex channel avoidance if the default algorithm is disabled via overlay
+ * (i.e. config_wifiCoexDefaultAlgorithmEnabled = false). Otherwise do nothing.
+ *
+ * @param unsafeChannels Set of {@link CoexUnsafeChannel} to avoid.
+ * @param restrictions Bitmap of {@link CoexRestriction} specifying the mandatory restricted
+ * uses of the specified channels. If any restrictions are set, then the
+ * supplied CoexUnsafeChannels will be completely avoided for the
+ * specified modes, rather than be avoided with best effort.
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.WIFI_UPDATE_COEX_UNSAFE_CHANNELS)
+ public void setCoexUnsafeChannels(@NonNull Set<CoexUnsafeChannel> unsafeChannels,
+ int restrictions) {
+ if (unsafeChannels == null) {
+ throw new IllegalArgumentException("unsafeChannels must not be null");
+ }
+ try {
+ mService.setCoexUnsafeChannels(new ArrayList<>(unsafeChannels), restrictions);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Returns the set of current {@link CoexUnsafeChannel} being used for Wi-Fi/Cellular coex
+ * channel avoidance.
+ *
+ * This returns the set calculated by the default algorithm if
+ * config_wifiCoexDefaultAlgorithmEnabled is {@code true}. Otherwise, returns the set supplied
+ * in {@link #setCoexUnsafeChannels(Set, int)}.
+ *
+ * If any {@link CoexRestriction} flags are set in {@link #getCoexRestrictions()}, then the
+ * CoexUnsafeChannels should be totally avoided (i.e. not best effort) for the Wi-Fi modes
+ * specified by the flags.
+ *
+ * @return Set of current CoexUnsafeChannels.
+ *
+ * @hide
+ */
+ @NonNull
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.WIFI_ACCESS_COEX_UNSAFE_CHANNELS)
+ public Set<CoexUnsafeChannel> getCoexUnsafeChannels() {
+ try {
+ return new HashSet<>(mService.getCoexUnsafeChannels());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Returns the current coex restrictions being used for Wi-Fi/Cellular coex
+ * channel avoidance.
+ *
+ * This returns the restrictions calculated by the default algorithm if
+ * config_wifiCoexDefaultAlgorithmEnabled is {@code true}. Otherwise, returns the value supplied
+ * in {@link #setCoexUnsafeChannels(Set, int)}.
+ *
+ * @return int containing a bitwise-OR combination of {@link CoexRestriction}.
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.WIFI_ACCESS_COEX_UNSAFE_CHANNELS)
+ public int getCoexRestrictions() {
+ try {
+ return mService.getCoexRestrictions();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Registers a CoexCallback to listen on the current CoexUnsafeChannels and restrictions being
+ * used for Wi-Fi/cellular coex channel avoidance.
+ * @param executor Executor to execute listener callback on
+ * @param callback CoexCallback to register
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.WIFI_ACCESS_COEX_UNSAFE_CHANNELS)
+ public void registerCoexCallback(
+ @NonNull @CallbackExecutor Executor executor, @NonNull CoexCallback callback) {
+ if (executor == null) throw new IllegalArgumentException("executor must not be null");
+ if (callback == null) throw new IllegalArgumentException("callback must not be null");
+ CoexCallback.CoexCallbackProxy proxy = callback.getProxy();
+ proxy.initProxy(executor, callback);
+ try {
+ mService.registerCoexCallback(proxy);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Unregisters a CoexCallback from listening on the current CoexUnsafeChannels and restrictions
+ * being used for Wi-Fi/cellular coex channel avoidance.
+ * @param callback CoexCallback to unregister
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.WIFI_ACCESS_COEX_UNSAFE_CHANNELS)
+ public void unregisterCoexCallback(@NonNull CoexCallback callback) {
+ if (callback == null) throw new IllegalArgumentException("callback must not be null");
+ CoexCallback.CoexCallbackProxy proxy = callback.getProxy();
+ try {
+ mService.unregisterCoexCallback(proxy);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ } finally {
+ proxy.cleanUpProxy();
+ }
+ }
+
+ /**
+ * Abstract callback class for applications to receive updates about current CoexUnsafeChannels
+ * for Wi-Fi/Cellular coex channel avoidance.
+ *
+ * @hide
+ */
+ @SystemApi
+ public abstract static class CoexCallback {
+ private final CoexCallbackProxy mCoexCallbackProxy;
+
+ public CoexCallback() {
+ mCoexCallbackProxy = new CoexCallbackProxy();
+ }
+
+ /*package*/ @NonNull
+ CoexCallbackProxy getProxy() {
+ return mCoexCallbackProxy;
+ }
+
+ /**
+ * Indicates that the current CoexUnsafeChannels or restrictions have changed.
+ * Clients should call {@link #getCoexUnsafeChannels()} and {@link #getCoexRestrictions()}
+ * to get the updated values.
+ */
+ public abstract void onCoexUnsafeChannelsChanged();
+
+ /**
+ * Callback proxy for CoexCallback objects.
+ */
+ private static class CoexCallbackProxy extends ICoexCallback.Stub {
+ private final Object mLock = new Object();
+ @Nullable @GuardedBy("mLock") private Executor mExecutor;
+ @Nullable @GuardedBy("mLock") private CoexCallback mCallback;
+
+ CoexCallbackProxy() {
+ mExecutor = null;
+ mCallback = null;
+ }
+
+ /*package*/ void initProxy(@NonNull Executor executor,
+ @NonNull CoexCallback callback) {
+ synchronized (mLock) {
+ mExecutor = executor;
+ mCallback = callback;
+ }
+ }
+
+ /*package*/ void cleanUpProxy() {
+ synchronized (mLock) {
+ mExecutor = null;
+ mCallback = null;
+ }
+ }
+
+ @Override
+ public void onCoexUnsafeChannelsChanged() {
+ Executor executor;
+ CoexCallback callback;
+ synchronized (mLock) {
+ executor = mExecutor;
+ callback = mCallback;
+ }
+ if (executor == null || callback == null) {
+ return;
+ }
+ Binder.clearCallingIdentity();
+ executor.execute(callback::onCoexUnsafeChannelsChanged);
+ }
+ }
+ }
+
/**
* Start Soft AP (hotspot) mode for tethering purposes with the specified configuration.
* Note that starting Soft AP mode may disable station mode operation if the device does not
@@ -5551,6 +5784,89 @@ public class WifiManager {
}
/**
+ * Easy Connect Device information maximum allowed length.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final int EASY_CONNECT_DEVICE_INFO_MAXIMUM_LENGTH = 40;
+
+ /**
+ * Easy Connect Cryptography Curve name: prime256v1
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final int EASY_CONNECT_CRYPTOGRAPHY_CURVE_PRIME256V1 = 0;
+
+ /**
+ * Easy Connect Cryptography Curve name: secp384r1
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final int EASY_CONNECT_CRYPTOGRAPHY_CURVE_SECP384R1 = 1;
+
+ /**
+ * Easy Connect Cryptography Curve name: secp521r1
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final int EASY_CONNECT_CRYPTOGRAPHY_CURVE_SECP521R1 = 2;
+
+
+ /**
+ * Easy Connect Cryptography Curve name: brainpoolP256r1
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final int EASY_CONNECT_CRYPTOGRAPHY_CURVE_BRAINPOOLP256R1 = 3;
+
+
+ /**
+ * Easy Connect Cryptography Curve name: brainpoolP384r1
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final int EASY_CONNECT_CRYPTOGRAPHY_CURVE_BRAINPOOLP384R1 = 4;
+
+
+ /**
+ * Easy Connect Cryptography Curve name: brainpoolP512r1
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final int EASY_CONNECT_CRYPTOGRAPHY_CURVE_BRAINPOOLP512R1 = 5;
+
+ /**
+ * Easy Connect Cryptography Curve name: default
+ * This allows framework to choose manadatory curve prime256v1.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final int EASY_CONNECT_CRYPTOGRAPHY_CURVE_DEFAULT =
+ EASY_CONNECT_CRYPTOGRAPHY_CURVE_PRIME256V1;
+
+ /** @hide */
+ @IntDef(prefix = {"EASY_CONNECT_CRYPTOGRAPHY_CURVE_"}, value = {
+ EASY_CONNECT_CRYPTOGRAPHY_CURVE_DEFAULT,
+ EASY_CONNECT_CRYPTOGRAPHY_CURVE_PRIME256V1,
+ EASY_CONNECT_CRYPTOGRAPHY_CURVE_SECP384R1,
+ EASY_CONNECT_CRYPTOGRAPHY_CURVE_SECP521R1,
+ EASY_CONNECT_CRYPTOGRAPHY_CURVE_BRAINPOOLP256R1,
+ EASY_CONNECT_CRYPTOGRAPHY_CURVE_BRAINPOOLP384R1,
+ EASY_CONNECT_CRYPTOGRAPHY_CURVE_BRAINPOOLP512R1,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface EasyConnectCryptographyCurve {
+ }
+
+ /**
* Start Easy Connect (DPP) in Configurator-Initiator role. The current device will initiate
* Easy Connect bootstrapping with a peer, and configure the peer with the SSID and password of
* the specified network using the Easy Connect protocol on an encrypted link.
@@ -5606,6 +5922,52 @@ public class WifiManager {
}
/**
+ * Start Easy Connect (DPP) in Enrollee-Responder role.
+ * The device will:
+ * 1. Generate a DPP bootstrap URI and return it using the
+ * {@link EasyConnectStatusCallback#onBootstrapUriGenerated(String)} method.
+ * 2. Start DPP as a Responder, waiting for an Initiator device to start the DPP
+ * authentication process.
+ * The caller should use the URI provided in step #1, for instance display it as a QR code
+ * or communicate it in some other way to the initiator device.
+ *
+ * @param deviceInfo Device specific information to add to the DPP URI. This field allows
+ * the users of the configurators to identify the device.
+ * Optional - if not provided or in case of an empty string,
+ * Info field (I:) will be skipped in the generated DPP URI.
+ * Allowed Range of ASCII characters in deviceInfo - %x20-7E.
+ * semicolon and space are not allowed.
+ * Due to the limitation of maximum allowed characters in QR code,
+ * framework limits to a max of
+ * {@link #EASY_CONNECT_DEVICE_INFO_MAXIMUM_LENGTH} characters in
+ * deviceInfo.
+ * Violation of these rules will result in an exception.
+ * @param curve Elliptic curve cryptography used to generate DPP
+ * public/private key pair. If application is not interested in a
+ * specific curve, choose default curve
+ * {@link #EASY_CONNECT_CRYPTOGRAPHY_CURVE_DEFAULT}.
+ * @param callback Callback for status updates
+ * @param executor The Executor on which to run the callback.
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.NETWORK_SETTINGS,
+ android.Manifest.permission.NETWORK_SETUP_WIZARD})
+ public void startEasyConnectAsEnrolleeResponder(@Nullable String deviceInfo,
+ @EasyConnectCryptographyCurve int curve,
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull EasyConnectStatusCallback callback) {
+ Binder binder = new Binder();
+ try {
+ mService.startDppAsEnrolleeResponder(binder, deviceInfo, curve,
+ new EasyConnectCallbackProxy(executor, callback));
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Stop or abort a current Easy Connect (DPP) session. This call, once processed, will
* terminate any ongoing transaction, and clean up all associated resources. Caller should not
* expect any callbacks once this call is made. However, due to the asynchronous nature of
@@ -5679,6 +6041,15 @@ public class WifiManager {
mEasyConnectStatusCallback.onProgress(status);
});
}
+
+ @Override
+ public void onBootstrapUriGenerated(String uri) {
+ Log.d(TAG, "Easy Connect onBootstrapUriGenerated callback");
+ Binder.clearCallingIdentity();
+ mExecutor.execute(() -> {
+ mEasyConnectStatusCallback.onBootstrapUriGenerated(uri);
+ });
+ }
}
/**
@@ -5853,7 +6224,6 @@ public class WifiManager {
executor.execute(callback::onScanResultsAvailable);
}
}
-
}
/**
diff --git a/wifi/tests/Android.bp b/wifi/tests/Android.bp
index 7272e146f4f8..7eba0a73be31 100644
--- a/wifi/tests/Android.bp
+++ b/wifi/tests/Android.bp
@@ -20,6 +20,9 @@ android_test {
defaults: ["framework-wifi-test-defaults"],
+ min_sdk_version: "30",
+ target_sdk_version: "30",
+
srcs: ["**/*.java"],
jacoco: {
diff --git a/wifi/tests/src/android/net/wifi/CoexUnsafeChannelTest.java b/wifi/tests/src/android/net/wifi/CoexUnsafeChannelTest.java
new file mode 100644
index 000000000000..320f25e715fe
--- /dev/null
+++ b/wifi/tests/src/android/net/wifi/CoexUnsafeChannelTest.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 static android.net.wifi.WifiScanner.WIFI_BAND_24_GHZ;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.os.Parcel;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+
+/**
+ * Unit tests for {@link android.net.wifi.CoexUnsafeChannel}.
+ */
+@SmallTest
+public class CoexUnsafeChannelTest {
+ /**
+ * Verifies {@link CoexUnsafeChannel#isPowerCapAvailable()} returns false if no cap is set.
+ */
+ @Test
+ public void testIsPowerCapAvailable_noPowerCap_returnsFalse() {
+ CoexUnsafeChannel unsafeChannel = new CoexUnsafeChannel(WIFI_BAND_24_GHZ, 6);
+
+ assertThat(unsafeChannel.isPowerCapAvailable()).isFalse();
+ }
+
+ /**
+ * Verifies {@link CoexUnsafeChannel#isPowerCapAvailable()} returns true if a cap is set, and
+ * {@link CoexUnsafeChannel#getPowerCapDbm()} returns the set value.
+ */
+ @Test
+ public void testIsPowerCapAvailable_powerCapSet_returnsTrue() {
+ final int powerCapDbm = -50;
+ CoexUnsafeChannel unsafeChannel = new CoexUnsafeChannel(WIFI_BAND_24_GHZ, 6);
+
+ unsafeChannel.setPowerCapDbm(powerCapDbm);
+
+ assertThat(unsafeChannel.isPowerCapAvailable()).isTrue();
+ assertThat(unsafeChannel.getPowerCapDbm()).isEqualTo(powerCapDbm);
+ }
+
+ /**
+ * Verifies {@link CoexUnsafeChannel#getPowerCapDbm()} throws an IllegalStateException if
+ * {@link CoexUnsafeChannel#isPowerCapAvailable()} is {@code false}.
+ */
+ @Test(expected = IllegalStateException.class)
+ public void testGetPowerCap_powerCapUnavailable_throwsException() {
+ CoexUnsafeChannel unsafeChannel = new CoexUnsafeChannel(WIFI_BAND_24_GHZ, 6);
+
+ unsafeChannel.getPowerCapDbm();
+ }
+
+ /**
+ * Verify parcel read/write for CoexUnsafeChannel with or without power cap.
+ */
+ @Test
+ public void testParcelReadWrite_withOrWithoutCap_readEqualsWritten() throws Exception {
+ CoexUnsafeChannel writeUnsafeChannelNoCap =
+ new CoexUnsafeChannel(WIFI_BAND_24_GHZ, 6);
+ CoexUnsafeChannel writeUnsafeChannelCapped =
+ new CoexUnsafeChannel(WIFI_BAND_24_GHZ, 6, -50);
+
+ CoexUnsafeChannel readUnsafeChannelNoCap = parcelReadWrite(writeUnsafeChannelNoCap);
+ CoexUnsafeChannel readUnsafeChannelCapped = parcelReadWrite(writeUnsafeChannelCapped);
+
+ assertThat(writeUnsafeChannelNoCap).isEqualTo(readUnsafeChannelNoCap);
+ assertThat(writeUnsafeChannelCapped).isEqualTo(readUnsafeChannelCapped);
+ }
+
+ /**
+ * Write the provided {@link CoexUnsafeChannel} to a parcel and deserialize it.
+ */
+ private static CoexUnsafeChannel parcelReadWrite(CoexUnsafeChannel writeResult)
+ throws Exception {
+ Parcel parcel = Parcel.obtain();
+ writeResult.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0); // Rewind data position back to the beginning for read.
+ return CoexUnsafeChannel.CREATOR.createFromParcel(parcel);
+ }
+}
diff --git a/wifi/tests/src/android/net/wifi/EasyConnectStatusCallbackTest.java b/wifi/tests/src/android/net/wifi/EasyConnectStatusCallbackTest.java
index b10141434b0b..cf37b78b889a 100644
--- a/wifi/tests/src/android/net/wifi/EasyConnectStatusCallbackTest.java
+++ b/wifi/tests/src/android/net/wifi/EasyConnectStatusCallbackTest.java
@@ -19,6 +19,7 @@ package android.net.wifi;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
+import android.annotation.NonNull;
import android.util.SparseArray;
import androidx.test.filters.SmallTest;
@@ -52,6 +53,11 @@ public class EasyConnectStatusCallbackTest {
mOnFailureR1EventReceived = true;
mLastCode = code;
}
+
+ @Override
+ public void onBootstrapUriGenerated(@NonNull String uri) {
+
+ }
};
private boolean mOnFailureR1EventReceived;
private int mLastCode;
diff --git a/wifi/tests/src/android/net/wifi/WifiManagerTest.java b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
index aefebbcec607..39f6f57b05b3 100644
--- a/wifi/tests/src/android/net/wifi/WifiManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
@@ -19,6 +19,9 @@ package android.net.wifi;
import static android.net.wifi.WifiConfiguration.METERED_OVERRIDE_METERED;
import static android.net.wifi.WifiManager.ActionListener;
import static android.net.wifi.WifiManager.BUSY;
+import static android.net.wifi.WifiManager.COEX_RESTRICTION_SOFTAP;
+import static android.net.wifi.WifiManager.COEX_RESTRICTION_WIFI_AWARE;
+import static android.net.wifi.WifiManager.COEX_RESTRICTION_WIFI_DIRECT;
import static android.net.wifi.WifiManager.ERROR;
import static android.net.wifi.WifiManager.LocalOnlyHotspotCallback.ERROR_GENERIC;
import static android.net.wifi.WifiManager.LocalOnlyHotspotCallback.ERROR_INCOMPATIBLE_MODE;
@@ -43,6 +46,7 @@ import static android.net.wifi.WifiManager.WIFI_FEATURE_SCANNER;
import static android.net.wifi.WifiManager.WIFI_FEATURE_WPA3_SAE;
import static android.net.wifi.WifiManager.WIFI_FEATURE_WPA3_SUITE_B;
import static android.net.wifi.WifiManager.WpsCallback;
+import static android.net.wifi.WifiScanner.WIFI_BAND_24_GHZ;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
@@ -74,6 +78,7 @@ import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.net.DhcpInfo;
import android.net.MacAddress;
+import android.net.wifi.WifiManager.CoexCallback;
import android.net.wifi.WifiManager.LocalOnlyHotspotCallback;
import android.net.wifi.WifiManager.LocalOnlyHotspotObserver;
import android.net.wifi.WifiManager.LocalOnlyHotspotReservation;
@@ -108,9 +113,11 @@ import org.mockito.MockitoAnnotations;
import java.util.ArrayList;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
+import java.util.Set;
import java.util.concurrent.Executor;
/**
@@ -151,6 +158,7 @@ public class WifiManagerTest {
private WifiManager mWifiManager;
private WifiNetworkSuggestion mWifiNetworkSuggestion;
private ScanResultsCallback mScanResultsCallback;
+ private CoexCallback mCoexCallback;
private WifiActivityEnergyInfo mWifiActivityEnergyInfo;
/**
@@ -214,10 +222,149 @@ public class WifiManagerTest {
mRunnable.run();
}
};
+ mCoexCallback = new CoexCallback() {
+ @Override
+ public void onCoexUnsafeChannelsChanged() {
+ mRunnable.run();
+ }
+ };
mWifiActivityEnergyInfo = new WifiActivityEnergyInfo(0, 0, 0, 0, 0, 0);
}
/**
+ * Check the call to setCoexUnsafeChannels calls WifiServiceImpl to setCoexUnsafeChannels with
+ * the provided CoexUnsafeChannels and restrictions bitmask.
+ */
+ @Test
+ public void testSetCoexUnsafeChannelsGoesToWifiServiceImpl() throws Exception {
+ Set<CoexUnsafeChannel> unsafeChannels = new HashSet<>();
+ int restrictions = COEX_RESTRICTION_WIFI_DIRECT | COEX_RESTRICTION_SOFTAP
+ | COEX_RESTRICTION_WIFI_AWARE;
+
+ mWifiManager.setCoexUnsafeChannels(unsafeChannels, restrictions);
+
+ verify(mWifiService).setCoexUnsafeChannels(new ArrayList<>(unsafeChannels), restrictions);
+ }
+
+ /**
+ * Verify an IllegalArgumentException if passed a null value for unsafeChannels.
+ */
+ @Test
+ public void testSetCoexUnsafeChannelsThrowsIllegalArgumentExceptionOnNullUnsafeChannels() {
+ try {
+ mWifiManager.setCoexUnsafeChannels(null, 0);
+ fail("expected IllegalArgumentException");
+ } catch (IllegalArgumentException expected) {
+ }
+ }
+
+ /**
+ * Check the call to getCoexUnsafeChannels calls WifiServiceImpl to return the values from
+ * getCoexUnsafeChannels.
+ */
+ @Test
+ public void testGetCoexUnsafeChannelsGoesToWifiServiceImpl() throws Exception {
+ Set<CoexUnsafeChannel> unsafeChannels = new HashSet<>();
+ unsafeChannels.add(new CoexUnsafeChannel(WIFI_BAND_24_GHZ, 6));
+ when(mWifiService.getCoexUnsafeChannels()).thenReturn(new ArrayList<>(unsafeChannels));
+
+ assertEquals(mWifiManager.getCoexUnsafeChannels(), unsafeChannels);
+ }
+
+ /**
+ * Verify call to getCoexRestrictions calls WifiServiceImpl to return the value from
+ * getCoexRestrictions.
+ */
+ @Test
+ public void testGetCoexRestrictionsGoesToWifiServiceImpl() throws Exception {
+ int restrictions = COEX_RESTRICTION_WIFI_DIRECT | COEX_RESTRICTION_SOFTAP
+ | COEX_RESTRICTION_WIFI_AWARE;
+ when(mWifiService.getCoexRestrictions()).thenReturn(restrictions);
+
+ assertEquals(mWifiService.getCoexRestrictions(), restrictions);
+ }
+
+
+ /**
+ * Verify an IllegalArgumentException is thrown if callback is not provided.
+ */
+ @Test(expected = IllegalArgumentException.class)
+ public void testRegisterCoexCallbackWithNullCallback() throws Exception {
+ mWifiManager.registerCoexCallback(mExecutor, null);
+ }
+
+ /**
+ * Verify an IllegalArgumentException is thrown if executor is not provided.
+ */
+ @Test(expected = IllegalArgumentException.class)
+ public void testRegisterCoexCallbackWithNullExecutor() throws Exception {
+ mWifiManager.registerCoexCallback(null, mCoexCallback);
+ }
+
+ /**
+ * Verify client provided callback is being called to the right callback.
+ */
+ @Test
+ public void testAddCoexCallbackAndReceiveEvent() throws Exception {
+ ArgumentCaptor<ICoexCallback.Stub> callbackCaptor =
+ ArgumentCaptor.forClass(ICoexCallback.Stub.class);
+ mWifiManager.registerCoexCallback(new SynchronousExecutor(), mCoexCallback);
+ verify(mWifiService).registerCoexCallback(callbackCaptor.capture());
+ callbackCaptor.getValue().onCoexUnsafeChannelsChanged();
+ verify(mRunnable).run();
+ }
+
+ /**
+ * Verify client provided callback is being called to the right executor.
+ */
+ @Test
+ public void testRegisterCoexCallbackWithTheTargetExecutor() throws Exception {
+ ArgumentCaptor<ICoexCallback.Stub> callbackCaptor =
+ ArgumentCaptor.forClass(ICoexCallback.Stub.class);
+ mWifiManager.registerCoexCallback(mExecutor, mCoexCallback);
+ verify(mWifiService).registerCoexCallback(callbackCaptor.capture());
+ mWifiManager.registerCoexCallback(mAnotherExecutor, mCoexCallback);
+ callbackCaptor.getValue().onCoexUnsafeChannelsChanged();
+ verify(mExecutor, never()).execute(any(Runnable.class));
+ verify(mAnotherExecutor).execute(any(Runnable.class));
+ }
+
+ /**
+ * Verify client register unregister then register again, to ensure callback still works.
+ */
+ @Test
+ public void testRegisterUnregisterThenRegisterAgainWithCoexCallback() throws Exception {
+ ArgumentCaptor<ICoexCallback.Stub> callbackCaptor =
+ ArgumentCaptor.forClass(ICoexCallback.Stub.class);
+ mWifiManager.registerCoexCallback(new SynchronousExecutor(), mCoexCallback);
+ verify(mWifiService).registerCoexCallback(callbackCaptor.capture());
+ mWifiManager.unregisterCoexCallback(mCoexCallback);
+ callbackCaptor.getValue().onCoexUnsafeChannelsChanged();
+ verify(mRunnable, never()).run();
+ mWifiManager.registerCoexCallback(new SynchronousExecutor(), mCoexCallback);
+ callbackCaptor.getValue().onCoexUnsafeChannelsChanged();
+ verify(mRunnable).run();
+ }
+
+ /**
+ * Verify client unregisterCoexCallback.
+ */
+ @Test
+ public void testUnregisterCoexCallback() throws Exception {
+ mWifiManager.unregisterCoexCallback(mCoexCallback);
+ verify(mWifiService).unregisterCoexCallback(any());
+ }
+
+ /**
+ * Verify client unregisterCoexCallback with null callback will cause an exception.
+ */
+ @Test(expected = IllegalArgumentException.class)
+ public void testUnregisterCoexCallbackWithNullCallback() throws Exception {
+ mWifiManager.unregisterCoexCallback(null);
+ }
+
+
+ /**
* Check the call to startSoftAp calls WifiService to startSoftAp with the provided
* WifiConfiguration. Verify that the return value is propagated to the caller.
*/