From 12bb6d3cbf05cea529a165917c7430af607056f2 Mon Sep 17 00:00:00 2001 From: Haamed Gheibi Date: Wed, 9 Mar 2022 12:05:14 -0800 Subject: Merge SP2A.220305.013 Bug: 220074017 Change-Id: Idfdd94e902f656ac65a2a75dfdd199f6f85ba472 --- Android.bp | 3 + apct-tests/perftests/autofill/AndroidManifest.xml | 10 + .../src/android/wm/RecentsAnimationPerfTest.java | 7 +- .../src/android/wm/WindowAddRemovePerfTest.java | 5 +- .../app/appsearch/AppSearchBatchResult.java | 11 + .../app/appsearch/util/SchemaMigrationUtil.java | 2 +- .../server/appsearch/AppSearchManagerService.java | 358 ++- .../external/localstorage/AppSearchImpl.java | 45 +- .../external/localstorage/AppSearchLogger.java | 4 + .../localstorage/AppSearchLoggerHelper.java | 44 + .../external/localstorage/stats/SearchStats.java | 2 + .../localstorage/stats/SetSchemaStats.java | 17 - .../server/appsearch/stats/PlatformLogger.java | 6 + .../visibilitystore/VisibilityStoreImpl.java | 3 +- apex/appsearch/synced_jetpack_changeid.txt | 2 +- apex/appsearch/testing/Android.bp | 1 + .../testing/external/AppSearchTestUtils.java | 56 + core/api/current.txt | 102 +- core/api/system-current.txt | 51 + core/api/test-current.txt | 106 +- .../accessibilityservice/AccessibilityService.java | 111 +- .../accessibilityservice/AccessibilityTrace.java | 216 ++ .../IAccessibilityServiceConnection.aidl | 4 +- core/java/android/app/Activity.java | 42 +- core/java/android/app/ActivityClient.java | 14 + core/java/android/app/ActivityManager.java | 79 + core/java/android/app/ActivityManagerInternal.java | 32 + core/java/android/app/ActivityOptions.java | 48 +- core/java/android/app/ActivityTaskManager.java | 13 + core/java/android/app/ActivityThread.java | 309 ++- core/java/android/app/ActivityThreadInternal.java | 6 +- .../android/app/ActivityTransitionCoordinator.java | 1 + core/java/android/app/Application.java | 17 + .../java/android/app/ClientTransactionHandler.java | 7 +- core/java/android/app/ConfigurationController.java | 48 +- core/java/android/app/ContextImpl.java | 29 +- core/java/android/app/Dialog.java | 23 + core/java/android/app/DirectAction.java | 3 +- .../java/android/app/DisabledWallpaperManager.java | 31 +- ...oregroundServiceDidNotStartInTimeException.java | 33 - .../android/app/IActivityClientController.aidl | 1 + core/java/android/app/IActivityManager.aidl | 7 +- core/java/android/app/IActivityTaskManager.aidl | 14 + core/java/android/app/IApplicationThread.aidl | 2 +- core/java/android/app/Instrumentation.java | 42 +- core/java/android/app/LoadedApk.java | 34 + core/java/android/app/Notification.java | 27 +- core/java/android/app/RemoteServiceException.java | 124 +- core/java/android/app/ResourcesManager.java | 2 +- core/java/android/app/Service.java | 35 + .../app/ServiceStartNotAllowedException.java | 7 + core/java/android/app/StackTrace.java | 27 + core/java/android/app/StatusBarManager.java | 3 +- core/java/android/app/TaskInfo.java | 42 +- core/java/android/app/WallpaperInfo.java | 28 + core/java/android/app/WallpaperManager.java | 110 +- .../android/app/admin/DevicePolicyManager.java | 173 +- .../app/admin/EnterprisePlatformSecurity_OWNERS | 4 + .../android/app/admin/EnterprisePlatform_OWNERS | 2 + .../android/app/admin/IDevicePolicyManager.aidl | 5 +- core/java/android/app/admin/OWNERS | 10 +- .../android/app/admin/WorkDeviceExperience_OWNERS | 5 + core/java/android/app/compat/PackageOverride.java | 17 + .../app/servertransaction/ActivityResultItem.java | 19 +- .../servertransaction/ActivityTransactionItem.java | 31 +- .../TransferSplashScreenViewStateItem.java | 38 +- core/java/android/appwidget/AppWidgetHostView.java | 32 +- .../android/companion/CompanionDeviceManager.java | 3 +- .../ICompanionDeviceDiscoveryService.aidl | 2 + core/java/android/content/ClipDescription.java | 10 + core/java/android/content/Context.java | 6 +- core/java/android/content/pm/ActivityInfo.java | 93 +- .../content/pm/ConstrainDisplayApisConfig.java | 164 +- core/java/android/content/pm/PackageManager.java | 21 + .../hardware/biometrics/BiometricConstants.java | 6 + .../biometrics/BiometricFaceConstants.java | 2 +- .../biometrics/BiometricOverlayConstants.java | 53 + .../hardware/biometrics/BiometricPrompt.java | 13 + .../android/hardware/biometrics/PromptInfo.java | 11 + .../biometrics/SensorLocationInternal.aidl | 19 + .../biometrics/SensorLocationInternal.java | 112 + .../hardware/camera2/CameraCharacteristics.java | 127 +- .../android/hardware/camera2/CameraManager.java | 95 +- .../hardware/camera2/impl/CameraDeviceImpl.java | 28 +- .../camera2/impl/CameraMetadataNative.java | 25 +- .../params/DeviceStateSensorOrientationMap.java | 156 ++ .../hardware/devicestate/DeviceStateManager.java | 24 +- .../devicestate/DeviceStateManagerGlobal.java | 6 +- .../display/AmbientDisplayConfiguration.java | 30 +- .../android/hardware/display/DisplayManager.java | 39 +- .../hardware/display/DisplayManagerGlobal.java | 32 +- .../hardware/display/DisplayManagerInternal.java | 23 + .../android/hardware/display/IDisplayManager.aidl | 10 + .../android/hardware/display/VirtualDisplay.java | 10 +- .../hardware/display/VirtualDisplayConfig.java | 56 +- .../hardware/fingerprint/FingerprintManager.java | 11 +- .../FingerprintSensorPropertiesInternal.java | 83 +- .../hardware/fingerprint/IFingerprintService.aidl | 3 +- .../hardware/fingerprint/ISidefpsController.aidl | 6 +- .../fingerprint/IUdfpsOverlayController.aidl | 9 +- .../AbstractInputMethodService.java | 50 +- .../inputmethodservice/IInputMethodWrapper.java | 11 +- .../inputmethodservice/InputMethodService.java | 44 +- core/java/android/net/NetworkTemplate.java | 52 +- core/java/android/os/AppZygote.java | 8 +- core/java/android/os/BatteryStats.java | 97 + core/java/android/os/Build.java | 11 +- core/java/android/os/Environment.java | 16 +- core/java/android/os/PowerManager.java | 8 + core/java/android/os/SharedMemory.java | 11 +- core/java/android/os/TEST_MAPPING | 9 + .../java/android/permission/PermissionManager.java | 31 +- .../android/permission/PermissionUsageHelper.java | 113 +- core/java/android/provider/DeviceConfig.java | 8 + core/java/android/provider/Settings.java | 178 +- core/java/android/provider/Telephony.java | 9 + .../notification/NotificationListenerService.java | 27 +- .../service/voice/IVoiceInteractionSession.aidl | 2 + .../android/service/voice/VisibleActivityInfo.aidl | 19 + .../android/service/voice/VisibleActivityInfo.java | 205 ++ .../voice/VoiceInteractionManagerInternal.java | 1 - .../service/voice/VoiceInteractionSession.java | 182 +- .../service/wallpaper/EngineWindowPage.java | 6 - .../service/wallpaper/WallpaperService.java | 378 +-- core/java/android/text/style/StyleSpan.java | 48 +- core/java/android/util/ArrayMap.java | 2 +- core/java/android/util/DisplayUtils.java | 54 + core/java/android/util/FeatureFlagUtils.java | 11 + core/java/android/util/MathUtils.java | 4 + .../util/imetracing/ImeTracingServerImpl.java | 6 +- core/java/android/view/AttachedSurfaceControl.java | 71 + .../android/view/BatchedInputEventReceiver.java | 16 +- core/java/android/view/DisplayCutout.java | 124 +- .../java/android/view/IRecentsAnimationRunner.aidl | 16 +- core/java/android/view/IWindowManager.aidl | 37 +- core/java/android/view/IWindowSession.aidl | 15 +- .../java/android/view/ImeInsetsSourceConsumer.java | 5 + core/java/android/view/InputWindowHandle.java | 36 +- .../view/InsetsAnimationControlCallbacks.java | 10 +- .../android/view/InsetsAnimationControlImpl.java | 11 +- .../view/InsetsAnimationThreadControlRunner.java | 4 +- core/java/android/view/InsetsController.java | 139 +- .../android/view/InsetsResizeAnimationRunner.java | 238 ++ core/java/android/view/InsetsSourceControl.java | 9 + core/java/android/view/InsetsState.java | 19 +- core/java/android/view/InsetsVisibilities.aidl | 19 + core/java/android/view/InsetsVisibilities.java | 134 + .../view/InternalInsetsAnimationController.java | 41 + core/java/android/view/MotionEvent.java | 32 +- core/java/android/view/RemoteAnimationAdapter.java | 22 + core/java/android/view/RemoteAnimationTarget.java | 35 +- core/java/android/view/RoundedCorners.java | 174 +- core/java/android/view/Surface.java | 15 + core/java/android/view/SurfaceControl.java | 142 +- core/java/android/view/SurfaceControlViewHost.java | 13 +- core/java/android/view/SurfaceView.java | 247 +- core/java/android/view/TaskTransitionSpec.aidl | 20 + core/java/android/view/TaskTransitionSpec.java | 92 + core/java/android/view/View.java | 151 +- core/java/android/view/ViewConfiguration.java | 5 +- core/java/android/view/ViewParent.java | 3 + core/java/android/view/ViewRootImpl.java | 328 ++- .../android/view/ViewRootInsetsControllerHost.java | 4 +- core/java/android/view/WindowInfo.java | 7 + core/java/android/view/WindowManager.java | 174 +- core/java/android/view/WindowManagerGlobal.java | 11 + core/java/android/view/WindowManagerImpl.java | 34 + .../android/view/WindowManagerPolicyConstants.java | 40 + .../java/android/view/WindowlessWindowManager.java | 13 +- .../view/accessibility/AccessibilityEvent.java | 39 +- .../AccessibilityInteractionClient.java | 202 +- .../view/accessibility/AccessibilityManager.java | 65 +- .../view/accessibility/AccessibilityNodeInfo.java | 49 + .../accessibility/AccessibilityWindowInfo.java | 29 + .../view/contentcapture/ContentCaptureContext.java | 27 +- .../view/contentcapture/ContentCaptureEvent.java | 42 +- .../view/contentcapture/ContentCaptureManager.java | 2 + .../contentcapture/MainContentCaptureSession.java | 10 + .../java/android/view/inputmethod/InputMethod.java | 15 +- .../view/inputmethod/InputMethodManager.java | 1 + .../view/translation/UiTranslationController.java | 32 +- core/java/android/widget/AbsListView.java | 62 +- core/java/android/widget/RemoteViews.java | 476 +++- core/java/android/widget/RemoteViewsAdapter.java | 2 +- .../widget/TextViewTranslationCallback.java | 11 + core/java/android/window/ConfigurationHelper.java | 132 + core/java/android/window/DisplayAreaInfo.java | 13 + core/java/android/window/DisplayAreaOrganizer.java | 11 +- .../window/IRemoteTransitionFinishedCallback.aidl | 6 +- .../android/window/ITaskFragmentOrganizer.aidl | 51 + .../window/ITaskFragmentOrganizerController.aidl | 53 + core/java/android/window/ITaskOrganizer.aidl | 8 +- .../android/window/ITransitionMetricsReporter.aidl | 33 + .../android/window/IWindowOrganizerController.aidl | 20 + .../window/PictureInPictureSurfaceTransaction.java | 118 +- core/java/android/window/RemoteTransition.aidl | 19 + core/java/android/window/RemoteTransition.java | 196 ++ .../android/window/SizeConfigurationBuckets.java | 156 +- core/java/android/window/SplashScreen.java | 14 +- core/java/android/window/SplashScreenView.java | 93 +- core/java/android/window/StartingWindowInfo.java | 17 +- .../android/window/StartingWindowRemovalInfo.aidl | 20 + .../android/window/StartingWindowRemovalInfo.java | 111 + .../android/window/TaskFragmentCreationParams.aidl | 23 + .../android/window/TaskFragmentCreationParams.java | 193 ++ core/java/android/window/TaskFragmentInfo.aidl | 23 + core/java/android/window/TaskFragmentInfo.java | 227 ++ .../java/android/window/TaskFragmentOrganizer.java | 232 ++ .../android/window/TaskFragmentOrganizerToken.java | 97 + core/java/android/window/TaskOrganizer.java | 19 +- core/java/android/window/TaskSnapshot.java | 27 +- core/java/android/window/TransitionFilter.java | 119 +- core/java/android/window/TransitionInfo.java | 250 +- core/java/android/window/TransitionMetrics.java | 57 + .../java/android/window/TransitionRequestInfo.java | 20 +- .../android/window/WindowContainerTransaction.java | 623 ++++- core/java/android/window/WindowContext.java | 51 +- core/java/android/window/WindowInfosListener.java | 63 + core/java/android/window/WindowOrganizer.java | 55 +- core/java/android/window/WindowProvider.java | 39 + .../java/android/window/WindowProviderService.java | 88 +- core/java/android/window/WindowTokenClient.java | 101 +- .../AccessibilityShortcutChooserActivity.java | 18 + .../util/AccessibilityStatsLogUtils.java | 20 +- .../com/android/internal/app/ChooserActivity.java | 45 +- .../app/IVoiceInteractionManagerService.aidl | 10 + .../internal/app/LocalePickerWithRegion.java | 8 + .../internal/inputmethod/InputMethodDebug.java | 2 + .../inputmethod/SoftInputShowHideReason.java | 10 +- .../com/android/internal/jank/FrameTracker.java | 379 +-- .../internal/jank/InteractionJankMonitor.java | 338 ++- ...ficationAccessConfirmationActivityContract.java | 18 +- .../internal/os/AmbientDisplayPowerCalculator.java | 43 +- .../com/android/internal/os/BatteryStatsImpl.java | 463 +++- .../com/android/internal/os/PowerCalculator.java | 26 - .../java/com/android/internal/os/PowerProfile.java | 122 + .../android/internal/os/ScreenPowerCalculator.java | 53 +- core/java/com/android/internal/os/ZygoteInit.java | 2 +- .../com/android/internal/policy/DecorView.java | 22 +- .../internal/policy/IKeyguardStateCallback.aidl | 1 - .../internal/policy/ScreenDecorationsUtils.java | 23 +- .../android/internal/policy/SystemBarUtils.java | 94 + .../internal/policy/TransitionAnimation.java | 273 +- .../android/internal/protolog/ProtoLogGroup.java | 5 + .../android/internal/protolog/ProtoLogImpl.java | 2 +- .../com/android/internal/statusbar/IStatusBar.aidl | 12 +- .../statusbar/RegisterStatusBarResult.java | 20 +- .../com/android/internal/util/LatencyTracker.java | 166 +- .../com/android/internal/view/IInputMethod.aidl | 2 +- .../internal/view/ScrollCaptureInternal.java | 38 +- .../internal/view/WebViewCaptureHelper.java | 100 + .../internal/widget/PointerLocationView.java | 153 +- core/jni/Android.bp | 6 + core/jni/AndroidRuntime.cpp | 3 + core/jni/OWNERS | 1 + core/jni/android_graphics_BLASTBufferQueue.cpp | 43 +- ...droid_hardware_input_InputApplicationHandle.cpp | 19 + ...android_hardware_input_InputApplicationHandle.h | 5 +- .../android_hardware_input_InputWindowHandle.cpp | 128 +- .../jni/android_hardware_input_InputWindowHandle.h | 8 +- core/jni/android_media_AudioDeviceAttributes.cpp | 27 +- core/jni/android_media_AudioDeviceAttributes.h | 3 + core/jni/android_media_AudioSystem.cpp | 89 +- core/jni/android_os_Debug.cpp | 22 + core/jni/android_util_AssetManager.cpp | 4 + core/jni/android_view_InputEventSender.cpp | 1 + core/jni/android_view_MotionEvent.cpp | 25 +- core/jni/android_view_SurfaceControl.cpp | 46 +- core/jni/android_window_WindowInfosListener.cpp | 134 + core/proto/android/providers/settings/secure.proto | 2 +- core/proto/android/server/accessibilitytrace.proto | 18 +- .../android/server/windowmanagerservice.proto | 31 +- core/proto/android/view/surfacecontrol.proto | 1 + core/res/AndroidManifest.xml | 24 +- core/res/OWNERS | 6 + core/res/res/anim/task_fragment_close_enter.xml | 32 + core/res/res/anim/task_fragment_close_exit.xml | 42 + core/res/res/anim/task_fragment_open_enter.xml | 41 + core/res/res/anim/task_fragment_open_exit.xml | 32 + core/res/res/drawable-nodpi/default_wallpaper.png | Bin 489912 -> 738385 bytes .../drawable-sw600dp-nodpi/default_wallpaper.png | Bin 1197339 -> 2774036 bytes .../drawable-sw720dp-nodpi/default_wallpaper.png | Bin 1930496 -> 4958722 bytes core/res/res/drawable/ic_corp_badge.xml | 5 +- core/res/res/drawable/ic_corp_badge_case.xml | 6 +- .../res/drawable/ic_corp_badge_no_background.xml | 2 +- core/res/res/drawable/ic_corp_icon.xml | 2 +- core/res/res/drawable/ic_corp_icon_badge_case.xml | 12 +- core/res/res/drawable/ic_corp_statusbar_icon.xml | 2 +- core/res/res/drawable/ic_corp_user_badge.xml | 3 - core/res/res/layout-car/car_alert_dialog.xml | 2 +- .../res/layout-car/car_alert_dialog_button_bar.xml | 9 + .../layout/accessibility_shortcut_chooser_item.xml | 17 +- core/res/res/layout/alert_dialog.xml | 6 +- core/res/res/layout/chooser_grid.xml | 2 + core/res/res/layout/chooser_grid_preview_image.xml | 4 +- core/res/res/layout/splash_screen_view.xml | 1 + core/res/res/layout/transient_notification.xml | 1 - core/res/res/values-af/strings.xml | 10 +- core/res/res/values-am/strings.xml | 10 +- core/res/res/values-ar/strings.xml | 38 +- core/res/res/values-as/strings.xml | 110 +- core/res/res/values-az/strings.xml | 10 +- core/res/res/values-b+sr+Latn/strings.xml | 12 +- core/res/res/values-be/strings.xml | 18 +- core/res/res/values-bg/strings.xml | 10 +- core/res/res/values-bn/strings.xml | 10 +- core/res/res/values-bs/strings.xml | 28 +- core/res/res/values-ca/strings.xml | 10 +- core/res/res/values-cs/strings.xml | 12 +- core/res/res/values-da/strings.xml | 10 +- core/res/res/values-de/strings.xml | 10 +- core/res/res/values-el/strings.xml | 10 +- core/res/res/values-en-rAU/strings.xml | 10 +- core/res/res/values-en-rCA/strings.xml | 10 +- core/res/res/values-en-rGB/strings.xml | 10 +- core/res/res/values-en-rIN/strings.xml | 10 +- core/res/res/values-en-rXC/strings.xml | 10 +- core/res/res/values-es-rUS/strings.xml | 26 +- core/res/res/values-es/strings.xml | 10 +- core/res/res/values-et/strings.xml | 10 +- core/res/res/values-eu/strings.xml | 32 +- core/res/res/values-fa/strings.xml | 12 +- core/res/res/values-fi/strings.xml | 10 +- core/res/res/values-fr-rCA/strings.xml | 20 +- core/res/res/values-fr/strings.xml | 10 +- core/res/res/values-gl/strings.xml | 10 +- core/res/res/values-gu/strings.xml | 10 +- core/res/res/values-hi/strings.xml | 20 +- core/res/res/values-hr/strings.xml | 12 +- core/res/res/values-hu/strings.xml | 10 +- core/res/res/values-hy/strings.xml | 10 +- core/res/res/values-in/strings.xml | 16 +- core/res/res/values-is/strings.xml | 10 +- core/res/res/values-it/strings.xml | 102 +- core/res/res/values-iw/strings.xml | 12 +- core/res/res/values-ja/strings.xml | 10 +- core/res/res/values-ka/strings.xml | 12 +- core/res/res/values-kk/strings.xml | 10 +- core/res/res/values-km/strings.xml | 10 +- core/res/res/values-kn/strings.xml | 10 +- core/res/res/values-ko/strings.xml | 16 +- core/res/res/values-ky/strings.xml | 12 +- core/res/res/values-land/dimens.xml | 2 - core/res/res/values-lo/strings.xml | 10 +- core/res/res/values-lt/strings.xml | 10 +- core/res/res/values-lv/strings.xml | 14 +- core/res/res/values-mk/strings.xml | 10 +- core/res/res/values-ml/strings.xml | 10 +- core/res/res/values-mn/strings.xml | 10 +- core/res/res/values-mr/strings.xml | 14 +- core/res/res/values-ms/strings.xml | 10 +- core/res/res/values-my/strings.xml | 46 +- core/res/res/values-nb/strings.xml | 10 +- core/res/res/values-ne/strings.xml | 10 +- core/res/res/values-nl/strings.xml | 14 +- core/res/res/values-or/strings.xml | 10 +- core/res/res/values-pa/strings.xml | 30 +- core/res/res/values-pl/strings.xml | 10 +- core/res/res/values-pt-rBR/strings.xml | 18 +- core/res/res/values-pt-rPT/strings.xml | 78 +- core/res/res/values-pt/strings.xml | 18 +- core/res/res/values-ro/strings.xml | 10 +- core/res/res/values-ru/strings.xml | 10 +- core/res/res/values-si/strings.xml | 10 +- core/res/res/values-sk/strings.xml | 10 +- core/res/res/values-sl/strings.xml | 12 +- core/res/res/values-sq/strings.xml | 10 +- core/res/res/values-sr/strings.xml | 12 +- core/res/res/values-sv/strings.xml | 10 +- core/res/res/values-sw/strings.xml | 10 +- core/res/res/values-sw600dp/config.xml | 7 + core/res/res/values-sw600dp/dimens.xml | 3 + core/res/res/values-ta/strings.xml | 26 +- core/res/res/values-te/strings.xml | 68 +- core/res/res/values-th/strings.xml | 10 +- core/res/res/values-tl/strings.xml | 10 +- core/res/res/values-tr/strings.xml | 10 +- core/res/res/values-uk/strings.xml | 12 +- core/res/res/values-ur/strings.xml | 10 +- core/res/res/values-uz/strings.xml | 10 +- core/res/res/values-vi/strings.xml | 12 +- core/res/res/values-zh-rCN/strings.xml | 10 +- core/res/res/values-zh-rHK/strings.xml | 10 +- core/res/res/values-zh-rTW/strings.xml | 12 +- core/res/res/values-zu/strings.xml | 12 +- core/res/res/values/attrs.xml | 24 +- core/res/res/values/colors.xml | 110 +- core/res/res/values/config.xml | 247 +- core/res/res/values/dimens.xml | 45 +- core/res/res/values/dimens_car.xml | 8 +- core/res/res/values/ids.xml | 9 + core/res/res/values/public.xml | 25 +- core/res/res/values/strings.xml | 19 +- core/res/res/values/styles.xml | 1 + core/res/res/values/symbols.xml | 55 + core/res/res/xml/power_profile.xml | 30 +- core/tests/BroadcastRadioTests/OWNERS | 3 +- .../hal2/StartProgramListUpdatesFanoutTest.java | 3 +- .../coretests/res/drawable/custom_drawable.xml | 21 + .../AccessibilityServiceTest.java | 126 +- .../src/android/app/NotificationTest.java | 24 + .../android/app/activity/ActivityThreadTest.java | 8 +- .../external/app/GenericDocumentTest.java | 14 - .../app/servertransaction/ObjectPoolTests.java | 3 +- .../servertransaction/TransactionParcelTests.java | 2 +- .../coretests/src/android/content/ContextTest.java | 8 - .../content/pm/ConstrainDisplayApisConfigTest.java | 24 +- .../view/InsetsAnimationControlImplTest.java | 4 +- .../src/android/view/InsetsControllerTest.java | 117 +- .../src/android/view/InsetsStateTest.java | 16 +- .../src/android/view/InsetsVisibilitiesTest.java | 121 + .../src/android/view/MotionEventTest.java | 24 + .../coretests/src/android/view/WindowInfoTest.java | 3 + .../AccessibilityServiceConnectionImpl.java | 3 + .../contentcapture/ContentCaptureContextTest.java | 4 +- .../src/android/window/CustomDrawable.java | 25 + .../window/WindowContextControllerTest.java | 3 +- .../src/android/window/WindowContextTest.java | 9 + .../android/internal/jank/FrameTrackerTest.java | 280 +- .../internal/jank/InteractionJankMonitorTest.java | 108 +- .../os/AmbientDisplayPowerCalculatorTest.java | 117 +- .../android/internal/os/BatteryStatsNoteTest.java | 474 +++- .../android/internal/os/BatteryUsageStatsRule.java | 14 + .../android/internal/os/MockBatteryStatsImpl.java | 16 +- .../com/android/internal/os/PowerProfileTest.java | 11 +- .../internal/os/ScreenPowerCalculatorTest.java | 225 +- .../statusbar/RegisterStatusBarResultTest.java | 7 +- .../devicestate/DeviceStateManagerGlobalTest.java | 28 + .../android/window/ConfigurationHelperTest.java | 164 ++ .../window/SizeConfigurationBucketsTest.java | 379 +++ data/etc/car/Android.bp | 7 + data/etc/car/com.android.car.carlauncher.xml | 2 + data/etc/car/com.android.car.shell.xml | 1 + .../car/com.google.android.car.adaslocation.xml | 21 + .../etc/car/com.google.android.car.kitchensink.xml | 4 + data/etc/platform.xml | 1 + data/etc/services.core.protolog.json | 695 +++-- .../java/android/graphics/BLASTBufferQueue.java | 18 +- .../java/android/graphics/HardwareRenderer.java | 33 +- .../security/keystore2/AndroidKeyStoreKey.java | 18 +- .../keystore2/AndroidKeyStorePublicKey.java | 18 +- .../security/keystore2/AndroidKeyStoreSpi.java | 5 +- .../keystore2/KeyStoreCryptoOperationUtils.java | 2 +- .../security/keystore2/AndroidKeyStoreSpiTest.java | 114 + .../window/common/CommonDisplayFeature.java | 35 +- .../src/androidx/window/common/DisplayFeature.java | 24 + .../window/extensions/ExtensionProvider.java | 41 - .../window/extensions/SampleExtensionImpl.java | 137 - .../androidx/window/extensions/StubExtension.java | 72 - .../window/extensions/WindowExtensionsImpl.java | 78 + .../extensions/WindowExtensionsProvider.java | 38 + .../embedding/JetpackTaskFragmentOrganizer.java | 296 ++ .../extensions/embedding/SplitContainer.java | 133 + .../extensions/embedding/SplitController.java | 930 +++++++ .../extensions/embedding/SplitPresenter.java | 424 +++ .../embedding/TaskFragmentAnimationAdapter.java | 205 ++ .../embedding/TaskFragmentAnimationController.java | 78 + .../embedding/TaskFragmentAnimationRunner.java | 277 ++ .../embedding/TaskFragmentAnimationSpec.java | 216 ++ .../embedding/TaskFragmentContainer.java | 315 +++ .../layout/WindowLayoutComponentImpl.java | 244 ++ .../androidx/window/sidecar/SampleSidecarImpl.java | 24 +- .../androidx/window/sidecar/SidecarProvider.java | 4 +- .../Jetpack/window-extensions-release.aar | Bin 7613 -> 19210 bytes libs/WindowManager/Shell/Android.bp | 14 +- libs/WindowManager/Shell/OWNERS | 4 - .../res/color/size_compat_background_ripple.xml | 19 + .../Shell/res/color/split_divider_background.xml | 19 + .../Shell/res/color/taskbar_background.xml | 19 + .../res/color/unfold_transition_background.xml | 19 + .../Shell/res/drawable/bubble_manage_btn_bg.xml | 2 +- .../Shell/res/drawable/compat_hint_bubble.xml | 21 + .../Shell/res/drawable/compat_hint_point.xml | 25 + .../WindowManager/Shell/res/drawable/pip_split.xml | 27 + .../res/drawable/size_compat_restart_button.xml | 25 +- .../drawable/size_compat_restart_button_ripple.xml | 20 + .../Shell/res/layout/bubble_manage_button.xml | 10 +- .../Shell/res/layout/bubble_manage_menu.xml | 30 +- .../Shell/res/layout/bubble_overflow_view.xml | 2 +- .../res/layout/bubble_stack_user_education.xml | 1 - .../res/layout/bubbles_manage_button_education.xml | 19 +- .../Shell/res/layout/compat_mode_hint.xml | 46 + .../Shell/res/layout/compat_ui_layout.xml | 37 + .../Shell/res/layout/docked_stack_divider.xml | 2 +- libs/WindowManager/Shell/res/layout/pip_menu.xml | 26 +- .../Shell/res/layout/size_compat_mode_hint.xml | 65 - .../Shell/res/layout/size_compat_ui.xml | 30 - .../WindowManager/Shell/res/layout/split_decor.xml | 30 + .../Shell/res/layout/split_divider.xml | 28 +- .../Shell/res/layout/split_outline.xml | 27 + libs/WindowManager/Shell/res/values-af/strings.xml | 2 +- libs/WindowManager/Shell/res/values-am/strings.xml | 2 +- libs/WindowManager/Shell/res/values-ar/strings.xml | 2 +- libs/WindowManager/Shell/res/values-as/strings.xml | 2 +- libs/WindowManager/Shell/res/values-az/strings.xml | 2 +- .../Shell/res/values-b+sr+Latn/strings.xml | 2 +- libs/WindowManager/Shell/res/values-be/strings.xml | 2 +- libs/WindowManager/Shell/res/values-bg/strings.xml | 2 +- libs/WindowManager/Shell/res/values-bn/strings.xml | 2 +- libs/WindowManager/Shell/res/values-bs/strings.xml | 2 +- .../Shell/res/values-bs/strings_tv.xml | 2 +- libs/WindowManager/Shell/res/values-ca/strings.xml | 2 +- libs/WindowManager/Shell/res/values-cs/strings.xml | 2 +- libs/WindowManager/Shell/res/values-da/strings.xml | 2 +- libs/WindowManager/Shell/res/values-de/strings.xml | 2 +- libs/WindowManager/Shell/res/values-el/strings.xml | 2 +- .../Shell/res/values-en-rAU/strings.xml | 2 +- .../Shell/res/values-en-rCA/strings.xml | 2 +- .../Shell/res/values-en-rGB/strings.xml | 2 +- .../Shell/res/values-en-rIN/strings.xml | 2 +- .../Shell/res/values-en-rXC/strings.xml | 2 +- .../Shell/res/values-es-rUS/strings.xml | 2 +- libs/WindowManager/Shell/res/values-es/strings.xml | 2 +- libs/WindowManager/Shell/res/values-et/strings.xml | 2 +- libs/WindowManager/Shell/res/values-eu/strings.xml | 2 +- libs/WindowManager/Shell/res/values-fa/strings.xml | 2 +- libs/WindowManager/Shell/res/values-fi/strings.xml | 2 +- .../Shell/res/values-fr-rCA/strings.xml | 2 +- libs/WindowManager/Shell/res/values-fr/strings.xml | 2 +- libs/WindowManager/Shell/res/values-gl/strings.xml | 2 +- libs/WindowManager/Shell/res/values-gu/strings.xml | 2 +- libs/WindowManager/Shell/res/values-hi/strings.xml | 2 +- libs/WindowManager/Shell/res/values-hr/strings.xml | 2 +- libs/WindowManager/Shell/res/values-hu/strings.xml | 2 +- libs/WindowManager/Shell/res/values-hy/strings.xml | 2 +- libs/WindowManager/Shell/res/values-in/strings.xml | 2 +- libs/WindowManager/Shell/res/values-is/strings.xml | 2 +- libs/WindowManager/Shell/res/values-it/strings.xml | 2 +- libs/WindowManager/Shell/res/values-iw/strings.xml | 2 +- libs/WindowManager/Shell/res/values-ja/strings.xml | 2 +- libs/WindowManager/Shell/res/values-ka/strings.xml | 2 +- libs/WindowManager/Shell/res/values-kk/strings.xml | 2 +- libs/WindowManager/Shell/res/values-km/strings.xml | 2 +- libs/WindowManager/Shell/res/values-kn/strings.xml | 2 +- libs/WindowManager/Shell/res/values-ko/strings.xml | 2 +- libs/WindowManager/Shell/res/values-ky/strings.xml | 2 +- .../WindowManager/Shell/res/values-land/dimens.xml | 4 + .../WindowManager/Shell/res/values-land/styles.xml | 3 +- libs/WindowManager/Shell/res/values-lo/strings.xml | 2 +- libs/WindowManager/Shell/res/values-lt/strings.xml | 2 +- libs/WindowManager/Shell/res/values-lv/strings.xml | 2 +- libs/WindowManager/Shell/res/values-mk/strings.xml | 2 +- libs/WindowManager/Shell/res/values-ml/strings.xml | 2 +- libs/WindowManager/Shell/res/values-mn/strings.xml | 2 +- libs/WindowManager/Shell/res/values-mr/strings.xml | 2 +- libs/WindowManager/Shell/res/values-ms/strings.xml | 2 +- libs/WindowManager/Shell/res/values-my/strings.xml | 4 +- .../Shell/res/values-my/strings_tv.xml | 2 +- libs/WindowManager/Shell/res/values-nb/strings.xml | 2 +- libs/WindowManager/Shell/res/values-ne/strings.xml | 2 +- libs/WindowManager/Shell/res/values-nl/strings.xml | 2 +- libs/WindowManager/Shell/res/values-or/strings.xml | 2 +- libs/WindowManager/Shell/res/values-pa/strings.xml | 2 +- libs/WindowManager/Shell/res/values-pl/strings.xml | 2 +- .../Shell/res/values-pt-rBR/strings.xml | 2 +- .../Shell/res/values-pt-rPT/strings.xml | 2 +- libs/WindowManager/Shell/res/values-pt/strings.xml | 2 +- libs/WindowManager/Shell/res/values-ro/strings.xml | 2 +- libs/WindowManager/Shell/res/values-ru/strings.xml | 2 +- libs/WindowManager/Shell/res/values-si/strings.xml | 2 +- libs/WindowManager/Shell/res/values-sk/strings.xml | 2 +- libs/WindowManager/Shell/res/values-sl/strings.xml | 2 +- libs/WindowManager/Shell/res/values-sq/strings.xml | 2 +- libs/WindowManager/Shell/res/values-sr/strings.xml | 2 +- libs/WindowManager/Shell/res/values-sv/strings.xml | 2 +- libs/WindowManager/Shell/res/values-sw/strings.xml | 2 +- libs/WindowManager/Shell/res/values-ta/strings.xml | 2 +- libs/WindowManager/Shell/res/values-te/strings.xml | 2 +- libs/WindowManager/Shell/res/values-th/strings.xml | 2 +- libs/WindowManager/Shell/res/values-tl/strings.xml | 2 +- libs/WindowManager/Shell/res/values-tr/strings.xml | 2 +- libs/WindowManager/Shell/res/values-uk/strings.xml | 2 +- libs/WindowManager/Shell/res/values-ur/strings.xml | 2 +- libs/WindowManager/Shell/res/values-uz/strings.xml | 2 +- libs/WindowManager/Shell/res/values-vi/strings.xml | 2 +- .../Shell/res/values-zh-rCN/strings.xml | 2 +- .../Shell/res/values-zh-rHK/strings.xml | 2 +- .../Shell/res/values-zh-rTW/strings.xml | 2 +- libs/WindowManager/Shell/res/values-zu/strings.xml | 2 +- libs/WindowManager/Shell/res/values/colors.xml | 5 +- libs/WindowManager/Shell/res/values/config.xml | 7 + libs/WindowManager/Shell/res/values/dimen.xml | 49 +- libs/WindowManager/Shell/res/values/strings.xml | 6 +- libs/WindowManager/Shell/res/values/styles.xml | 5 +- .../android/wm/shell/FullscreenTaskListener.java | 128 - .../android/wm/shell/RootDisplayAreaOrganizer.java | 114 + .../wm/shell/RootTaskDisplayAreaOrganizer.java | 8 + .../android/wm/shell/ShellCommandHandlerImpl.java | 13 +- .../src/com/android/wm/shell/ShellInitImpl.java | 40 +- .../com/android/wm/shell/ShellTaskOrganizer.java | 197 +- .../Shell/src/com/android/wm/shell/TaskView.java | 27 +- .../wm/shell/TaskViewFactoryController.java | 8 +- .../android/wm/shell/animation/Interpolators.java | 6 + .../src/com/android/wm/shell/apppairs/AppPair.java | 80 +- .../wm/shell/apppairs/AppPairsController.java | 10 +- .../Shell/src/com/android/wm/shell/apppairs/OWNERS | 2 + .../src/com/android/wm/shell/bubbles/Bubble.java | 22 +- .../android/wm/shell/bubbles/BubbleController.java | 90 +- .../com/android/wm/shell/bubbles/BubbleData.java | 24 +- .../wm/shell/bubbles/BubbleExpandedView.java | 90 +- .../android/wm/shell/bubbles/BubbleFlyoutView.java | 30 +- .../com/android/wm/shell/bubbles/BubbleOverflow.kt | 4 - .../shell/bubbles/BubbleOverflowContainerView.java | 4 +- .../android/wm/shell/bubbles/BubblePositioner.java | 352 ++- .../android/wm/shell/bubbles/BubbleStackView.java | 391 ++- .../wm/shell/bubbles/BubbleViewProvider.java | 6 - .../src/com/android/wm/shell/bubbles/Bubbles.java | 13 +- .../com/android/wm/shell/bubbles/DismissView.kt | 39 +- .../wm/shell/bubbles/ManageEducationView.kt | 81 +- .../Shell/src/com/android/wm/shell/bubbles/OWNERS | 2 + .../android/wm/shell/bubbles/StackEducationView.kt | 62 +- .../animation/ExpandedAnimationController.java | 169 +- .../animation/StackAnimationController.java | 27 +- .../wm/shell/common/DisplayChangeController.java | 24 +- .../android/wm/shell/common/DisplayController.java | 83 +- .../wm/shell/common/DisplayImeController.java | 92 +- .../wm/shell/common/DisplayInsetsController.java | 265 ++ .../com/android/wm/shell/common/DisplayLayout.java | 122 +- .../shell/common/SingleInstanceRemoteListener.java | 123 + .../com/android/wm/shell/common/SurfaceUtils.java | 16 +- .../wm/shell/common/SyncTransactionQueue.java | 69 +- .../common/annotations/ExternalMainThread.java | 34 + .../wm/shell/common/split/DividerHandleView.java | 18 +- .../shell/common/split/DividerRoundedCorner.java | 160 ++ .../android/wm/shell/common/split/DividerView.java | 121 +- .../wm/shell/common/split/SplitDecorManager.java | 190 ++ .../android/wm/shell/common/split/SplitLayout.java | 553 +++- .../shell/common/split/SplitScreenConstants.java | 47 + .../wm/shell/common/split/SplitWindowManager.java | 38 +- .../com/android/wm/shell/compatui/CompatUI.java | 32 + .../wm/shell/compatui/CompatUIController.java | 343 +++ .../android/wm/shell/compatui/CompatUILayout.java | 89 + .../wm/shell/compatui/CompatUIWindowManager.java | 321 +++ .../android/wm/shell/dagger/DynamicOverride.java | 119 + .../src/com/android/wm/shell/dagger/README.txt | 13 + .../com/android/wm/shell/dagger/TvPipModule.java | 174 ++ .../android/wm/shell/dagger/TvWMShellModule.java | 54 + .../android/wm/shell/dagger/WMShellBaseModule.java | 664 +++++ .../wm/shell/dagger/WMShellConcurrencyModule.java | 178 ++ .../com/android/wm/shell/dagger/WMShellModule.java | 375 +++ .../com/android/wm/shell/dagger/WMSingleton.java | 33 + .../shell/displayareahelper/DisplayAreaHelper.java | 39 + .../DisplayAreaHelperController.java | 45 + .../android/wm/shell/draganddrop/DragAndDrop.java | 34 + .../shell/draganddrop/DragAndDropController.java | 65 +- .../shell/draganddrop/DragAndDropEventLogger.java | 135 + .../wm/shell/draganddrop/DragAndDropPolicy.java | 84 +- .../android/wm/shell/draganddrop/DragLayout.java | 272 +- .../wm/shell/draganddrop/DropOutlineDrawable.java | 2 +- .../android/wm/shell/draganddrop/DropZoneView.java | 313 +++ .../wm/shell/freeform/FreeformTaskListener.java | 135 + .../shell/fullscreen/FullscreenTaskListener.java | 227 ++ .../fullscreen/FullscreenUnfoldController.java | 229 ++ .../HideDisplayCutoutOrganizer.java | 11 +- .../wm/shell/legacysplitscreen/DividerView.java | 7 +- .../LegacySplitDisplayLayout.java | 47 +- .../LegacySplitScreenController.java | 8 + .../LegacySplitScreenTransitions.java | 19 +- .../src/com/android/wm/shell/onehanded/OWNERS | 2 + .../wm/shell/onehanded/OneHandedController.java | 52 +- .../onehanded/OneHandedDisplayAreaOrganizer.java | 14 - .../wm/shell/onehanded/OneHandedSettingsUtil.java | 2 + .../Shell/src/com/android/wm/shell/pip/OWNERS | 2 + .../Shell/src/com/android/wm/shell/pip/Pip.java | 14 +- .../wm/shell/pip/PipAnimationController.java | 39 +- .../com/android/wm/shell/pip/PipBoundsState.java | 26 +- .../android/wm/shell/pip/PipMenuController.java | 5 + .../wm/shell/pip/PipSurfaceTransactionHelper.java | 4 +- .../com/android/wm/shell/pip/PipTaskOrganizer.java | 255 +- .../com/android/wm/shell/pip/PipTransition.java | 244 +- .../wm/shell/pip/PipTransitionController.java | 44 +- .../android/wm/shell/pip/PipTransitionState.java | 97 + .../wm/shell/pip/phone/PhonePipMenuController.java | 33 +- .../PipAccessibilityInteractionConnection.java | 2 +- .../android/wm/shell/pip/phone/PipController.java | 150 +- .../shell/pip/phone/PipDismissTargetHandler.java | 39 +- .../wm/shell/pip/phone/PipMenuIconsAlgorithm.java | 26 +- .../android/wm/shell/pip/phone/PipMenuView.java | 74 +- .../wm/shell/pip/phone/PipMotionHelper.java | 15 +- .../wm/shell/pip/phone/PipTouchHandler.java | 24 +- .../android/wm/shell/pip/tv/TvPipController.java | 2 +- .../android/wm/shell/pip/tv/TvPipTransition.java | 3 +- .../com/android/wm/shell/recents/IRecentTasks.aidl | 41 + .../wm/shell/recents/IRecentTasksListener.aidl | 28 + .../com/android/wm/shell/recents/RecentTasks.java | 32 + .../wm/shell/recents/RecentTasksController.java | 328 +++ .../wm/shell/sizecompatui/SizeCompatHintPopup.java | 71 - .../sizecompatui/SizeCompatRestartButton.java | 85 - .../shell/sizecompatui/SizeCompatUIController.java | 220 -- .../wm/shell/sizecompatui/SizeCompatUILayout.java | 332 --- .../sizecompatui/SizeCompatUIWindowManager.java | 127 - .../android/wm/shell/splitscreen/ISplitScreen.aidl | 39 +- .../android/wm/shell/splitscreen/MainStage.java | 46 +- .../src/com/android/wm/shell/splitscreen/OWNERS | 2 + .../android/wm/shell/splitscreen/SideStage.java | 23 +- .../android/wm/shell/splitscreen/SplitScreen.java | 35 +- .../shell/splitscreen/SplitScreenController.java | 512 +++- .../shell/splitscreen/SplitScreenTransitions.java | 12 +- .../shell/splitscreen/SplitscreenEventLogger.java | 375 +++ .../wm/shell/splitscreen/StageCoordinator.java | 933 +++++-- .../wm/shell/splitscreen/StageTaskListener.java | 150 +- .../splitscreen/StageTaskUnfoldController.java | 229 ++ .../android/wm/shell/stagesplit/ISplitScreen.aidl | 103 + .../wm/shell/stagesplit/ISplitScreenListener.aidl | 33 + .../com/android/wm/shell/stagesplit/MainStage.java | 104 + .../src/com/android/wm/shell/stagesplit/OWNERS | 2 + .../wm/shell/stagesplit/OutlineManager.java | 181 ++ .../android/wm/shell/stagesplit/OutlineView.java | 82 + .../com/android/wm/shell/stagesplit/SideStage.java | 144 + .../android/wm/shell/stagesplit/SplitScreen.java | 99 + .../wm/shell/stagesplit/SplitScreenController.java | 594 ++++ .../shell/stagesplit/SplitScreenTransitions.java | 298 +++ .../shell/stagesplit/SplitscreenEventLogger.java | 324 +++ .../wm/shell/stagesplit/StageCoordinator.java | 1331 +++++++++ .../wm/shell/stagesplit/StageTaskListener.java | 288 ++ .../stagesplit/StageTaskUnfoldController.java | 224 ++ .../startingsurface/SplashScreenExitAnimation.java | 32 +- .../startingsurface/SplashscreenContentDrawer.java | 29 +- .../SplashscreenIconDrawableFactory.java | 36 +- .../wm/shell/startingsurface/StartingSurface.java | 8 + .../startingsurface/StartingSurfaceDrawer.java | 116 +- .../startingsurface/StartingWindowController.java | 93 +- .../shell/startingsurface/TaskSnapshotWindow.java | 37 +- .../phone/PhoneStartingWindowTypeAlgorithm.java | 20 +- .../shell/transition/DefaultTransitionHandler.java | 536 +++- .../wm/shell/transition/IShellTransitions.aidl | 6 +- .../wm/shell/transition/LegacyTransitions.java | 124 + .../wm/shell/transition/OneShotRemoteHandler.java | 40 +- .../shell/transition/RemoteTransitionHandler.java | 164 +- .../shell/transition/ScreenRotationAnimation.java | 485 ++++ .../wm/shell/transition/ShellTransitions.java | 8 +- .../android/wm/shell/transition/Transitions.java | 124 +- .../wm/shell/transition/WindowThumbnail.java | 71 + .../shell/unfold/ShellUnfoldProgressProvider.java | 50 + .../shell/unfold/UnfoldBackgroundController.java | 89 + .../com/android/wm/shell/util/CounterRotator.java | 87 + .../wm/shell/util/GroupedRecentTaskInfo.aidl | 19 + .../wm/shell/util/GroupedRecentTaskInfo.java | 96 + .../android/wm/shell/util/StagedSplitBounds.java | 134 + libs/WindowManager/Shell/tests/flicker/Android.bp | 8 +- .../Shell/tests/flicker/AndroidManifest.xml | 3 + .../android/wm/shell/flicker/CommonAssertions.kt | 72 +- .../android/wm/shell/flicker/CommonConstants.kt | 8 +- .../src/com/android/wm/shell/flicker/WaitUtils.kt | 1 + .../AppPairsTestCannotPairNonResizeableApps.kt | 17 +- .../AppPairsTestPairPrimaryAndSecondaryApps.kt | 25 +- .../AppPairsTestSupportPairNonResizeableApps.kt | 15 +- .../AppPairsTestUnpairPrimaryAndSecondaryApps.kt | 36 +- .../shell/flicker/apppairs/AppPairsTransition.kt | 39 +- .../RotateTwoLaunchedAppsInAppPairsMode.kt | 43 +- ...ateTwoLaunchedAppsRotateAndEnterAppPairsMode.kt | 45 +- .../apppairs/RotateTwoLaunchedAppsTransition.kt | 18 +- .../wm/shell/flicker/bubble/BaseBubbleScreen.kt | 118 + .../wm/shell/flicker/bubble/DismissBubbleScreen.kt | 65 + .../wm/shell/flicker/bubble/ExpandBubbleScreen.kt | 59 + .../wm/shell/flicker/bubble/LaunchBubbleScreen.kt | 48 + .../wm/shell/flicker/bubble/MultiBubblesScreen.kt | 66 + .../wm/shell/flicker/helpers/AppPairsHelper.kt | 17 +- .../wm/shell/flicker/helpers/BaseAppHelper.kt | 9 +- .../wm/shell/flicker/helpers/FixedAppHelper.kt | 3 +- .../wm/shell/flicker/helpers/ImeAppHelper.kt | 7 +- .../wm/shell/flicker/helpers/LaunchBubbleHelper.kt | 33 + .../wm/shell/flicker/helpers/MultiWindowHelper.kt | 4 +- .../wm/shell/flicker/helpers/PipAppHelper.kt | 78 +- .../wm/shell/flicker/helpers/SimpleAppHelper.kt | 3 +- .../wm/shell/flicker/helpers/SplitScreenHelper.kt | 17 +- .../EnterSplitScreenDockActivity.kt | 49 +- .../EnterSplitScreenFromDetachedRecentTask.kt | 30 +- .../EnterSplitScreenLaunchToSide.kt | 61 +- .../EnterSplitScreenNotSupportNonResizable.kt | 27 +- .../EnterSplitScreenSupportNonResizable.kt | 25 +- .../ExitLegacySplitScreenFromBottom.kt | 59 +- ...xitPrimarySplitScreenShowSecondaryFullscreen.kt | 53 +- ...ySplitScreenFromIntentNotSupportNonResizable.kt | 111 +- ...gacySplitScreenFromIntentSupportNonResizable.kt | 64 +- ...ySplitScreenFromRecentNotSupportNonResizable.kt | 81 +- ...gacySplitScreenFromRecentSupportNonResizable.kt | 65 +- .../LegacySplitScreenToLauncher.kt | 69 +- .../LegacySplitScreenTransition.kt | 27 +- .../OpenAppToLegacySplitScreen.kt | 55 +- .../legacysplitscreen/ResizeLegacySplitScreen.kt | 60 +- .../RotateOneLaunchedAppAndEnterSplitScreen.kt | 48 +- .../RotateOneLaunchedAppInSplitScreenMode.kt | 44 +- .../RotateTwoLaunchedAppAndEnterSplitScreen.kt | 68 +- .../RotateTwoLaunchedAppInSplitScreenMode.kt | 61 +- .../wm/shell/flicker/pip/CommonAssertions.kt | 5 +- .../wm/shell/flicker/pip/EnterExitPipTest.kt | 116 - .../android/wm/shell/flicker/pip/EnterPipTest.kt | 122 +- .../flicker/pip/EnterPipToOtherOrientationTest.kt | 119 +- .../wm/shell/flicker/pip/ExitPipToAppTransition.kt | 130 + .../wm/shell/flicker/pip/ExitPipTransition.kt | 92 + .../flicker/pip/ExitPipViaExpandButtonClickTest.kt | 92 + .../wm/shell/flicker/pip/ExitPipViaIntentTest.kt | 89 + .../flicker/pip/ExitPipWithDismissButtonTest.kt | 78 + .../shell/flicker/pip/ExitPipWithSwipeDownTest.kt | 124 + .../flicker/pip/ExpandPipOnDoubleClickTest.kt | 174 ++ .../com/android/wm/shell/flicker/pip/Extensions.kt | 29 - .../pip/MovePipDownShelfHeightChangeTest.kt | 95 + .../flicker/pip/MovePipShelfHeightTransition.kt | 116 + .../flicker/pip/MovePipUpShelfHeightChangeTest.kt | 95 + .../wm/shell/flicker/pip/PipCloseTransition.kt | 79 - .../flicker/pip/PipCloseWithDismissButtonTest.kt | 60 - .../wm/shell/flicker/pip/PipCloseWithSwipeTest.kt | 93 - .../wm/shell/flicker/pip/PipKeyboardTest.kt | 10 +- .../shell/flicker/pip/PipLegacySplitScreenTest.kt | 56 +- .../wm/shell/flicker/pip/PipRotationTest.kt | 120 +- .../wm/shell/flicker/pip/PipShelfHeightTest.kt | 98 - .../android/wm/shell/flicker/pip/PipToAppTest.kt | 105 - .../android/wm/shell/flicker/pip/PipTransition.kt | 32 +- .../pip/SetRequestedOrientationWhilePinnedTest.kt | 45 +- .../wm/shell/flicker/pip/tv/TvPipMenuTests.kt | 9 +- .../com/android/wm/shell/flicker/pip/tv/TvUtils.kt | 6 +- .../test-apps/flickerapp/AndroidManifest.xml | 15 + .../test-apps/flickerapp/res/drawable/bg.png | Bin 0 -> 1966 bytes .../flickerapp/res/drawable/ic_bubble.xml | 31 + .../flickerapp/res/drawable/ic_message.xml | 26 + .../flickerapp/res/layout/activity_bubble.xml | 48 + .../flickerapp/res/layout/activity_main.xml | 48 + .../wm/shell/flicker/testapp/BubbleActivity.java | 77 + .../wm/shell/flicker/testapp/BubbleHelper.java | 178 ++ .../wm/shell/flicker/testapp/Components.java | 12 + .../flicker/testapp/LaunchBubbleActivity.java | 82 + .../android/wm/shell/ShellTaskOrganizerTests.java | 58 +- .../src/com/android/wm/shell/ShellTestCase.java | 2 + .../src/com/android/wm/shell/TaskViewTest.java | 15 +- .../wm/shell/apppairs/TestAppPairsController.java | 3 +- .../android/wm/shell/bubbles/BubbleDataTest.java | 89 +- .../wm/shell/bubbles/BubbleFlyoutViewTest.java | 17 +- .../animation/ExpandedAnimationControllerTest.java | 43 +- .../wm/shell/common/DisplayImeControllerTest.java | 2 +- .../shell/common/DisplayInsetsControllerTest.java | 193 ++ .../android/wm/shell/common/DisplayLayoutTest.java | 43 +- .../wm/shell/common/split/SplitLayoutTests.java | 71 +- .../common/split/SplitWindowManagerTests.java | 8 +- .../wm/shell/compatui/CompatUIControllerTest.java | 286 ++ .../wm/shell/compatui/CompatUILayoutTest.java | 111 + .../shell/compatui/CompatUIWindowManagerTest.java | 253 ++ .../draganddrop/DragAndDropControllerTest.java | 80 + .../shell/draganddrop/DragAndDropPolicyTest.java | 108 +- .../fullscreen/FullscreenTaskListenerTest.java | 155 ++ .../HideDisplayCutoutOrganizerTest.java | 17 +- .../shell/onehanded/OneHandedControllerTest.java | 53 + .../android/wm/shell/pip/PipBoundsStateTest.java | 2 +- .../android/wm/shell/pip/PipTaskOrganizerTest.java | 13 +- .../shell/recents/RecentTasksControllerTest.java | 263 ++ .../wm/shell/recents/StagedSplitBoundsTest.java | 94 + .../sizecompatui/SizeCompatHintPopupTest.java | 85 - .../sizecompatui/SizeCompatRestartButtonTest.java | 95 - .../sizecompatui/SizeCompatUIControllerTest.java | 161 -- .../shell/sizecompatui/SizeCompatUILayoutTest.java | 257 -- .../wm/shell/splitscreen/MainStageTests.java | 14 +- .../wm/shell/splitscreen/SideStageTests.java | 13 +- .../wm/shell/splitscreen/SplitTestUtils.java | 16 +- .../wm/shell/splitscreen/SplitTransitionTests.java | 47 +- .../shell/splitscreen/StageCoordinatorTests.java | 255 +- .../shell/splitscreen/StageTaskListenerTests.java | 84 +- .../StartingSurfaceDrawerTests.java | 59 +- .../startingsurface/TaskSnapshotWindowTest.java | 7 +- .../wm/shell/transition/ShellTransitionTests.java | 281 +- libs/androidfw/LoadedArsc.cpp | 19 +- libs/androidfw/tests/LoadedArsc_test.cpp | 32 + libs/androidfw/tests/data/sparse/R.h | 19 +- libs/androidfw/tests/data/sparse/gen_strings.sh | 2 + libs/androidfw/tests/data/sparse/not_sparse.apk | Bin 61971 -> 62155 bytes .../tests/data/sparse/res/values-v26/strings.xml | 1 + libs/androidfw/tests/data/sparse/sparse.apk | Bin 59275 -> 59459 bytes libs/hwui/Android.bp | 2 + libs/hwui/Properties.cpp | 3 +- libs/hwui/apex/android_matrix.cpp | 7 + libs/hwui/apex/include/android/graphics/matrix.h | 10 + .../hwui/jni/android_graphics_HardwareRenderer.cpp | 54 +- libs/hwui/jni/android_graphics_Matrix.cpp | 7 + libs/hwui/jni/android_graphics_Matrix.h | 3 + libs/hwui/libhwui.map.txt | 1 + libs/hwui/pipeline/skia/FunctorDrawable.h | 4 + libs/hwui/pipeline/skia/TransformCanvas.cpp | 14 +- libs/hwui/renderthread/CanvasContext.cpp | 12 +- libs/hwui/renderthread/CanvasContext.h | 6 +- libs/hwui/renderthread/DrawFrameTask.cpp | 18 +- libs/hwui/renderthread/DrawFrameTask.h | 9 +- libs/hwui/renderthread/EglManager.cpp | 7 +- .../renderthread/RenderEffectCapabilityQuery.cpp | 39 + .../renderthread/RenderEffectCapabilityQuery.h | 35 + libs/hwui/renderthread/RenderProxy.cpp | 6 +- libs/hwui/renderthread/RenderProxy.h | 3 +- libs/hwui/tests/unit/EglManagerTests.cpp | 14 + .../unit/RenderEffectCapabilityQueryTests.cpp | 52 + libs/input/SpriteController.cpp | 3 +- media/java/android/media/AudioAttributes.java | 99 +- media/java/android/media/AudioFormat.java | 89 +- media/java/android/media/AudioManager.java | 15 +- media/java/android/media/AudioSystem.java | 43 +- media/java/android/media/AudioTrack.java | 18 +- media/java/android/media/IAudioService.aidl | 55 + media/java/android/media/IMediaRouterClient.aidl | 1 + media/java/android/media/IMediaRouterService.aidl | 1 + media/java/android/media/ISpatializerCallback.aidl | 29 + .../ISpatializerHeadToSoundStagePoseCallback.aidl | 31 + .../ISpatializerHeadTrackingModeCallback.aidl | 29 + .../android/media/ISpatializerOutputCallback.aidl | 27 + media/java/android/media/MediaFormat.java | 13 + media/java/android/media/MediaMetrics.java | 10 +- media/java/android/media/MediaRouter.java | 38 +- media/java/android/media/Spatializer.java | 1089 ++++++++ .../android/media/projection/MediaProjection.java | 60 +- .../BluetoothMidiService/AndroidManifest.xml | 2 +- .../BluetoothMidiService/AndroidManifestBase.xml | 2 +- native/android/surface_control.cpp | 6 +- .../CompanionDeviceActivity.java | 12 +- .../CompanionDeviceDiscoveryService.java | 19 +- packages/InputDevices/res/values-it/strings.xml | 10 +- packages/InputDevices/res/values-pl/strings.xml | 82 +- .../PackageInstaller/res/values-as/strings.xml | 2 +- .../PackageInstaller/res/values-te/strings.xml | 6 +- .../PackageInstaller/res/values-zu/strings.xml | 2 +- packages/PrintSpooler/res/values-as/strings.xml | 8 +- packages/PrintSpooler/res/values-it/strings.xml | 4 +- packages/PrintSpooler/res/values-pa/strings.xml | 4 +- .../PrintSpooler/res/values-pt-rPT/strings.xml | 4 +- packages/PrintSpooler/res/values-te/strings.xml | 8 +- packages/SettingsLib/ActivityEmbedding/Android.bp | 21 + .../ActivityEmbedding/AndroidManifest.xml | 23 + .../activityembedding/ActivityEmbeddingUtils.java | 49 + packages/SettingsLib/Android.bp | 1 + .../settingslib/widget/FooterPreference.java | 7 +- .../res/layout/illustration_preference.xml | 10 +- .../settingslib/widget/IllustrationPreference.java | 65 +- .../MainSwitchPreference/res/values-v31/dimens.xml | 4 +- .../MainSwitchPreference/res/values/dimens.xml | 2 +- .../SearchWidget/res/values-sv/strings.xml | 2 +- .../src/com/android/settingslib/drawer/Tile.java | 13 + .../com/android/settingslib/drawer/TileUtils.java | 7 + .../layout-v31/preference_two_target_divider.xml | 2 + .../settingslib/utils/BuildCompatUtils.java | 6 +- packages/SettingsLib/res/values-ar/strings.xml | 2 +- packages/SettingsLib/res/values-as/arrays.xml | 8 +- packages/SettingsLib/res/values-as/strings.xml | 38 +- packages/SettingsLib/res/values-es-rUS/strings.xml | 2 +- packages/SettingsLib/res/values-es/strings.xml | 2 +- packages/SettingsLib/res/values-eu/arrays.xml | 4 +- packages/SettingsLib/res/values-eu/strings.xml | 4 +- packages/SettingsLib/res/values-fa/strings.xml | 2 +- packages/SettingsLib/res/values-fr-rCA/strings.xml | 2 +- packages/SettingsLib/res/values-gu/strings.xml | 2 +- packages/SettingsLib/res/values-in/strings.xml | 2 +- packages/SettingsLib/res/values-it/strings.xml | 2 +- packages/SettingsLib/res/values-iw/strings.xml | 4 +- packages/SettingsLib/res/values-km/strings.xml | 2 +- packages/SettingsLib/res/values-kn/strings.xml | 2 +- packages/SettingsLib/res/values-ml/strings.xml | 2 +- packages/SettingsLib/res/values-mr/strings.xml | 2 +- packages/SettingsLib/res/values-ms/strings.xml | 2 +- packages/SettingsLib/res/values-my/strings.xml | 4 +- packages/SettingsLib/res/values-nl/strings.xml | 2 +- packages/SettingsLib/res/values-pt-rPT/strings.xml | 2 +- packages/SettingsLib/res/values-ru/strings.xml | 2 +- packages/SettingsLib/res/values-vi/strings.xml | 2 +- packages/SettingsLib/res/values-zh-rTW/strings.xml | 2 +- .../settingslib/RestrictedLockUtilsInternal.java | 19 +- .../src/com/android/settingslib/SignalIcon.java | 211 +- .../applications/RecentAppOpsAccess.java | 264 ++ .../bluetooth/CachedBluetoothDevice.java | 6 + .../bluetooth/HearingAidDeviceManager.java | 3 + .../settingslib/bluetooth/HearingAidProfile.java | 11 +- .../instrumentation/MetricsFeatureProvider.java | 3 + .../settingslib/drawable/UserIconDrawable.java | 14 + .../settingslib/fuelgauge/BatteryStatus.java | 9 + .../fuelgauge/PowerAllowlistBackend.java | 12 + .../location/RecentLocationAccesses.java | 242 -- .../settingslib/location/SettingsInjector.java | 16 +- .../settingslib/media/LocalMediaManager.java | 2 +- .../android/settingslib/mobile/MobileMappings.java | 4 + .../android/settingslib/mobile/TelephonyIcons.java | 140 +- .../notification/EnableZenModeDialog.java | 24 +- .../com/android/settingslib/utils/StringUtil.java | 36 + .../settingslib/wifi/WifiRestrictionsCache.java | 131 + .../settingslib/wifi/WifiStatusTracker.java | 2 - .../applications/RecentAppOpsAccessesTest.java | 200 ++ .../fuelgauge/PowerAllowlistBackendTest.java | 10 + .../location/RecentLocationAccessesTest.java | 167 -- .../widget/IllustrationPreferenceTest.java | 31 + .../wifi/WifiRestrictionsCacheTest.java | 172 ++ .../provider/settings/backup/GlobalSettings.java | 2 + .../provider/settings/backup/SecureSettings.java | 1 + .../validators/GlobalSettingsValidators.java | 2 + .../validators/SecureSettingsValidators.java | 32 +- .../providers/settings/SettingsBackupAgent.java | 9 +- .../providers/settings/SettingsProvider.java | 50 +- .../src/android/provider/SettingsBackupTest.java | 4 +- packages/Shell/AndroidManifest.xml | 3 + packages/SystemUI/Android.bp | 26 + packages/SystemUI/AndroidManifest.xml | 23 +- packages/SystemUI/TEST_MAPPING | 41 +- .../animation/res/anim/launch_dialog_enter.xml | 23 + .../animation/res/anim/launch_dialog_exit.xml | 22 + .../launch_animation_interpolator_x.xml | 18 - .../launch_animation_interpolator_y.xml | 18 - packages/SystemUI/animation/res/values/ids.xml | 19 + packages/SystemUI/animation/res/values/styles.xml | 24 + .../systemui/animation/ActivityLaunchAnimator.kt | 440 +-- .../animation/DelegateLaunchAnimatorController.kt | 16 + .../systemui/animation/DialogLaunchAnimator.kt | 795 ++++++ .../GhostedViewLaunchAnimatorController.kt | 109 +- .../android/systemui/animation/Interpolators.java | 128 +- .../android/systemui/animation/LaunchAnimator.kt | 401 +++ .../android/systemui/animation/LaunchableView.kt | 30 + .../systemui/animation/ShadeInterpolation.kt | 37 + packages/SystemUI/docs/keyguard.md | 46 + packages/SystemUI/docs/keyguard/aod.md | 1 + packages/SystemUI/docs/keyguard/bouncer.md | 18 + packages/SystemUI/docs/plugins.md | 1 + packages/SystemUI/monet/Android.bp | 31 + packages/SystemUI/monet/AndroidManifest.xml | 20 + .../src/com/android/systemui/monet/ColorScheme.kt | 262 ++ .../src/com/android/systemui/monet/Shades.java | 69 + .../systemui/plugins/BcSmartspaceDataPlugin.java | 21 +- .../android/systemui/plugins/ActivityStarter.java | 10 +- .../src/com/android/systemui/plugins/qs/QS.java | 23 +- .../systemui/plugins/qs/QSContainerController.kt | 9 + .../statusbar/NotificationMenuRowPlugin.java | 6 - .../statusbar/StatusBarStateController.java | 3 +- packages/SystemUI/proguard.flags | 3 - .../color/numpad_key_color_secondary.xml | 5 + .../drawable/bubble_manage_user_education_bg.xml | 21 - .../res-keyguard/drawable/circle_white.xml | 19 - .../res-keyguard/drawable/face_auth_wallpaper.png | Bin 709067 -> 0 bytes .../res-keyguard/drawable/fp_to_unlock.xml | 171 ++ .../res-keyguard/drawable/ic_backspace_24dp.xml | 2 +- .../res-keyguard/drawable/ic_done_black_24dp.xml | 25 - .../res-keyguard/drawable/ic_fingerprint.xml | 48 + .../res-keyguard/drawable/ic_keyboard_tab_36dp.xml | 3 +- .../SystemUI/res-keyguard/drawable/ic_lock.xml | 95 + .../SystemUI/res-keyguard/drawable/ic_lock_aod.xml | 41 + .../SystemUI/res-keyguard/drawable/ic_unlocked.xml | 48 + .../res-keyguard/drawable/ic_unlocked_aod.xml | 44 + .../res-keyguard/drawable/lock_aod_to_ls.xml | 151 ++ .../res-keyguard/drawable/lock_ls_to_aod.xml | 151 ++ .../res-keyguard/drawable/lock_to_unlock.xml | 163 ++ .../res-keyguard/drawable/ripple_drawable_pin.xml | 20 - .../res-keyguard/drawable/super_lock_icon.xml | 102 + .../res-keyguard/drawable/unlock_to_fp.xml | 298 +++ .../res-keyguard/drawable/unlocked_aod_to_ls.xml | 133 + .../res-keyguard/drawable/unlocked_ls_to_aod.xml | 136 + .../res-keyguard/drawable/unlocked_to_aod_lock.xml | 169 ++ .../res-keyguard/layout/footer_actions.xml | 105 + .../res-keyguard/layout/keyguard_clock_switch.xml | 31 +- .../res-keyguard/layout/keyguard_pattern_view.xml | 71 +- .../res-keyguard/layout/keyguard_pin_view.xml | 315 +-- .../res-keyguard/layout/keyguard_slice_view.xml | 44 + .../res-keyguard/layout/keyguard_status_area.xml | 47 - .../SystemUI/res-keyguard/values-af/strings.xml | 35 +- .../SystemUI/res-keyguard/values-am/strings.xml | 35 +- .../SystemUI/res-keyguard/values-ar/strings.xml | 47 +- .../SystemUI/res-keyguard/values-as/strings.xml | 35 +- .../SystemUI/res-keyguard/values-az/strings.xml | 35 +- .../res-keyguard/values-b+sr+Latn/strings.xml | 38 +- .../SystemUI/res-keyguard/values-be/strings.xml | 41 +- .../SystemUI/res-keyguard/values-bg/strings.xml | 35 +- .../SystemUI/res-keyguard/values-bn/strings.xml | 35 +- .../SystemUI/res-keyguard/values-bs/strings.xml | 38 +- .../SystemUI/res-keyguard/values-ca/strings.xml | 35 +- .../SystemUI/res-keyguard/values-cs/strings.xml | 41 +- .../SystemUI/res-keyguard/values-da/strings.xml | 35 +- .../SystemUI/res-keyguard/values-de/strings.xml | 35 +- .../SystemUI/res-keyguard/values-el/strings.xml | 35 +- .../res-keyguard/values-en-rAU/strings.xml | 35 +- .../res-keyguard/values-en-rCA/strings.xml | 35 +- .../res-keyguard/values-en-rGB/strings.xml | 35 +- .../res-keyguard/values-en-rIN/strings.xml | 35 +- .../res-keyguard/values-en-rXC/strings.xml | 35 +- .../res-keyguard/values-es-rUS/strings.xml | 35 +- .../SystemUI/res-keyguard/values-es/strings.xml | 35 +- .../SystemUI/res-keyguard/values-et/strings.xml | 35 +- .../SystemUI/res-keyguard/values-eu/strings.xml | 35 +- .../SystemUI/res-keyguard/values-fa/strings.xml | 35 +- .../SystemUI/res-keyguard/values-fi/strings.xml | 35 +- .../res-keyguard/values-fr-rCA/strings.xml | 35 +- .../SystemUI/res-keyguard/values-fr/strings.xml | 35 +- .../SystemUI/res-keyguard/values-gl/strings.xml | 35 +- .../SystemUI/res-keyguard/values-gu/strings.xml | 35 +- .../SystemUI/res-keyguard/values-hi/strings.xml | 35 +- .../SystemUI/res-keyguard/values-hr/strings.xml | 38 +- .../SystemUI/res-keyguard/values-hu/strings.xml | 35 +- .../SystemUI/res-keyguard/values-hy/strings.xml | 35 +- .../SystemUI/res-keyguard/values-in/strings.xml | 35 +- .../SystemUI/res-keyguard/values-is/strings.xml | 35 +- .../SystemUI/res-keyguard/values-it/strings.xml | 45 +- .../SystemUI/res-keyguard/values-iw/strings.xml | 41 +- .../SystemUI/res-keyguard/values-ja/strings.xml | 35 +- .../SystemUI/res-keyguard/values-ka/strings.xml | 35 +- .../SystemUI/res-keyguard/values-kk/strings.xml | 35 +- .../SystemUI/res-keyguard/values-km/strings.xml | 35 +- .../SystemUI/res-keyguard/values-kn/strings.xml | 35 +- .../SystemUI/res-keyguard/values-ko/strings.xml | 35 +- .../SystemUI/res-keyguard/values-ky/strings.xml | 35 +- .../res-keyguard/values-land/donottranslate.xml | 19 + .../SystemUI/res-keyguard/values-land/integers.xml | 23 - .../SystemUI/res-keyguard/values-lo/strings.xml | 35 +- .../SystemUI/res-keyguard/values-lt/strings.xml | 41 +- .../SystemUI/res-keyguard/values-lv/strings.xml | 38 +- .../SystemUI/res-keyguard/values-mk/strings.xml | 35 +- .../SystemUI/res-keyguard/values-ml/strings.xml | 37 +- .../SystemUI/res-keyguard/values-mn/strings.xml | 35 +- .../SystemUI/res-keyguard/values-mr/strings.xml | 35 +- .../SystemUI/res-keyguard/values-ms/strings.xml | 35 +- .../SystemUI/res-keyguard/values-my/strings.xml | 45 +- .../SystemUI/res-keyguard/values-nb/strings.xml | 35 +- .../SystemUI/res-keyguard/values-ne/strings.xml | 35 +- .../SystemUI/res-keyguard/values-nl/strings.xml | 35 +- .../SystemUI/res-keyguard/values-or/strings.xml | 35 +- .../SystemUI/res-keyguard/values-pa/strings.xml | 35 +- .../SystemUI/res-keyguard/values-pl/strings.xml | 41 +- .../SystemUI/res-keyguard/values-port/bools.xml | 19 - .../SystemUI/res-keyguard/values-port/integers.xml | 23 - .../res-keyguard/values-pt-rBR/strings.xml | 35 +- .../res-keyguard/values-pt-rPT/strings.xml | 45 +- .../SystemUI/res-keyguard/values-pt/strings.xml | 35 +- .../SystemUI/res-keyguard/values-ro/strings.xml | 38 +- .../SystemUI/res-keyguard/values-ru/strings.xml | 41 +- .../SystemUI/res-keyguard/values-si/strings.xml | 35 +- .../SystemUI/res-keyguard/values-sk/strings.xml | 41 +- .../SystemUI/res-keyguard/values-sl/strings.xml | 41 +- .../SystemUI/res-keyguard/values-sq/strings.xml | 35 +- .../SystemUI/res-keyguard/values-sr/strings.xml | 38 +- .../SystemUI/res-keyguard/values-sv/strings.xml | 35 +- .../SystemUI/res-keyguard/values-sw/strings.xml | 35 +- .../res-keyguard/values-sw600dp-land/dimens.xml | 4 + .../values-sw600dp-land/donottranslate.xml | 21 + .../SystemUI/res-keyguard/values-sw600dp/bools.xml | 19 - .../res-keyguard/values-sw600dp/dimens.xml | 3 + .../SystemUI/res-keyguard/values-sw720dp/bools.xml | 20 + .../SystemUI/res-keyguard/values-ta/strings.xml | 35 +- .../SystemUI/res-keyguard/values-te/strings.xml | 41 +- .../SystemUI/res-keyguard/values-th/strings.xml | 35 +- .../SystemUI/res-keyguard/values-tl/strings.xml | 35 +- .../SystemUI/res-keyguard/values-tr/strings.xml | 35 +- .../SystemUI/res-keyguard/values-uk/strings.xml | 41 +- .../SystemUI/res-keyguard/values-ur/strings.xml | 35 +- .../SystemUI/res-keyguard/values-uz/strings.xml | 35 +- .../SystemUI/res-keyguard/values-vi/strings.xml | 35 +- .../res-keyguard/values-zh-rCN/strings.xml | 35 +- .../res-keyguard/values-zh-rHK/strings.xml | 35 +- .../res-keyguard/values-zh-rTW/strings.xml | 35 +- .../SystemUI/res-keyguard/values-zu/strings.xml | 35 +- packages/SystemUI/res-keyguard/values/alias.xml | 3 - packages/SystemUI/res-keyguard/values/colors.xml | 2 - packages/SystemUI/res-keyguard/values/dimens.xml | 18 +- .../res-keyguard/values/donottranslate.xml | 3 +- packages/SystemUI/res-keyguard/values/strings.xml | 87 +- packages/SystemUI/res-keyguard/values/styles.xml | 28 +- .../SystemUI/res-product/values-as/strings.xml | 24 +- .../SystemUI/res-product/values-te/strings.xml | 4 +- .../SystemUI/res-product/values-zu/strings.xml | 6 +- packages/SystemUI/res/anim/bottomsheet_in.xml | 26 - packages/SystemUI/res/anim/bottomsheet_out.xml | 25 - packages/SystemUI/res/anim/fp_to_unlock.xml | 171 -- packages/SystemUI/res/anim/lock_to_unlock.xml | 163 -- .../anim/tv_pip_controls_focus_gain_animation.xml | 21 - .../anim/tv_pip_controls_focus_loss_animation.xml | 21 - .../res/anim/tv_pip_menu_fade_in_animation.xml | 21 - .../res/anim/tv_pip_menu_fade_out_animation.xml | 21 - .../res/color/notification_guts_buttons.xml | 7 - packages/SystemUI/res/color/pin_delete_color.xml | 19 - packages/SystemUI/res/color/pin_divider_color.xml | 19 - .../SystemUI/res/color/qs_user_detail_name.xml | 23 - .../res/color/screenrecord_switch_thumb_color.xml | 26 - .../res/color/screenrecord_switch_track_color.xml | 27 - .../SystemUI/res/color/settingslib_state_off.xml | 5 - .../res/drawable-hdpi/pip_dismiss_scrim.9.png | Bin 525 -> 0 bytes .../res/drawable-hdpi/screenshot_panel.9.png | Bin 582 -> 0 bytes .../res/drawable-hdpi/search_bg_transparent.9.png | Bin 625 -> 0 bytes .../ic_5g_plus_mobiledata.xml | 36 - .../ic_5g_plus_mobiledata.xml | 36 - .../res/drawable-mdpi/one_handed_tutorial.png | Bin 1054 -> 0 bytes .../res/drawable-mdpi/pip_dismiss_scrim.9.png | Bin 436 -> 0 bytes .../res/drawable-mdpi/screenshot_panel.9.png | Bin 404 -> 0 bytes .../res/drawable-mdpi/search_bg_transparent.9.png | Bin 431 -> 0 bytes .../res/drawable-nodpi/android_11_dial.xml | 63 - .../drawable-nodpi/work_challenge_background.png | Bin 210081 -> 0 bytes .../res/drawable-xhdpi/one_handed_tutorial.png | Bin 2215 -> 0 bytes .../res/drawable-xhdpi/pip_dismiss_scrim.9.png | Bin 611 -> 0 bytes packages/SystemUI/res/drawable-xhdpi/remote.png | Bin 6957 -> 0 bytes .../res/drawable-xhdpi/search_bg_transparent.9.png | Bin 866 -> 0 bytes .../res/drawable-xxhdpi/one_handed_tutorial.png | Bin 3649 -> 0 bytes .../res/drawable-xxhdpi/pip_dismiss_scrim.9.png | Bin 633 -> 0 bytes .../drawable-xxhdpi/search_bg_transparent.9.png | Bin 1246 -> 0 bytes .../res/drawable-xxxhdpi/one_handed_tutorial.png | Bin 5029 -> 0 bytes .../res/drawable-xxxhdpi/pip_dismiss_scrim.9.png | Bin 647 -> 0 bytes .../res/drawable/assist_orb_navbar_scrim.xml | 25 - .../SystemUI/res/drawable/assist_orb_scrim.xml | 25 - .../SystemUI/res/drawable/circle_blue_40dp.xml | 22 - .../SystemUI/res/drawable/circle_white_40dp.xml | 22 - .../floating_dismiss_gradient_transition.xml | 19 - packages/SystemUI/res/drawable/ic_add_to_home.xml | 26 - .../SystemUI/res/drawable/ic_arrow_downward.xml | 25 - packages/SystemUI/res/drawable/ic_camera.xml | 25 - packages/SystemUI/res/drawable/ic_cancel_24.xml | 25 - packages/SystemUI/res/drawable/ic_chevron_up.xml | 24 - packages/SystemUI/res/drawable/ic_clear.xml | 24 - .../res/drawable/ic_demote_conversation.xml | 25 - packages/SystemUI/res/drawable/ic_drag_handle.xml | 24 - packages/SystemUI/res/drawable/ic_exit_to_app.xml | 27 - packages/SystemUI/res/drawable/ic_fingerprint.xml | 39 - .../res/drawable/ic_fullscreen_white_24dp.xml | 24 - packages/SystemUI/res/drawable/ic_important.xml | 26 - .../SystemUI/res/drawable/ic_kg_fingerprint.xml | 39 + .../res/drawable/ic_notification_block.xml | 25 - .../res/drawable/ic_notification_gentle.xml | 40 - .../res/drawable/ic_notification_interruptive.xml | 41 - packages/SystemUI/res/drawable/ic_pause_white.xml | 25 - packages/SystemUI/res/drawable/ic_photo_camera.xml | 28 - .../SystemUI/res/drawable/ic_play_arrow_white.xml | 25 - .../drawable/ic_power_settings_new_gm2_24px.xml | 9 - .../SystemUI/res/drawable/ic_qs_bluetooth_on.xml | 24 - .../res/drawable/ic_qs_no_internet_airplane.xml | 28 - .../SystemUI/res/drawable/ic_qs_screenrecord.xml | 9 - packages/SystemUI/res/drawable/ic_qs_wifi_0.xml | 32 - .../SystemUI/res/drawable/ic_settings_16dp.xml | 27 - .../SystemUI/res/drawable/ic_tune_black_16dp.xml | 26 - packages/SystemUI/res/drawable/ic_unlock.xml | 42 - packages/SystemUI/res/drawable/ic_volume_voice.xml | 27 - packages/SystemUI/res/drawable/ic_width.xml | 28 - .../res/drawable/internet_dialog_background.xml | 23 - .../drawable/internet_dialog_footer_background.xml | 30 - ...ternet_dialog_rounded_top_corner_background.xml | 22 - .../res/drawable/keyguard_bottom_affordance_bg.xml | 3 +- .../drawable/media_output_dialog_background.xml | 23 - .../media_output_dialog_button_background.xml | 32 + packages/SystemUI/res/drawable/pip_icon.xml | 25 - .../SystemUI/res/drawable/pip_resize_handle.xml | 29 - packages/SystemUI/res/drawable/qs_bg_gradient.xml | 24 - .../SystemUI/res/drawable/qs_dialog_btn_filled.xml | 39 + .../res/drawable/qs_dialog_btn_outline.xml | 42 + .../SystemUI/res/drawable/qs_dual_tile_caret.xml | 25 - .../res/drawable/rounded_bg_bottom_background.xml | 11 - packages/SystemUI/res/drawable/rounded_bg_top.xml | 22 - .../drawable/rounded_corner_bottom_secondary.xml | 16 + .../res/drawable/rounded_corner_top_secondary.xml | 16 + .../SystemUI/res/drawable/rounded_secondary.xml | 24 + .../screenrecord_button_background_outline.xml | 30 - .../res/drawable/screenrecord_switch_thumb.xml | 29 - .../res/drawable/screenrecord_switch_track.xml | 24 - .../res/drawable/screenshot_rounded_corners.xml | 20 - .../settingslib_switch_bar_bg_disabled.xml | 26 - .../SystemUI/res/drawable/stat_notify_image.xml | 28 - packages/SystemUI/res/drawable/stat_sys_camera.xml | 22 - .../SystemUI/res/drawable/stat_sys_location.xml | 19 - .../drawable/stat_sys_managed_profile_status.xml | 5 +- .../SystemUI/res/drawable/stat_sys_mic_none.xml | 30 - packages/SystemUI/res/drawable/tv_ic_mic_white.xml | 27 - .../res/drawable/udfps_enroll_checkmark.xml | 35 + .../res/interpolator/assist_disclosure_trace.xml | 22 - ...or_to_trustedstate_animation_interpolator_0.xml | 19 - ...or_to_trustedstate_animation_interpolator_1.xml | 19 - ...or_to_trustedstate_animation_interpolator_2.xml | 19 - ...or_to_trustedstate_animation_interpolator_3.xml | 19 - ...or_to_trustedstate_animation_interpolator_4.xml | 19 - ...or_to_trustedstate_animation_interpolator_5.xml | 19 - ...or_to_trustedstate_animation_interpolator_6.xml | 19 - .../ic_caret_down_animation_interpolator_0.xml | 19 - .../ic_caret_up_animation_interpolator_0.xml | 19 - ...ingerprint_toerror_animation_interpolator_0.xml | 19 - ...ingerprint_toerror_animation_interpolator_1.xml | 19 - ...ingerprint_toerror_animation_interpolator_2.xml | 19 - ...ingerprint_toerror_animation_interpolator_3.xml | 19 - ...ingerprint_toerror_animation_interpolator_4.xml | 19 - ...ingerprint_toerror_animation_interpolator_5.xml | 19 - ...ingerprint_toerror_animation_interpolator_6.xml | 19 - ...c_fingerprint_tofp_animation_interpolator_0.xml | 19 - ...c_fingerprint_tofp_animation_interpolator_1.xml | 19 - ...c_fingerprint_tofp_animation_interpolator_2.xml | 19 - ...c_fingerprint_tofp_animation_interpolator_3.xml | 19 - ...c_fingerprint_tofp_animation_interpolator_4.xml | 19 - ...c_fingerprint_tofp_animation_interpolator_5.xml | 19 - ...andscape_to_rotate_animation_interpolator_0.xml | 19 - ...otate_to_landscape_animation_interpolator_0.xml | 19 - ...rotate_to_portrait_animation_interpolator_0.xml | 19 - ...ngerprint_draw_off_animation_interpolator_0.xml | 19 - ...ngerprint_draw_off_animation_interpolator_1.xml | 19 - ...ingerprint_draw_on_animation_interpolator_0.xml | 19 - ...ingerprint_draw_on_animation_interpolator_1.xml | 19 - ...ted_state_to_error_animation_interpolator_0.xml | 19 - ...ted_state_to_error_animation_interpolator_1.xml | 19 - ...ted_state_to_error_animation_interpolator_2.xml | 19 - ...ted_state_to_error_animation_interpolator_3.xml | 19 - ...ted_state_to_error_animation_interpolator_4.xml | 19 - ...ted_state_to_error_animation_interpolator_5.xml | 19 - .../wireless_charging_animation_interpolator_0.xml | 21 - .../wireless_charging_animation_interpolator_1.xml | 21 - .../layout-land/global_actions_column_seascape.xml | 68 - .../res/layout-land/global_actions_grid_item.xml | 61 - .../layout-land/global_actions_grid_seascape.xml | 79 - .../layout-sw600dp-land/global_actions_grid_v2.xml | 68 - .../res/layout-sw600dp/global_actions_grid_v2.xml | 76 - .../layout/alert_dialog_button_bar_systemui.xml | 63 + .../SystemUI/res/layout/alert_dialog_systemui.xml | 91 + .../res/layout/alert_dialog_title_systemui.xml | 62 + packages/SystemUI/res/layout/app_ops_info.xml | 96 - packages/SystemUI/res/layout/assist_orb.xml | 53 - .../res/layout/auth_biometric_contents.xml | 3 + .../SystemUI/res/layout/combined_qs_header.xml | 104 + packages/SystemUI/res/layout/controls_icon.xml | 26 - .../res/layout/global_actions_change_panel.xml | 31 - .../res/layout/global_actions_grid_item.xml | 60 - .../SystemUI/res/layout/global_actions_grid_v2.xml | 35 - .../SystemUI/res/layout/global_actions_item.xml | 60 - .../res/layout/global_actions_lock_view.xml | 35 - .../res/layout/global_screenshot_static.xml | 11 +- .../SystemUI/res/layout/horizontal_divider.xml | 25 - .../res/layout/internet_connectivity_dialog.xml | 112 +- .../SystemUI/res/layout/internet_list_item.xml | 4 +- .../SystemUI/res/layout/keyguard_bottom_area.xml | 4 +- .../SystemUI/res/layout/media_output_dialog.xml | 42 +- .../SystemUI/res/layout/media_output_list_item.xml | 89 +- packages/SystemUI/res/layout/media_view.xml | 1 + packages/SystemUI/res/layout/mland.xml | 103 - packages/SystemUI/res/layout/mland_scorefield.xml | 32 - .../SystemUI/res/layout/nav_control_widget.xml | 62 - packages/SystemUI/res/layout/nav_width_view.xml | 26 - .../res/layout/navigation_bar_app_item.xml | 30 - packages/SystemUI/res/layout/ongoing_call_chip.xml | 1 + .../SystemUI/res/layout/people_space_widget.xml | 27 - .../res/layout/people_space_widget_item.xml | 93 - .../res/layout/preference_widget_settings.xml | 44 - packages/SystemUI/res/layout/privacy_dialog.xml | 3 +- .../SystemUI/res/layout/punctuation_layout.xml | 100 - packages/SystemUI/res/layout/qs_add_tiles_list.xml | 32 - .../res/layout/qs_customize_panel_content.xml | 2 +- packages/SystemUI/res/layout/qs_detail.xml | 2 +- packages/SystemUI/res/layout/qs_detail_header.xml | 2 +- packages/SystemUI/res/layout/qs_footer_impl.xml | 88 +- packages/SystemUI/res/layout/qs_page_indicator.xml | 27 - packages/SystemUI/res/layout/qs_panel.xml | 15 +- packages/SystemUI/res/layout/qs_tile_layout.xml | 21 - packages/SystemUI/res/layout/qs_user_detail.xml | 2 +- .../SystemUI/res/layout/qs_user_detail_item.xml | 6 +- .../SystemUI/res/layout/qs_user_dialog_content.xml | 33 + .../SystemUI/res/layout/quick_qs_status_icons.xml | 8 +- .../layout/quick_status_bar_expanded_header.xml | 41 +- .../SystemUI/res/layout/recents_onboarding.xml | 64 - .../res/layout/remember_permission_checkbox.xml | 34 - packages/SystemUI/res/layout/rotate_suggestion.xml | 23 +- packages/SystemUI/res/layout/rounded_corners.xml | 75 - .../SystemUI/res/layout/rounded_corners_bottom.xml | 7 +- .../SystemUI/res/layout/rounded_corners_top.xml | 12 +- .../SystemUI/res/layout/screen_record_dialog.xml | 56 +- packages/SystemUI/res/layout/shelf_menu_anchor.xml | 24 - packages/SystemUI/res/layout/sidefps_view.xml | 16 +- .../SystemUI/res/layout/split_shade_header.xml | 100 + .../SystemUI/res/layout/status_bar_expanded.xml | 29 +- .../res/layout/status_bar_no_notifications.xml | 3 +- .../res/layout/super_notification_shade.xml | 14 +- packages/SystemUI/res/layout/super_status_bar.xml | 4 +- packages/SystemUI/res/layout/system_icons.xml | 2 +- packages/SystemUI/res/layout/text_toast.xml | 1 - packages/SystemUI/res/layout/tuner_activity.xml | 4 +- .../SystemUI/res/layout/udfps_aod_lock_icon.xml | 27 + .../SystemUI/res/layout/udfps_surface_view.xml | 21 - packages/SystemUI/res/mipmap-hdpi/ic_daydreams.png | Bin 8822 -> 0 bytes packages/SystemUI/res/mipmap-mdpi/ic_daydreams.png | Bin 5268 -> 0 bytes .../SystemUI/res/mipmap-xhdpi/ic_daydreams.png | Bin 13030 -> 0 bytes packages/SystemUI/res/raw/sfps_pulse.json | 1 + .../SystemUI/res/raw/sfps_pulse_landscape.json | 1 + .../res/transition/tv_privacy_chip_collapse.xml | 20 - .../res/transition/tv_privacy_chip_expand.xml | 20 - packages/SystemUI/res/values-af/strings.xml | 315 +-- packages/SystemUI/res/values-af/strings_tv.xml | 2 - packages/SystemUI/res/values-am/strings.xml | 315 +-- packages/SystemUI/res/values-am/strings_tv.xml | 2 - packages/SystemUI/res/values-ar/strings.xml | 321 +-- packages/SystemUI/res/values-ar/strings_tv.xml | 2 - packages/SystemUI/res/values-as-land/strings.xml | 2 +- packages/SystemUI/res/values-as/strings.xml | 339 +-- packages/SystemUI/res/values-as/strings_tv.xml | 2 - packages/SystemUI/res/values-az/strings.xml | 315 +-- packages/SystemUI/res/values-az/strings_tv.xml | 2 - packages/SystemUI/res/values-b+sr+Latn/strings.xml | 327 +-- .../SystemUI/res/values-b+sr+Latn/strings_tv.xml | 2 - packages/SystemUI/res/values-be/strings.xml | 323 +-- packages/SystemUI/res/values-be/strings_tv.xml | 2 - packages/SystemUI/res/values-bg/strings.xml | 315 +-- packages/SystemUI/res/values-bg/strings_tv.xml | 2 - packages/SystemUI/res/values-bn/strings.xml | 315 +-- packages/SystemUI/res/values-bn/strings_tv.xml | 2 - packages/SystemUI/res/values-bs/strings.xml | 315 +-- packages/SystemUI/res/values-bs/strings_tv.xml | 2 - packages/SystemUI/res/values-ca/strings.xml | 315 +-- packages/SystemUI/res/values-ca/strings_tv.xml | 2 - packages/SystemUI/res/values-cs/strings.xml | 315 +-- packages/SystemUI/res/values-cs/strings_tv.xml | 2 - packages/SystemUI/res/values-da/strings.xml | 315 +-- packages/SystemUI/res/values-da/strings_tv.xml | 2 - packages/SystemUI/res/values-de/strings.xml | 317 +-- packages/SystemUI/res/values-de/strings_tv.xml | 2 - packages/SystemUI/res/values-el/strings.xml | 315 +-- packages/SystemUI/res/values-el/strings_tv.xml | 2 - packages/SystemUI/res/values-en-rAU/strings.xml | 315 +-- packages/SystemUI/res/values-en-rAU/strings_tv.xml | 2 - packages/SystemUI/res/values-en-rCA/strings.xml | 315 +-- packages/SystemUI/res/values-en-rCA/strings_tv.xml | 2 - packages/SystemUI/res/values-en-rGB/strings.xml | 315 +-- packages/SystemUI/res/values-en-rGB/strings_tv.xml | 2 - packages/SystemUI/res/values-en-rIN/strings.xml | 315 +-- packages/SystemUI/res/values-en-rIN/strings_tv.xml | 2 - packages/SystemUI/res/values-en-rXC/strings.xml | 315 +-- packages/SystemUI/res/values-en-rXC/strings_tv.xml | 2 - packages/SystemUI/res/values-es-rUS/strings.xml | 323 +-- packages/SystemUI/res/values-es-rUS/strings_tv.xml | 2 - packages/SystemUI/res/values-es/strings.xml | 319 +-- packages/SystemUI/res/values-es/strings_tv.xml | 2 - packages/SystemUI/res/values-et/strings.xml | 317 +-- packages/SystemUI/res/values-et/strings_tv.xml | 2 - packages/SystemUI/res/values-eu/strings.xml | 317 +-- packages/SystemUI/res/values-eu/strings_tv.xml | 2 - packages/SystemUI/res/values-fa/strings.xml | 317 +-- packages/SystemUI/res/values-fa/strings_tv.xml | 2 - packages/SystemUI/res/values-fi/strings.xml | 319 +-- packages/SystemUI/res/values-fi/strings_tv.xml | 2 - packages/SystemUI/res/values-fr-rCA/strings.xml | 315 +-- packages/SystemUI/res/values-fr-rCA/strings_tv.xml | 2 - packages/SystemUI/res/values-fr/strings.xml | 315 +-- packages/SystemUI/res/values-fr/strings_tv.xml | 2 - .../res/values-fr/tiles_states_strings.xml | 4 +- packages/SystemUI/res/values-gl/strings.xml | 315 +-- packages/SystemUI/res/values-gl/strings_tv.xml | 2 - packages/SystemUI/res/values-gu/strings.xml | 317 +-- packages/SystemUI/res/values-gu/strings_tv.xml | 2 - .../SystemUI/res/values-h560dp-xhdpi/config.xml | 23 - packages/SystemUI/res/values-h800dp/dimens.xml | 2 +- packages/SystemUI/res/values-hi/strings.xml | 317 +-- packages/SystemUI/res/values-hi/strings_tv.xml | 2 - packages/SystemUI/res/values-hr/strings.xml | 317 +-- packages/SystemUI/res/values-hr/strings_tv.xml | 2 - packages/SystemUI/res/values-hu/strings.xml | 315 +-- packages/SystemUI/res/values-hu/strings_tv.xml | 2 - packages/SystemUI/res/values-hy/strings.xml | 317 +-- packages/SystemUI/res/values-hy/strings_tv.xml | 2 - packages/SystemUI/res/values-in/strings.xml | 315 +-- packages/SystemUI/res/values-in/strings_tv.xml | 2 - packages/SystemUI/res/values-is/strings.xml | 315 +-- packages/SystemUI/res/values-is/strings_tv.xml | 2 - packages/SystemUI/res/values-it/strings.xml | 333 +-- packages/SystemUI/res/values-it/strings_tv.xml | 2 - .../res/values-it/tiles_states_strings.xml | 50 +- packages/SystemUI/res/values-iw/strings.xml | 317 +-- packages/SystemUI/res/values-iw/strings_tv.xml | 2 - packages/SystemUI/res/values-ja/strings.xml | 317 +-- packages/SystemUI/res/values-ja/strings_tv.xml | 2 - packages/SystemUI/res/values-ka/strings.xml | 315 +-- packages/SystemUI/res/values-ka/strings_tv.xml | 2 - packages/SystemUI/res/values-kk/strings.xml | 315 +-- packages/SystemUI/res/values-kk/strings_tv.xml | 2 - packages/SystemUI/res/values-km/strings.xml | 317 +-- packages/SystemUI/res/values-km/strings_tv.xml | 2 - packages/SystemUI/res/values-kn/strings.xml | 315 +-- packages/SystemUI/res/values-kn/strings_tv.xml | 2 - packages/SystemUI/res/values-ko/strings.xml | 315 +-- packages/SystemUI/res/values-ko/strings_tv.xml | 2 - packages/SystemUI/res/values-ky/strings.xml | 315 +-- packages/SystemUI/res/values-ky/strings_tv.xml | 2 - packages/SystemUI/res/values-land/config.xml | 3 - packages/SystemUI/res/values-land/dimens.xml | 6 +- packages/SystemUI/res/values-land/styles.xml | 6 - packages/SystemUI/res/values-lo/strings.xml | 315 +-- packages/SystemUI/res/values-lo/strings_tv.xml | 2 - packages/SystemUI/res/values-lt/strings.xml | 315 +-- packages/SystemUI/res/values-lt/strings_tv.xml | 2 - packages/SystemUI/res/values-lv/strings.xml | 315 +-- packages/SystemUI/res/values-lv/strings_tv.xml | 2 - packages/SystemUI/res/values-mk/strings.xml | 315 +-- packages/SystemUI/res/values-mk/strings_tv.xml | 2 - packages/SystemUI/res/values-ml/strings.xml | 315 +-- packages/SystemUI/res/values-ml/strings_tv.xml | 2 - packages/SystemUI/res/values-mn/strings.xml | 315 +-- packages/SystemUI/res/values-mn/strings_tv.xml | 2 - packages/SystemUI/res/values-mr/strings.xml | 319 +-- packages/SystemUI/res/values-mr/strings_tv.xml | 2 - packages/SystemUI/res/values-ms/strings.xml | 323 +-- packages/SystemUI/res/values-ms/strings_tv.xml | 2 - packages/SystemUI/res/values-my/strings.xml | 325 +-- packages/SystemUI/res/values-my/strings_tv.xml | 2 - packages/SystemUI/res/values-nb/strings.xml | 315 +-- packages/SystemUI/res/values-nb/strings_tv.xml | 2 - packages/SystemUI/res/values-ne/strings.xml | 315 +-- packages/SystemUI/res/values-ne/strings_tv.xml | 2 - packages/SystemUI/res/values-night/colors.xml | 2 +- packages/SystemUI/res/values-night/styles.xml | 10 +- packages/SystemUI/res/values-nl/strings.xml | 315 +-- packages/SystemUI/res/values-nl/strings_tv.xml | 2 - packages/SystemUI/res/values-or/strings.xml | 315 +-- packages/SystemUI/res/values-or/strings_tv.xml | 2 - packages/SystemUI/res/values-pa/strings.xml | 315 +-- packages/SystemUI/res/values-pa/strings_tv.xml | 2 - packages/SystemUI/res/values-pl/strings.xml | 317 +-- packages/SystemUI/res/values-pl/strings_tv.xml | 2 - packages/SystemUI/res/values-pt-rBR/strings.xml | 315 +-- packages/SystemUI/res/values-pt-rBR/strings_tv.xml | 2 - packages/SystemUI/res/values-pt-rPT/strings.xml | 327 +-- packages/SystemUI/res/values-pt-rPT/strings_tv.xml | 2 - packages/SystemUI/res/values-pt/strings.xml | 315 +-- packages/SystemUI/res/values-pt/strings_tv.xml | 2 - packages/SystemUI/res/values-ro/strings.xml | 315 +-- packages/SystemUI/res/values-ro/strings_tv.xml | 2 - packages/SystemUI/res/values-ru/strings.xml | 319 +-- packages/SystemUI/res/values-ru/strings_tv.xml | 2 - packages/SystemUI/res/values-si/strings.xml | 315 +-- packages/SystemUI/res/values-si/strings_tv.xml | 2 - packages/SystemUI/res/values-sk/strings.xml | 315 +-- packages/SystemUI/res/values-sk/strings_tv.xml | 2 - packages/SystemUI/res/values-sl/strings.xml | 315 +-- packages/SystemUI/res/values-sl/strings_tv.xml | 2 - packages/SystemUI/res/values-sq/strings.xml | 315 +-- packages/SystemUI/res/values-sq/strings_tv.xml | 2 - packages/SystemUI/res/values-sr/strings.xml | 327 +-- packages/SystemUI/res/values-sr/strings_tv.xml | 2 - packages/SystemUI/res/values-sv/strings.xml | 315 +-- packages/SystemUI/res/values-sv/strings_tv.xml | 2 - packages/SystemUI/res/values-sw/strings.xml | 315 +-- packages/SystemUI/res/values-sw/strings_tv.xml | 2 - packages/SystemUI/res/values-sw360dp/dimens.xml | 3 - packages/SystemUI/res/values-sw392dp/dimens.xml | 8 - packages/SystemUI/res/values-sw410dp/config.xml | 24 - packages/SystemUI/res/values-sw410dp/dimens.xml | 8 - .../SystemUI/res/values-sw600dp-land/config.xml | 16 + .../SystemUI/res/values-sw600dp-land/dimens.xml | 28 + .../SystemUI/res/values-sw600dp-port/config.xml | 27 + .../SystemUI/res/values-sw600dp-port/dimens.xml | 2 +- packages/SystemUI/res/values-sw600dp/config.xml | 12 +- packages/SystemUI/res/values-sw600dp/dimens.xml | 50 +- packages/SystemUI/res/values-sw600dp/styles.xml | 3 - .../SystemUI/res/values-sw720dp-land/config.xml | 38 + .../SystemUI/res/values-sw720dp-port/config.xml | 33 + packages/SystemUI/res/values-sw720dp/config.xml | 29 - packages/SystemUI/res/values-sw720dp/dimens.xml | 9 - packages/SystemUI/res/values-sw900dp/dimens.xml | 1 - packages/SystemUI/res/values-ta/strings.xml | 315 +-- packages/SystemUI/res/values-ta/strings_tv.xml | 2 - packages/SystemUI/res/values-te/strings.xml | 329 +-- packages/SystemUI/res/values-te/strings_tv.xml | 2 - packages/SystemUI/res/values-th/strings.xml | 315 +-- packages/SystemUI/res/values-th/strings_tv.xml | 2 - packages/SystemUI/res/values-tl/strings.xml | 315 +-- packages/SystemUI/res/values-tl/strings_tv.xml | 2 - packages/SystemUI/res/values-tr/strings.xml | 317 +-- packages/SystemUI/res/values-tr/strings_tv.xml | 2 - packages/SystemUI/res/values-uk/strings.xml | 315 +-- packages/SystemUI/res/values-uk/strings_tv.xml | 2 - packages/SystemUI/res/values-ur/strings.xml | 315 +-- packages/SystemUI/res/values-ur/strings_tv.xml | 2 - packages/SystemUI/res/values-uz/strings.xml | 315 +-- packages/SystemUI/res/values-uz/strings_tv.xml | 2 - packages/SystemUI/res/values-vi/strings.xml | 315 +-- packages/SystemUI/res/values-vi/strings_tv.xml | 2 - packages/SystemUI/res/values-zh-rCN/strings.xml | 315 +-- packages/SystemUI/res/values-zh-rCN/strings_tv.xml | 2 - packages/SystemUI/res/values-zh-rHK/strings.xml | 315 +-- packages/SystemUI/res/values-zh-rHK/strings_tv.xml | 2 - packages/SystemUI/res/values-zh-rTW/strings.xml | 315 +-- packages/SystemUI/res/values-zh-rTW/strings_tv.xml | 2 - packages/SystemUI/res/values-zu/strings.xml | 315 +-- packages/SystemUI/res/values-zu/strings_tv.xml | 2 - packages/SystemUI/res/values/arrays_tv.xml | 22 - packages/SystemUI/res/values/attrs.xml | 1 + packages/SystemUI/res/values/colors.xml | 84 +- packages/SystemUI/res/values/config.xml | 166 +- packages/SystemUI/res/values/dimens.xml | 451 +--- packages/SystemUI/res/values/flags.xml | 30 +- packages/SystemUI/res/values/ids.xml | 6 - packages/SystemUI/res/values/integers.xml | 5 - packages/SystemUI/res/values/internal.xml | 1 - packages/SystemUI/res/values/mland_config.xml | 1 - packages/SystemUI/res/values/mland_strings.xml | 20 - packages/SystemUI/res/values/strings.xml | 722 +---- packages/SystemUI/res/values/strings_tv.xml | 2 - packages/SystemUI/res/values/styles.xml | 172 +- .../SystemUI/res/xml/combined_qs_header_scene.xml | 50 + packages/SystemUI/res/xml/media_collapsed.xml | 4 +- packages/SystemUI/res/xml/qqs_header.xml | 61 + packages/SystemUI/res/xml/qs_header.xml | 62 + packages/SystemUI/res/xml/split_header.xml | 57 + packages/SystemUI/shared/Android.bp | 33 +- .../shared/src/com/android/systemui/flags/Flag.kt | 183 ++ .../src/com/android/systemui/flags/FlagManager.kt | 172 ++ .../src/com/android/systemui/flags/FlagReader.kt | 43 + .../navigationbar/buttons/KeyButtonRipple.java | 531 ++++ .../animation/UnfoldMoveFromCenterAnimator.kt | 175 ++ .../shared/navigationbar/RegionSamplingHelper.java | 302 +++ .../shared/pip/PipSurfaceTransactionHelper.java | 26 +- .../shared/plugins/PluginActionManager.java | 432 +++ .../systemui/shared/plugins/PluginInitializer.java | 45 - .../systemui/shared/plugins/PluginInstance.java | 228 ++ .../shared/plugins/PluginInstanceManager.java | 462 ---- .../systemui/shared/plugins/PluginManager.java | 16 +- .../systemui/shared/plugins/PluginManagerImpl.java | 262 +- .../systemui/shared/plugins/VersionInfo.java | 12 + .../systemui/shared/recents/IOverviewProxy.aidl | 25 +- .../systemui/shared/recents/ISystemUiProxy.aidl | 17 +- .../systemui/shared/recents/model/Task.java | 16 +- .../shared/recents/model/ThumbnailData.java | 19 +- .../shared/recents/utilities/Utilities.java | 76 + .../shared/recents/utilities/ViewRippler.java | 55 + .../shared/rotation/FloatingRotationButton.java | 311 +++ .../FloatingRotationButtonPositionCalculator.kt | 65 + .../rotation/FloatingRotationButtonView.java | 102 + .../systemui/shared/rotation/RotationButton.java | 59 + .../shared/rotation/RotationButtonController.java | 591 ++++ .../shared/system/ActivityManagerWrapper.java | 33 +- .../system/InteractionJankMonitorWrapper.java | 3 +- .../systemui/shared/system/QuickStepContract.java | 25 +- .../system/RecentsAnimationControllerCompat.java | 8 +- .../shared/system/RecentsAnimationListener.java | 6 +- .../system/RemoteAnimationAdapterCompat.java | 77 +- .../shared/system/RemoteAnimationTargetCompat.java | 26 +- .../shared/system/RemoteTransitionCompat.java | 227 +- .../shared/system/WindowManagerWrapper.java | 5 + .../statusbar/policy/CallbackController.java | 54 + .../systemui/unfold/UnfoldTransitionFactory.kt | 79 + .../unfold/UnfoldTransitionProgressProvider.kt | 38 + .../config/ResourceUnfoldTransitionConfig.kt | 47 + .../unfold/config/UnfoldTransitionConfig.kt | 21 + .../FixedTimingTransitionProgressProvider.kt | 117 + ...PhysicsBasedUnfoldTransitionProgressProvider.kt | 207 ++ .../unfold/updates/DeviceFoldStateProvider.kt | 206 ++ .../systemui/unfold/updates/FoldStateProvider.kt | 59 + .../updates/hinge/EmptyHingeAngleProvider.kt | 17 + .../unfold/updates/hinge/HingeAngleProvider.kt | 18 + .../updates/hinge/HingeSensorAngleProvider.kt | 42 + .../unfold/updates/screen/ScreenStatusProvider.kt | 29 + .../util/NaturalRotationUnfoldProgressProvider.kt | 72 + .../util/ScaleAwareTransitionProgressProvider.kt | 50 + .../ScopedUnfoldTransitionProgressProvider.java | 142 + .../android/systemui/flags/FeatureFlagManager.java | 233 ++ .../com/android/systemui/flags/FlagsModule.kt | 35 + .../android/systemui/flags/FeatureFlagManager.java | 93 + .../com/android/systemui/flags/FlagsModule.kt | 22 + .../keyguard/AnimatableClockController.java | 4 - .../com/android/keyguard/AnimatableClockView.java | 50 +- .../com/android/keyguard/CarrierTextManager.java | 12 +- .../com/android/keyguard/KeyguardClockSwitch.java | 110 +- .../keyguard/KeyguardClockSwitchController.java | 120 +- .../com/android/keyguard/KeyguardConstants.java | 4 +- .../keyguard/KeyguardHostViewController.java | 4 + .../keyguard/KeyguardInputViewController.java | 12 +- .../com/android/keyguard/KeyguardListenModel.kt | 3 +- .../com/android/keyguard/KeyguardMessageArea.java | 26 + .../keyguard/KeyguardMessageAreaController.java | 6 + .../src/com/android/keyguard/KeyguardPINView.java | 90 +- .../keyguard/KeyguardPasswordViewController.java | 3 +- .../com/android/keyguard/KeyguardPatternView.java | 21 +- .../keyguard/KeyguardPatternViewController.java | 10 +- .../keyguard/KeyguardPinViewController.java | 16 +- .../keyguard/KeyguardSecurityContainer.java | 207 +- .../KeyguardSecurityContainerController.java | 96 +- .../com/android/keyguard/KeyguardSliceView.java | 89 +- .../keyguard/KeyguardSliceViewController.java | 23 +- .../com/android/keyguard/KeyguardStatusView.java | 2 +- .../keyguard/KeyguardStatusViewController.java | 13 +- .../android/keyguard/KeyguardUnfoldTransition.kt | 113 + .../android/keyguard/KeyguardUpdateMonitor.java | 376 +-- .../keyguard/KeyguardUpdateMonitorCallback.java | 15 +- .../android/keyguard/KeyguardViewController.java | 12 +- .../android/keyguard/KeyguardVisibilityHelper.java | 14 +- .../src/com/android/keyguard/LockIconView.java | 107 +- .../android/keyguard/LockIconViewController.java | 416 +-- .../src/com/android/keyguard/NumPadButton.java | 15 +- .../src/com/android/keyguard/NumPadKey.java | 4 +- .../keyguard/clock/AnalogClockController.java | 2 +- .../keyguard/clock/BubbleClockController.java | 2 +- .../com/android/keyguard/clock/ClockManager.java | 8 +- .../android/keyguard/clock/SmallClockPosition.java | 13 +- .../dagger/KeyguardStatusBarViewComponent.java | 6 +- .../dagger/KeyguardStatusBarViewModule.java | 8 + .../keyguard/dagger/KeyguardStatusViewModule.java | 2 +- .../android/systemui/ActivityStarterDelegate.java | 79 +- .../android/systemui/AutoReinflateContainer.java | 2 +- .../src/com/android/systemui/BatteryMeterView.java | 508 ---- .../src/com/android/systemui/Dependency.java | 46 +- .../systemui/ForegroundServiceController.java | 3 +- .../src/com/android/systemui/ImageWallpaper.java | 17 +- .../src/com/android/systemui/LatencyTester.java | 24 +- .../android/systemui/PluginInflateContainer.java | 4 +- .../com/android/systemui/ScreenDecorations.java | 341 ++- .../src/com/android/systemui/SwipeHelper.java | 102 +- .../src/com/android/systemui/SystemUIFactory.java | 16 +- .../AccessibilityButtonModeObserver.java | 4 +- .../accessibility/MagnificationModeSwitch.java | 3 +- .../SecureSettingsContentObserver.java | 4 +- .../systemui/accessibility/SystemActions.java | 31 +- .../accessibility/WindowMagnification.java | 2 +- .../WindowMagnificationController.java | 113 +- .../floatingmenu/AccessibilityFloatingMenu.java | 4 + .../AccessibilityFloatingMenuController.java | 8 +- .../AccessibilityFloatingMenuView.java | 83 +- .../com/android/systemui/assist/AssistManager.java | 37 +- .../systemui/assist/AssistOrbContainer.java | 157 -- .../systemui/assist/AssistOrbController.java | 182 -- .../com/android/systemui/assist/AssistOrbView.java | 279 -- .../android/systemui/assist/PhoneStateMonitor.java | 7 +- .../android/systemui/battery/BatteryMeterView.java | 403 +++ .../battery/BatteryMeterViewController.java | 203 ++ .../systemui/biometrics/AuthBiometricFaceView.java | 16 +- .../systemui/biometrics/AuthBiometricView.java | 19 +- .../systemui/biometrics/AuthController.java | 196 +- .../systemui/biometrics/AuthPanelController.java | 18 - .../systemui/biometrics/AuthRippleController.kt | 140 +- .../android/systemui/biometrics/AuthRippleView.kt | 187 +- .../biometrics/BiometricDisplayListener.kt | 89 + .../BiometricOrientationEventListener.kt | 57 - .../src/com/android/systemui/biometrics/OWNERS | 1 + .../systemui/biometrics/SidefpsController.java | 239 -- .../systemui/biometrics/SidefpsController.kt | 282 ++ .../android/systemui/biometrics/SidefpsView.java | 107 - .../systemui/biometrics/UdfpsAnimationView.java | 2 +- .../biometrics/UdfpsAnimationViewController.java | 49 +- .../systemui/biometrics/UdfpsBpViewController.java | 9 +- .../systemui/biometrics/UdfpsController.java | 159 +- .../biometrics/UdfpsDialogMeasureAdapter.java | 17 +- .../systemui/biometrics/UdfpsEnrollDrawable.java | 32 +- .../systemui/biometrics/UdfpsEnrollHelper.java | 4 +- .../biometrics/UdfpsEnrollProgressBarDrawable.java | 266 +- .../biometrics/UdfpsEnrollProgressBarSegment.java | 280 -- .../systemui/biometrics/UdfpsEnrollView.java | 3 +- .../biometrics/UdfpsEnrollViewController.java | 9 +- .../biometrics/UdfpsFpmOtherViewController.java | 9 +- .../systemui/biometrics/UdfpsHapticsSimulator.kt | 4 - .../biometrics/UdfpsKeyguardViewController.java | 42 +- .../com/android/systemui/biometrics/UdfpsView.java | 6 +- .../src/com/android/systemui/biometrics/Utils.java | 13 +- .../classifier/BrightLineFalsingManager.java | 2 +- .../systemui/classifier/DiagonalClassifier.java | 5 +- .../systemui/classifier/FalsingCollectorImpl.java | 7 +- .../colorextraction/SysuiColorExtractor.java | 24 +- .../controller/ControlsProviderLifecycleManager.kt | 6 + .../controls/management/ControlsRequestReceiver.kt | 26 +- .../controls/ui/ControlActionCoordinatorImpl.kt | 11 +- .../controls/ui/ControlsUiControllerImpl.kt | 2 +- .../android/systemui/controls/ui/DetailDialog.kt | 28 +- .../systemui/dagger/DefaultActivityBinder.java | 7 - .../systemui/dagger/DependencyProvider.java | 99 +- .../systemui/dagger/FrameworkServicesModule.java | 26 +- .../com/android/systemui/dagger/GlobalModule.java | 7 +- .../systemui/dagger/GlobalRootComponent.java | 7 - .../com/android/systemui/dagger/PluginModule.java | 26 +- .../android/systemui/dagger/SysUIComponent.java | 37 +- .../systemui/dagger/SystemUIDefaultModule.java | 14 +- .../android/systemui/dagger/SystemUIModule.java | 25 +- .../com/android/systemui/dagger/WMComponent.java | 21 +- .../com/android/systemui/dagger/WMSingleton.java | 33 - .../src/com/android/systemui/doze/DozeHost.java | 1 - .../src/com/android/systemui/doze/DozeLog.java | 33 +- .../src/com/android/systemui/doze/DozeLogger.kt | 19 + .../systemui/doze/DozeScreenBrightness.java | 119 +- .../com/android/systemui/doze/DozeScreenState.java | 5 + .../src/com/android/systemui/doze/DozeSensors.java | 432 ++- .../com/android/systemui/doze/DozeTriggers.java | 28 +- .../src/com/android/systemui/doze/DozeUi.java | 73 +- .../android/systemui/doze/dagger/DozeModule.java | 46 +- .../src/com/android/systemui/dump/DumpManager.kt | 13 +- .../src/com/android/systemui/egg/MLand.java | 1440 ---------- .../com/android/systemui/egg/MLandActivity.java | 90 - .../android/systemui/flags/FeatureFlagReader.java | 134 - .../com/android/systemui/flags/FeatureFlags.java | 154 ++ .../src/com/android/systemui/flags/FlagWriter.kt | 21 + .../src/com/android/systemui/flags/Flags.java | 147 + .../systemui/flags/SystemPropertiesHelper.kt | 10 +- .../systemui/fragments/FragmentHostManager.java | 19 +- .../systemui/fragments/FragmentService.java | 60 +- .../globalactions/GlobalActionsDialog.java | 599 ----- .../globalactions/GlobalActionsDialogLite.java | 306 +-- .../systemui/globalactions/GlobalActionsImpl.java | 2 +- .../globalactions/GlobalActionsInfoProvider.kt | 120 - .../glwallpaper/ImageWallpaperRenderer.java | 7 + .../keyguard/FaceAuthScreenBrightnessController.kt | 195 -- ...KeyguardIndicationRotateTextViewController.java | 118 +- .../android/systemui/keyguard/KeyguardService.java | 282 +- .../keyguard/KeyguardUnlockAnimationController.kt | 79 +- .../systemui/keyguard/KeyguardViewMediator.java | 115 +- .../keyguard/LifecycleScreenStatusProvider.kt | 44 + .../android/systemui/keyguard/ScreenLifecycle.java | 8 +- .../systemui/keyguard/WakefulnessLifecycle.java | 13 +- .../systemui/keyguard/dagger/KeyguardModule.java | 42 +- .../src/com/android/systemui/log/LogBuffer.kt | 9 +- .../log/dagger/CollapsedSbFragmentLog.java | 36 + .../systemui/log/dagger/LSShadeTransitionLog.java | 33 + .../com/android/systemui/log/dagger/LogModule.java | 41 + .../systemui/log/dagger/QSFragmentDisableLog.java | 36 + .../systemui/log/dagger/SwipeStatusBarAwayLog.java | 36 + .../systemui/media/KeyguardMediaController.kt | 4 +- .../systemui/media/MediaCarouselController.kt | 207 +- .../android/systemui/media/MediaControlPanel.java | 60 +- .../src/com/android/systemui/media/MediaData.kt | 19 +- .../systemui/media/MediaDataCombineLatest.kt | 5 +- .../com/android/systemui/media/MediaDataFilter.kt | 42 +- .../com/android/systemui/media/MediaDataManager.kt | 69 +- .../android/systemui/media/MediaDeviceManager.kt | 26 +- .../systemui/media/MediaHierarchyManager.kt | 12 +- .../src/com/android/systemui/media/MediaHost.kt | 5 +- .../media/MediaProjectionPermissionActivity.java | 4 +- .../android/systemui/media/MediaResumeListener.kt | 4 +- .../systemui/media/MediaSessionBasedFilter.kt | 5 +- .../android/systemui/media/MediaTimeoutListener.kt | 2 +- .../com/android/systemui/media/PlayerViewHolder.kt | 2 + .../com/android/systemui/media/SeekBarObserver.kt | 21 +- .../android/systemui/media/SmartspaceMediaData.kt | 6 +- .../systemui/media/dialog/MediaOutputAdapter.java | 50 +- .../media/dialog/MediaOutputBaseAdapter.java | 24 +- .../media/dialog/MediaOutputBaseDialog.java | 40 +- .../media/dialog/MediaOutputController.java | 70 +- .../systemui/media/dialog/MediaOutputDialog.java | 9 +- .../media/dialog/MediaOutputDialogFactory.kt | 27 +- .../media/dialog/MediaOutputGroupAdapter.java | 3 - .../media/dialog/MediaOutputGroupDialog.java | 20 +- .../systemui/navigationbar/NavBarHelper.java | 272 ++ .../systemui/navigationbar/NavigationBar.java | 582 ++-- .../navigationbar/NavigationBarController.java | 279 +- .../systemui/navigationbar/NavigationBarView.java | 101 +- .../navigationbar/NavigationModeController.java | 8 +- .../systemui/navigationbar/RotationButton.java | 42 - .../navigationbar/RotationButtonController.java | 569 ---- .../systemui/navigationbar/TaskbarDelegate.java | 412 ++- .../navigationbar/buttons/KeyButtonRipple.java | 510 ---- .../navigationbar/buttons/KeyButtonView.java | 5 +- .../buttons/RotationContextButton.java | 19 +- .../gestural/EdgeBackGestureHandler.java | 8 +- .../gestural/FloatingRotationButton.java | 186 -- .../gestural/NavigationBarEdgePanel.java | 5 +- .../gestural/RegionSamplingHelper.java | 279 -- .../systemui/plugins/PluginDependencyProvider.java | 14 +- .../systemui/plugins/PluginEnablerImpl.java | 8 +- .../systemui/plugins/PluginInitializerImpl.java | 76 - .../android/systemui/plugins/PluginsModule.java | 130 + .../src/com/android/systemui/power/PowerUI.java | 10 +- .../android/systemui/privacy/PrivacyChipBuilder.kt | 2 +- .../com/android/systemui/privacy/PrivacyDialog.kt | 2 - .../android/systemui/qs/FooterActionsController.kt | 218 ++ .../systemui/qs/FooterActionsControllerBuilder.kt | 67 + .../com/android/systemui/qs/FooterActionsView.kt | 158 ++ .../systemui/qs/HeaderPrivacyIconsController.kt | 146 + .../com/android/systemui/qs/PagedTileLayout.java | 29 + .../com/android/systemui/qs/PseudoGridView.java | 19 +- .../src/com/android/systemui/qs/QSAnimator.java | 139 +- .../com/android/systemui/qs/QSContainerImpl.java | 26 +- .../src/com/android/systemui/qs/QSDetail.java | 16 +- .../src/com/android/systemui/qs/QSFooter.java | 5 - .../src/com/android/systemui/qs/QSFooterView.java | 126 +- .../systemui/qs/QSFooterViewController.java | 187 +- .../src/com/android/systemui/qs/QSFragment.java | 139 +- .../systemui/qs/QSFragmentDisableFlagsLogger.kt | 47 + .../src/com/android/systemui/qs/QSPanel.java | 108 +- .../com/android/systemui/qs/QSPanelController.java | 80 +- .../android/systemui/qs/QSPanelControllerBase.java | 24 +- .../android/systemui/qs/QSSquishinessController.kt | 35 + .../src/com/android/systemui/qs/QSTileHost.java | 2 +- .../systemui/qs/QuickQSBrightnessController.kt | 102 + .../src/com/android/systemui/qs/QuickQSPanel.java | 24 +- .../systemui/qs/QuickQSPanelController.java | 48 +- .../android/systemui/qs/QuickStatusBarHeader.java | 81 +- .../qs/QuickStatusBarHeaderController.java | 183 +- .../src/com/android/systemui/qs/SecureSetting.java | 13 +- .../src/com/android/systemui/qs/TileLayout.java | 38 +- .../qs/carrier/QSCarrierGroupController.java | 16 +- .../systemui/qs/customize/QSCustomizer.java | 32 +- .../qs/customize/QSCustomizerController.java | 6 +- .../systemui/qs/customize/TileQueryHelper.java | 2 +- .../android/systemui/qs/dagger/QSFlagsModule.java | 2 +- .../systemui/qs/dagger/QSFragmentComponent.java | 4 + .../systemui/qs/dagger/QSFragmentModule.java | 76 +- .../android/systemui/qs/external/TileServices.java | 8 +- .../systemui/qs/tileimpl/HeightOverrideable.kt | 7 +- .../android/systemui/qs/tileimpl/QSTileViewImpl.kt | 69 +- .../com/android/systemui/qs/tiles/CastTile.java | 46 +- .../android/systemui/qs/tiles/CellularTile.java | 15 +- .../systemui/qs/tiles/ColorInversionTile.java | 7 +- .../android/systemui/qs/tiles/DataSaverTile.java | 40 +- .../systemui/qs/tiles/DeviceControlsTile.kt | 17 +- .../src/com/android/systemui/qs/tiles/DndTile.java | 64 +- .../android/systemui/qs/tiles/InternetTile.java | 29 +- .../systemui/qs/tiles/QuickAccessWalletTile.java | 16 +- .../systemui/qs/tiles/RotationLockTile.java | 70 +- .../systemui/qs/tiles/ScreenRecordTile.java | 50 +- .../android/systemui/qs/tiles/UserDetailView.java | 24 +- .../com/android/systemui/qs/tiles/WifiTile.java | 15 +- .../systemui/qs/tiles/dialog/InternetAdapter.java | 34 +- .../systemui/qs/tiles/dialog/InternetDialog.java | 232 +- .../qs/tiles/dialog/InternetDialogController.java | 204 +- .../qs/tiles/dialog/InternetDialogFactory.kt | 23 +- .../systemui/qs/user/UserSwitchDialogController.kt | 117 + .../systemui/recents/OverviewProxyRecentsImpl.java | 11 +- .../systemui/recents/OverviewProxyService.java | 438 +-- .../systemui/recents/ScreenPinningRequest.java | 18 +- .../systemui/screenrecord/RecordingController.java | 25 +- .../systemui/screenrecord/RecordingService.java | 24 +- .../screenrecord/ScreenInternalAudioRecorder.java | 108 +- .../systemui/screenrecord/ScreenRecordDialog.java | 60 +- .../screenshot/LongScreenshotActivity.java | 9 +- .../systemui/screenshot/ScreenshotController.java | 44 +- .../systemui/screenshot/ScreenshotView.java | 50 +- .../systemui/screenshot/TakeScreenshotService.java | 9 +- .../systemui/sensorprivacy/SensorUseDialog.kt | 5 +- .../sensorprivacy/SensorUseStartedActivity.kt | 8 +- .../settings/brightness/BrightnessController.java | 74 +- .../settings/brightness/BrightnessDialog.java | 14 +- .../settings/brightness/BrightnessMirrorHandler.kt | 46 + .../settings/brightness/BrightnessSlider.java | 251 -- .../brightness/BrightnessSliderController.java | 265 ++ .../settings/brightness/BrightnessSliderView.java | 1 + .../brightness/MirroredBrightnessController.kt | 26 + .../systemui/settings/brightness/ToggleSlider.java | 4 + .../com/android/systemui/statusbar/BlurUtils.kt | 21 +- .../android/systemui/statusbar/CommandQueue.java | 42 +- .../systemui/statusbar/DisableFlagsLogger.kt | 216 ++ .../android/systemui/statusbar/FeatureFlags.java | 115 - .../statusbar/KeyguardIndicationController.java | 213 +- .../android/systemui/statusbar/LightRevealScrim.kt | 100 +- .../LockscreenShadeTransitionController.kt | 132 +- .../NotificationLockscreenUserManagerImpl.java | 45 +- .../statusbar/NotificationMediaManager.java | 71 +- .../statusbar/NotificationRemoteInputManager.java | 655 +++-- .../statusbar/NotificationShadeDepthController.kt | 31 +- .../systemui/statusbar/NotificationShelf.java | 10 +- .../NotificationViewHierarchyManager.java | 17 +- .../systemui/statusbar/OperatorNameView.java | 101 +- .../statusbar/OperatorNameViewController.java | 203 ++ .../systemui/statusbar/PulseExpansionHandler.kt | 26 +- .../systemui/statusbar/RemoteInputController.java | 8 +- .../RemoteInputNotificationRebuilder.java | 141 + .../systemui/statusbar/SmartReplyController.java | 24 +- .../statusbar/StatusBarStateControllerImpl.java | 66 +- .../statusbar/SuperStatusBarViewFactory.java | 139 - .../statusbar/SysuiStatusBarStateController.java | 8 +- .../com/android/systemui/statusbar/UserUtil.java | 4 +- .../statusbar/charging/DwellRippleShader.kt | 145 + .../charging/WiredChargingRippleController.kt | 12 +- .../connectivity/AccessPointController.kt | 93 + .../connectivity/AccessPointControllerImpl.java | 348 +++ .../statusbar/connectivity/CallbackHandler.java | 286 ++ .../statusbar/connectivity/ConnectivityState.kt | 104 + .../statusbar/connectivity/EthernetIcons.java | 26 + .../connectivity/EthernetSignalController.java | 71 + .../connectivity/MobileSignalController.java | 1274 +++++++++ .../systemui/statusbar/connectivity/MobileState.kt | 258 ++ .../statusbar/connectivity/NetworkController.java | 60 + .../connectivity/NetworkControllerImpl.java | 1497 +++++++++++ .../statusbar/connectivity/SignalCallback.kt | 189 ++ .../statusbar/connectivity/SignalController.java | 225 ++ .../systemui/statusbar/connectivity/WifiIcons.java | 135 + .../connectivity/WifiSignalController.java | 339 +++ .../systemui/statusbar/connectivity/WifiState.kt | 87 + .../dagger/StatusBarDependenciesModule.java | 90 +- .../statusbar/events/PrivacyDotViewController.kt | 63 +- .../events/SystemEventChipAnimationController.kt | 11 +- .../events/SystemStatusAnimationScheduler.kt | 2 +- .../gesture/SwipeStatusBarAwayGestureHandler.kt | 152 ++ .../gesture/SwipeStatusBarAwayGestureLogger.kt | 64 + .../lockscreen/LockscreenSmartspaceController.kt | 102 +- .../notification/ExpandAnimationParameters.kt | 6 +- .../notification/NotificationActivityStarter.java | 4 + .../notification/NotificationClicker.java | 10 + .../notification/NotificationEntryManager.java | 126 +- .../notification/NotificationFadeAware.java | 70 + .../NotificationLaunchAnimatorController.kt | 21 +- .../notification/NotificationWakeUpCoordinator.kt | 6 +- .../notification/collection/ListEntry.java | 2 +- .../notification/collection/NotifCollection.java | 62 +- .../notification/collection/NotifPipeline.java | 20 + .../notification/collection/NotificationEntry.java | 2 +- .../notification/collection/ShadeListBuilder.java | 115 +- .../collection/coordinator/AppOpsCoordinator.java | 8 +- .../collection/coordinator/BubbleCoordinator.java | 4 +- .../coordinator/ConversationCoordinator.kt | 11 +- .../coordinator/DeviceProvisionedCoordinator.java | 4 +- .../collection/coordinator/GutsCoordinator.kt | 126 + .../coordinator/GutsCoordinatorLogger.kt | 32 + .../collection/coordinator/HeadsUpCoordinator.java | 27 +- .../HideLocallyDismissedNotifsCoordinator.java | 8 + .../HideNotifsForOtherUsersCoordinator.java | 2 + .../coordinator/KeyguardCoordinator.java | 4 +- .../collection/coordinator/MediaCoordinator.java | 2 + .../collection/coordinator/NotifCoordinators.java | 122 - .../collection/coordinator/NotifCoordinators.kt | 126 + .../coordinator/PreparationCoordinator.java | 1 + .../collection/coordinator/RankingCoordinator.java | 43 +- .../coordinator/RemoteInputCoordinator.kt | 225 ++ .../coordinator/SensitiveContentCoordinator.kt | 105 + .../coordinator/ShadeEventCoordinator.kt | 79 + .../coordinator/ShadeEventCoordinatorLogger.kt | 38 + .../coordinator/SmartspaceDedupingCoordinator.kt | 4 +- .../coordinator/ViewConfigCoordinator.kt | 109 + .../coordinator/VisualStabilityCoordinator.java | 1 + .../coordinator/dagger/CoordinatorsModule.kt | 65 + .../inflation/LowPriorityInflationHelper.java | 2 +- .../collection/init/NotifPipelineInitializer.java | 2 +- .../LegacyNotificationPresenterExtensions.java | 100 + .../legacy/NotificationGroupManagerLegacy.java | 22 +- .../collection/legacy/VisualStabilityManager.java | 5 +- .../collection/listbuilder/NotifSection.kt | 5 +- .../collection/listbuilder/PipelineState.java | 6 +- .../listbuilder/ShadeListBuilderLogger.kt | 9 + .../listbuilder/pluggable/Invalidator.java | 24 + .../listbuilder/pluggable/NotifSectioner.java | 25 +- .../listbuilder/pluggable/Pluggable.java | 3 + .../notifcollection/InternalNotifUpdater.java | 37 + .../notifcollection/NotifCollectionListener.java | 11 + .../notifcollection/NotifCollectionLogger.kt | 20 + .../collection/notifcollection/NotifEvent.kt | 5 +- .../notifcollection/NotifLifetimeExtender.java | 14 +- .../SelfTrackingLifetimeExtender.kt | 113 + .../collection/provider/HighPriorityProvider.java | 2 +- .../collection/render/NodeController.kt | 2 +- .../collection/render/NodeSpecBuilder.kt | 74 + .../collection/render/NotifGutsViewListener.kt | 30 + .../collection/render/NotifGutsViewManager.kt | 24 + .../collection/render/NotifShadeEventSource.kt | 35 + .../collection/render/NotifViewBarn.kt | 10 +- .../collection/render/SectionHeaderController.kt | 12 +- .../collection/render/ShadeViewDiffer.kt | 3 +- .../collection/render/ShadeViewManager.kt | 39 +- .../notification/dagger/NotificationsModule.java | 58 +- .../init/NotificationsControllerImpl.kt | 5 +- .../interruption/HeadsUpController.java | 2 +- .../notification/logging/NotificationLogger.java | 4 + .../logging/NotificationPanelLogger.java | 12 +- .../row/ActivatableNotificationView.java | 71 +- .../row/ExpandableNotificationRow.java | 283 +- .../row/ExpandableNotificationRowController.java | 11 +- .../ExpandableNotificationRowDragController.java | 171 ++ .../statusbar/notification/row/ExpandableView.java | 11 + .../statusbar/notification/row/FooterView.java | 17 + .../row/HybridConversationNotificationView.java | 11 + .../notification/row/HybridNotificationView.java | 6 +- .../row/NotificationContentInflater.java | 2 +- .../notification/row/NotificationContentView.java | 58 +- .../notification/row/NotificationGutsManager.java | 69 +- .../notification/row/NotificationMenuRow.java | 14 +- .../notification/row/NotificationSnooze.java | 3 +- .../wrapper/NotificationCallTemplateViewWrapper.kt | 14 + .../NotificationConversationTemplateViewWrapper.kt | 10 + .../row/wrapper/NotificationCustomViewWrapper.java | 11 + .../NotificationDecoratedCustomViewWrapper.java | 11 + .../row/wrapper/NotificationViewWrapper.java | 10 + .../statusbar/notification/stack/AmbientState.java | 56 +- .../stack/NotificationChildrenContainer.java | 21 +- .../stack/NotificationPriorityBucket.kt | 25 + .../stack/NotificationRoundnessManager.java | 12 +- .../notification/stack/NotificationSection.java | 2 +- .../stack/NotificationSectionsManager.kt | 25 +- .../stack/NotificationStackScrollLayout.java | 377 +-- .../NotificationStackScrollLayoutController.java | 134 +- .../stack/NotificationSwipeHelper.java | 4 +- .../notification/stack/SectionHeaderView.java | 8 +- .../notification/stack/StackScrollAlgorithm.java | 42 +- .../notification/stack/StackStateAnimator.java | 4 +- .../statusbar/notification/stack/ViewState.java | 29 +- .../statusbar/phone/AutoHideController.java | 24 +- .../statusbar/phone/BiometricUnlockController.java | 48 +- .../phone/CollapsedStatusBarFragment.java | 556 ---- .../statusbar/phone/ConfigurationControllerImpl.kt | 12 +- .../statusbar/phone/DarkIconDispatcherImpl.java | 8 +- .../systemui/statusbar/phone/DemoStatusIcons.java | 2 +- .../systemui/statusbar/phone/DozeParameters.java | 110 +- .../statusbar/phone/DozeScrimController.java | 15 +- .../systemui/statusbar/phone/DozeServiceHost.java | 16 +- .../phone/HeadsUpAppearanceController.java | 106 +- .../statusbar/phone/HeadsUpManagerPhone.java | 8 +- .../statusbar/phone/KeyguardBottomAreaView.java | 51 +- .../systemui/statusbar/phone/KeyguardBouncer.java | 34 +- .../statusbar/phone/KeyguardBypassController.kt | 38 +- .../phone/KeyguardClockPositionAlgorithm.java | 122 +- .../phone/KeyguardIndicationTextView.java | 184 +- .../statusbar/phone/KeyguardStatusBarView.java | 200 +- .../phone/KeyguardStatusBarViewController.java | 430 ++- .../statusbar/phone/LSShadeTransitionLogger.kt | 183 ++ .../statusbar/phone/LightBarController.java | 60 +- .../phone/LightBarTransitionsController.java | 9 + .../statusbar/phone/LightsOutNotifController.java | 7 +- .../statusbar/phone/LockscreenGestureLogger.java | 6 +- .../statusbar/phone/LockscreenWallpaper.java | 15 - .../statusbar/phone/MultiUserSwitchController.java | 59 +- .../phone/NotificationIconAreaController.java | 4 + .../phone/NotificationPanelViewController.java | 915 ++++--- .../NotificationShadeWindowControllerImpl.java | 9 +- .../NotificationShadeWindowViewController.java | 35 +- .../phone/NotificationsQSContainerController.kt | 141 + .../phone/NotificationsQuickSettingsContainer.java | 126 +- .../android/systemui/statusbar/phone/PanelBar.java | 263 -- .../statusbar/phone/PanelExpansionListener.java | 38 - .../systemui/statusbar/phone/PanelView.java | 2 +- .../statusbar/phone/PanelViewController.java | 158 +- .../statusbar/phone/PhoneStatusBarPolicy.java | 3 +- .../statusbar/phone/PhoneStatusBarView.java | 218 +- .../phone/PhoneStatusBarViewController.kt | 134 + .../systemui/statusbar/phone/ScrimController.java | 172 +- .../systemui/statusbar/phone/ScrimState.java | 95 +- .../systemui/statusbar/phone/SettingsButton.java | 3 + .../statusbar/phone/ShadeControllerImpl.java | 15 +- .../statusbar/phone/SplitShadeHeaderController.kt | 210 ++ .../systemui/statusbar/phone/StatusBar.java | 2312 ++++++---------- .../phone/StatusBarCommandQueueCallbacks.java | 640 +++++ .../phone/StatusBarContentInsetsProvider.kt | 250 +- .../statusbar/phone/StatusBarDemoMode.java | 143 + .../phone/StatusBarHeadsUpChangeListener.java | 134 + .../phone/StatusBarHideIconsForBouncerManager.kt | 133 + .../statusbar/phone/StatusBarIconController.java | 19 +- .../phone/StatusBarIconControllerImpl.java | 22 +- .../phone/StatusBarKeyguardViewManager.java | 102 +- .../phone/StatusBarLaunchAnimatorController.kt | 6 +- .../StatusBarMoveFromCenterAnimationController.kt | 68 + .../StatusBarNotificationActivityStarter.java | 73 +- .../phone/StatusBarNotificationPresenter.java | 146 +- .../statusbar/phone/StatusBarSignalPolicy.java | 41 +- .../phone/StatusBarTouchableRegionManager.java | 6 +- .../statusbar/phone/StatusBarWindowCallback.java | 3 +- .../statusbar/phone/StatusBarWindowController.java | 217 -- .../statusbar/phone/StatusBarWindowView.java | 196 -- .../systemui/statusbar/phone/SystemUIDialog.java | 188 +- .../statusbar/phone/SystemUIDialogManager.java | 118 + .../statusbar/phone/TapAgainViewController.java | 5 - .../phone/UnlockedScreenOffAnimationController.kt | 36 +- .../statusbar/phone/dagger/StatusBarComponent.java | 72 +- .../phone/dagger/StatusBarPhoneModule.java | 93 +- .../phone/dagger/StatusBarViewModule.java | 217 +- .../phone/fragment/CollapsedStatusBarFragment.java | 607 +++++ .../fragment/CollapsedStatusBarFragmentLogger.kt | 63 + .../dagger/StatusBarFragmentComponent.java | 81 + .../fragment/dagger/StatusBarFragmentModule.java | 60 + .../fragment/dagger/StatusBarFragmentScope.java | 32 + .../phone/ongoingcall/OngoingCallController.kt | 144 +- .../phone/panelstate/PanelExpansionListener.java | 31 + .../phone/panelstate/PanelExpansionStateManager.kt | 160 ++ .../phone/panelstate/PanelStateListener.kt | 23 + .../policy/AccessPointControllerImpl.java | 347 --- .../policy/AccessibilityManagerWrapper.java | 5 +- .../policy/BrightnessMirrorController.java | 13 +- .../statusbar/policy/CallbackController.java | 54 - .../systemui/statusbar/policy/CallbackHandler.java | 290 -- .../statusbar/policy/ConfigurationController.java | 2 +- .../statusbar/policy/DevicePostureController.java | 79 + .../policy/DevicePostureControllerImpl.java | 94 + .../policy/DeviceProvisionedController.java | 45 +- .../policy/DeviceProvisionedControllerImpl.java | 149 -- .../policy/DeviceProvisionedControllerImpl.kt | 230 ++ .../DeviceStateRotationLockSettingController.java | 239 ++ .../systemui/statusbar/policy/EthernetIcons.java | 26 - .../statusbar/policy/EthernetSignalController.java | 74 - .../statusbar/policy/ExtensionControllerImpl.java | 3 +- .../statusbar/policy/FlashlightControllerImpl.java | 4 +- .../systemui/statusbar/policy/HeadsUpManager.java | 15 +- .../statusbar/policy/HotspotControllerImpl.java | 9 +- .../policy/KeyguardQsUserSwitchController.java | 16 +- .../statusbar/policy/KeyguardStateController.java | 6 + .../policy/KeyguardStateControllerImpl.java | 12 +- .../policy/KeyguardUserSwitcherController.java | 4 + .../policy/KeyguardUserSwitcherListView.java | 16 +- .../statusbar/policy/MobileSignalController.java | 1287 --------- .../statusbar/policy/NetworkControllerImpl.java | 1462 ---------- .../policy/RemoteInputQuickSettingsDisabler.java | 86 - .../policy/RemoteInputQuickSettingsDisabler.kt | 95 + .../systemui/statusbar/policy/RemoteInputView.java | 67 +- .../statusbar/policy/RotationLockController.java | 1 - .../policy/RotationLockControllerImpl.java | 76 +- .../statusbar/policy/SecurityControllerImpl.java | 6 +- .../policy/SensorPrivacyControllerImpl.java | 3 +- .../statusbar/policy/SignalController.java | 228 -- .../systemui/statusbar/policy/SmartReplyView.java | 90 +- .../statusbar/policy/UserSwitcherController.java | 95 +- .../systemui/statusbar/policy/WifiIcons.java | 134 - .../statusbar/policy/WifiSignalController.java | 400 --- .../statusbar/policy/ZenModeControllerImpl.java | 10 +- .../policy/dagger/StatusBarPolicyModule.java | 33 +- .../window/StatusBarWindowController.java | 318 +++ .../statusbar/window/StatusBarWindowModule.kt | 47 + .../statusbar/window/StatusBarWindowView.java | 103 + .../systemui/theme/ThemeOverlayController.java | 206 +- .../com/android/systemui/toast/SystemUIToast.java | 4 +- .../com/android/systemui/tracing/ProtoTracer.java | 11 +- .../com/android/systemui/tuner/PluginFragment.java | 8 +- .../com/android/systemui/tv/TvSystemUIModule.java | 14 +- .../src/com/android/systemui/tv/TvWMComponent.java | 4 +- .../android/systemui/unfold/SysUIUnfoldModule.kt | 84 + .../unfold/UnfoldLightRevealOverlayAnimation.kt | 270 ++ .../systemui/unfold/UnfoldProgressProvider.kt | 49 + .../systemui/unfold/UnfoldTransitionModule.kt | 111 + .../unfold/UnfoldTransitionWallpaperController.kt | 45 + .../systemui/util/AlphaTintDrawableWrapper.java | 6 + .../src/com/android/systemui/util/DumpUtils.kt | 75 + .../util/InjectionInflationController.java | 120 - .../src/com/android/systemui/util/ListenerSet.kt | 47 + .../systemui/util/NotificationChannels.java | 30 +- .../systemui/util/RoundedCornerProgressDrawable.kt | 8 + .../src/com/android/systemui/util/TraceUtils.kt | 32 + .../src/com/android/systemui/util/Utils.java | 48 +- .../android/systemui/util/WallpaperController.kt | 76 + .../util/concurrency/GlobalConcurrencyModule.java | 22 + .../systemui/util/concurrency/MessageRouter.java | 198 ++ .../util/concurrency/MessageRouterImpl.java | 186 ++ .../util/concurrency/SysUIConcurrencyModule.java | 26 +- .../android/systemui/util/dagger/UtilModule.java | 5 +- .../android/systemui/util/kotlin/nullability.kt | 7 + .../android/systemui/util/leak/GarbageMonitor.java | 65 +- .../android/systemui/util/leak/LeakDetector.java | 20 +- .../sensors/PostureDependentProximitySensor.java | 108 + .../systemui/util/sensors/ProximityCheck.java | 90 + .../systemui/util/sensors/ProximitySensor.java | 395 +-- .../systemui/util/sensors/ProximitySensorImpl.java | 361 +++ .../systemui/util/sensors/SensorModule.java | 171 +- .../systemui/util/sensors/ThresholdSensor.java | 42 +- .../util/sensors/ThresholdSensorEvent.java | 49 + .../systemui/util/sensors/ThresholdSensorImpl.java | 49 +- .../systemui/util/wrapper/RotationPolicyWrapper.kt | 67 + .../systemui/util/wrapper/UtilWrapperModule.kt | 29 + .../systemui/volume/VolumeDialogComponent.java | 31 +- .../android/systemui/volume/VolumeDialogImpl.java | 43 +- .../systemui/volume/dagger/VolumeModule.java | 36 + .../systemui/wallet/ui/WalletCardCarousel.java | 13 +- .../systemui/wallet/ui/WalletScreenController.java | 3 +- .../com/android/systemui/wallet/ui/WalletView.java | 6 +- .../android/systemui/wmshell/BubblesManager.java | 35 +- .../com/android/systemui/wmshell/TvPipModule.java | 165 -- .../android/systemui/wmshell/TvWMShellModule.java | 94 - .../src/com/android/systemui/wmshell/WMShell.java | 82 +- .../systemui/wmshell/WMShellBaseModule.java | 494 ---- .../systemui/wmshell/WMShellConcurrencyModule.java | 163 -- .../android/systemui/wmshell/WMShellModule.java | 244 -- .../KeyguardClockSwitchControllerTest.java | 63 +- .../android/keyguard/KeyguardClockSwitchTest.java | 36 + .../android/keyguard/KeyguardListenQueueTest.kt | 3 +- .../keyguard/KeyguardPatternViewControllerTest.kt | 5 +- .../KeyguardSecurityContainerControllerTest.java | 157 +- .../keyguard/KeyguardSecurityContainerTest.java | 114 +- .../android/keyguard/KeyguardSliceViewTest.java | 2 +- .../keyguard/KeyguardUnfoldTransitionTest.kt | 149 ++ .../keyguard/KeyguardUpdateMonitorTest.java | 76 +- .../android/keyguard/clock/ClockManagerTest.java | 6 +- .../keyguard/clock/SmallClockPositionTest.kt | 2 +- .../android/systemui/ScreenDecorationsTest.java | 918 ++++--- .../com/android/systemui/TestableDependency.java | 5 - .../accessibility/MagnificationModeSwitchTest.java | 24 + .../accessibility/TestableWindowManager.java | 22 +- .../WindowMagnificationControllerTest.java | 110 +- .../AccessibilityFloatingMenuControllerTest.java | 7 +- .../AccessibilityFloatingMenuViewTest.java | 81 +- .../floatingmenu/BaseTooltipViewTest.java | 10 + .../floatingmenu/DockTooltipViewTest.java | 10 + .../floatingmenu/ItemDelegateCompatTest.java | 8 + .../animation/ActivityLaunchAnimatorTest.kt | 13 +- .../systemui/animation/DialogLaunchAnimatorTest.kt | 177 ++ .../GhostedViewLaunchAnimatorControllerTest.kt | 2 +- .../com/android/systemui/animation/TestValues.kt | 23 + .../battery/BatteryMeterViewControllerTest.java | 133 + .../systemui/battery/BatteryMeterViewTest.kt | 71 + .../AuthBiometricFaceToFingerprintViewTest.java | 11 +- .../systemui/biometrics/AuthBiometricViewTest.java | 2 + .../systemui/biometrics/AuthControllerTest.java | 88 +- .../biometrics/AuthRippleControllerTest.kt | 27 +- .../systemui/biometrics/SidefpsControllerTest.kt | 215 +- .../systemui/biometrics/UdfpsControllerTest.java | 119 +- .../biometrics/UdfpsDialogMeasureAdapterTest.java | 11 +- .../UdfpsKeyguardViewControllerTest.java | 33 +- .../classifier/BrightLineFalsingManagerTest.java | 6 +- .../colorextraction/SysuiColorExtractorTests.java | 21 +- .../ControlsProviderLifecycleManagerTest.kt | 50 +- .../management/ControlsRequestReceiverTest.kt | 22 + .../systemui/controls/ui/DetailDialogTest.kt | 71 + .../systemui/doze/DozeConfigurationUtil.java | 6 +- .../systemui/doze/DozeScreenBrightnessTest.java | 218 +- .../com/android/systemui/doze/DozeSensorsTest.java | 253 +- .../android/systemui/doze/DozeTriggersTest.java | 17 +- .../src/com/android/systemui/doze/DozeUiTest.java | 94 +- .../systemui/flags/FeatureFlagManagerTest.java | 123 + .../systemui/flags/FeatureFlagReaderTest.java | 143 - .../src/com/android/systemui/flags/FlagsTest.java | 119 + .../systemui/fragments/FragmentServiceTest.kt | 82 + .../globalactions/GlobalActionsDialogLiteTest.java | 134 +- .../globalactions/GlobalActionsDialogTest.java | 575 ---- .../globalactions/GlobalActionsInfoProviderTest.kt | 134 - .../keyguard/AnimatableClockControllerTest.java | 4 - .../FaceAuthScreenBrightnessControllerTest.kt | 137 - ...uardIndicationRotateTextViewControllerTest.java | 43 +- .../KeyguardUnlockAnimationControllerTest.kt | 134 + .../keyguard/KeyguardViewMediatorTest.java | 52 + .../keyguard/LockIconViewControllerTest.java | 251 +- .../systemui/keyguard/ScreenLifecycleTest.java | 3 +- .../keyguard/WakefulnessLifecycleTest.java | 5 +- .../systemui/media/KeyguardMediaControllerTest.kt | 10 +- .../systemui/media/MediaCarouselControllerTest.kt | 191 ++ .../systemui/media/MediaControlPanelTest.kt | 9 +- .../systemui/media/MediaDataCombineLatestTest.java | 49 +- .../android/systemui/media/MediaDataFilterTest.kt | 50 +- .../android/systemui/media/MediaDataManagerTest.kt | 95 +- .../systemui/media/MediaDeviceManagerTest.kt | 23 +- .../systemui/media/MediaHierarchyManagerTest.kt | 7 +- .../android/systemui/media/MediaPlayerDataTest.kt | 20 +- .../systemui/media/MediaResumeListenerTest.kt | 18 +- .../systemui/media/MediaSessionBasedFilterTest.kt | 33 +- .../android/systemui/media/SeekBarObserverTest.kt | 4 + .../media/dialog/MediaOutputAdapterTest.java | 19 +- .../media/dialog/MediaOutputBaseDialogTest.java | 8 +- .../media/dialog/MediaOutputControllerTest.java | 18 +- .../media/dialog/MediaOutputDialogTest.java | 12 +- .../media/dialog/MediaOutputGroupAdapterTest.java | 5 - .../media/dialog/MediaOutputGroupDialogTest.java | 9 +- .../android/systemui/monet/ColorSchemeTest.java | 103 + .../systemui/navigationbar/NavBarHelperTest.java | 182 ++ .../navigationbar/NavigationBarControllerTest.java | 67 +- .../NavigationBarRotationContextTest.java | 51 +- .../systemui/navigationbar/NavigationBarTest.java | 177 +- ...FloatingRotationButtonPositionCalculatorTest.kt | 128 + .../com/android/systemui/power/PowerUITest.java | 8 +- .../systemui/qs/FooterActionsControllerTest.kt | 125 + .../qs/HeaderPrivacyIconsControllerTest.kt | 128 + .../systemui/qs/QSFooterViewControllerTest.java | 91 +- .../qs/QSFragmentDisableFlagsLoggerTest.kt | 57 + .../com/android/systemui/qs/QSFragmentTest.java | 18 +- .../systemui/qs/QSPanelControllerBaseTest.java | 18 +- .../android/systemui/qs/QSPanelControllerTest.java | 16 +- .../src/com/android/systemui/qs/QSPanelTest.java | 176 -- .../src/com/android/systemui/qs/QSPanelTest.kt | 167 ++ .../systemui/qs/QSSquishinessControllerTest.kt | 48 + .../com/android/systemui/qs/QSTileHostTest.java | 2 +- .../systemui/qs/QuickQSBrightnessControllerTest.kt | 118 + .../systemui/qs/QuickQSPanelControllerTest.kt | 31 +- .../qs/QuickStatusBarHeaderControllerTest.kt | 114 +- .../qs/carrier/QSCarrierGroupControllerTest.java | 18 +- .../systemui/qs/customize/TileQueryHelperTest.java | 2 +- .../systemui/qs/external/TileServicesTest.java | 14 +- .../android/systemui/qs/tiles/CastTileTest.java | 34 +- .../systemui/qs/tiles/ColorInversionTileTest.java | 116 + .../systemui/qs/tiles/DeviceControlsTileTest.kt | 64 +- .../com/android/systemui/qs/tiles/DndTileTest.kt | 192 ++ .../qs/tiles/QuickAccessWalletTileTest.java | 7 +- .../systemui/qs/tiles/RotationLockTileTest.java | 209 -- .../systemui/qs/tiles/ScreenRecordTileTest.java | 23 +- .../qs/tiles/dialog/InternetAdapterTest.java | 58 +- .../tiles/dialog/InternetDialogControllerTest.java | 204 +- .../qs/tiles/dialog/InternetDialogTest.java | 229 +- .../qs/user/UserSwitchDialogControllerTest.kt | 152 ++ .../screenrecord/RecordingControllerTest.java | 5 +- .../screenrecord/RecordingServiceTest.java | 4 +- .../brightness/BrightnessSliderControllerTest.kt | 218 ++ .../settings/brightness/BrightnessSliderTest.kt | 227 -- .../animation/UnfoldMoveFromCenterAnimatorTest.kt | 239 ++ .../shared/plugins/PluginActionManagerTest.java | 308 +++ .../shared/plugins/PluginInstanceManagerTest.java | 338 --- .../shared/plugins/PluginInstanceTest.java | 138 + .../systemui/shared/plugins/PluginManagerTest.java | 119 +- .../android/systemui/statusbar/BlurUtilsTest.kt | 27 +- .../systemui/statusbar/CommandQueueTest.java | 27 +- .../systemui/statusbar/DisableFlagsLoggerTest.kt | 205 ++ .../KeyguardIndicationControllerTest.java | 73 +- .../statusbar/LSShadeTransitionLoggerTest.kt | 44 + .../LockscreenShadeTransitionControllerTest.kt | 45 +- .../NotificationLockscreenUserManagerTest.java | 12 +- .../NotificationRemoteInputManagerTest.java | 196 +- .../NotificationShadeDepthControllerTest.kt | 105 +- .../NotificationViewHierarchyManagerTest.java | 8 +- .../android/systemui/statusbar/RankingBuilder.java | 10 +- .../RemoteInputNotificationRebuilderTest.java | 174 ++ .../statusbar/SmartReplyControllerTest.java | 19 +- .../statusbar/StatusBarStateControllerImplTest.kt | 4 +- .../charging/WiredChargingRippleControllerTest.kt | 2 +- .../connectivity/AccessPointControllerImplTest.kt | 229 ++ .../connectivity/CallbackHandlerTest.java | 199 ++ .../statusbar/connectivity/MobileStateTest.java | 137 + .../connectivity/NetworkControllerBaseTest.java | 652 +++++ .../connectivity/NetworkControllerDataTest.java | 326 +++ .../NetworkControllerEthernetTest.java | 67 + .../connectivity/NetworkControllerSignalTest.java | 699 +++++ .../connectivity/NetworkControllerWifiTest.java | 414 +++ .../LockscreenSmartspaceControllerTest.kt | 103 +- .../notification/NotificationEntryManagerTest.java | 32 +- .../notification/NotificationFilterTest.java | 4 +- .../notification/VisualStabilityManagerTest.java | 4 +- .../statusbar/notification/collection/EntryUtil.kt | 4 + .../collection/NotifCollectionTest.java | 92 +- .../collection/ShadeListBuilderTest.java | 66 +- .../collection/coordinator/GutsCoordinatorTest.kt | 117 + .../coordinator/HeadsUpCoordinatorTest.java | 5 +- .../coordinator/RankingCoordinatorTest.java | 36 +- .../coordinator/RemoteInputCoordinatorTest.kt | 145 + .../coordinator/SensitiveContentCoordinatorTest.kt | 209 ++ .../coordinator/ShadeEventCoordinatorTest.kt | 106 + .../SelfTrackingLifetimeExtenderTest.kt | 230 ++ .../collection/render/NodeSpecBuilderTest.kt | 323 +++ ...xpandableNotificationRowDragControllerTest.java | 114 + .../row/NotificationEntryManagerInflationTest.java | 14 +- .../row/NotificationGutsManagerTest.java | 15 +- .../notification/row/NotificationTestHelper.java | 26 +- .../stack/NotificationRoundnessManagerTest.java | 6 +- .../stack/NotificationSectionsManagerTest.java | 13 +- ...otificationStackScrollLayoutControllerTest.java | 454 ++++ .../stack/NotificationStackScrollLayoutTest.java | 105 +- .../NotificationStackScrollerControllerTest.java | 416 --- .../stack/NotificationSwipeHelperTest.java | 12 +- .../notification/stack/StackScrollAlgorithmTest.kt | 79 + .../phone/BiometricsUnlockControllerTest.java | 29 +- .../phone/CollapsedStatusBarFragmentTest.java | 273 -- .../statusbar/phone/DozeParametersTest.java | 184 +- .../statusbar/phone/DozeScrimControllerTest.java | 6 +- .../statusbar/phone/DozeServiceHostTest.java | 4 +- .../phone/HeadsUpAppearanceControllerTest.java | 23 +- .../statusbar/phone/KeyguardBottomAreaTest.kt | 4 +- .../phone/KeyguardClockPositionAlgorithmTest.java | 164 +- .../phone/KeyguardStatusBarViewControllerTest.java | 387 +++ .../statusbar/phone/KeyguardStatusBarViewTest.java | 59 + .../statusbar/phone/LightBarControllerTest.java | 9 +- .../phone/LightsOutNotifControllerTest.java | 15 +- .../NotificationGroupAlertTransferHelperTest.java | 4 +- .../phone/NotificationGroupManagerLegacyTest.java | 70 +- .../phone/NotificationIconAreaControllerTest.java | 1 + .../phone/NotificationPanelViewControllerTest.java | 224 +- .../phone/NotificationQSContainerControllerTest.kt | 254 ++ .../phone/NotificationShadeWindowViewTest.java | 14 +- .../phone/PhoneStatusBarViewControllerTest.kt | 140 + .../statusbar/phone/PhoneStatusBarViewTest.kt | 114 + .../statusbar/phone/ScrimControllerTest.java | 217 +- .../phone/SplitShadeHeaderControllerTest.kt | 119 + .../phone/StatusBarCommandQueueCallbacksTest.java | 177 ++ .../phone/StatusBarContentInsetsProviderTest.kt | 196 +- .../phone/StatusBarIconControllerTest.java | 2 +- .../phone/StatusBarKeyguardViewManagerTest.java | 181 +- ...atusBarMoveFromCenterAnimationControllerTest.kt | 104 + .../StatusBarNotificationActivityStarterTest.java | 38 +- .../phone/StatusBarNotificationPresenterTest.java | 48 +- .../systemui/statusbar/phone/StatusBarTest.java | 171 +- .../UnlockedScreenOffAnimationControllerTest.kt | 169 ++ .../CollapsedStatusBarFragmentLoggerTest.kt | 57 + .../fragment/CollapsedStatusBarFragmentTest.java | 381 +++ .../phone/ongoingcall/OngoingCallControllerTest.kt | 167 +- .../panelstate/PanelExpansionStateManagerTest.kt | 213 ++ .../policy/AccessPointControllerImplTest.kt | 229 -- .../statusbar/policy/CallbackHandlerTest.java | 203 -- .../policy/DeviceProvisionedControllerImplTest.kt | 241 ++ ...viceStateRotationLockSettingControllerTest.java | 239 ++ .../policy/ExtensionControllerImplTest.java | 8 +- .../statusbar/policy/FiveGServiceClientTest.java | 3 +- .../policy/HotspotControllerImplTest.java | 5 +- .../policy/KeyguardStateControllerTest.java | 11 +- .../policy/NetworkControllerBaseTest.java | 656 ----- .../policy/NetworkControllerDataTest.java | 310 --- .../policy/NetworkControllerEthernetTest.java | 53 - .../policy/NetworkControllerSignalTest.java | 627 ----- .../policy/NetworkControllerWifiTest.java | 385 --- .../RemoteInputQuickSettingsDisablerTest.java | 95 - .../policy/RemoteInputQuickSettingsDisablerTest.kt | 135 + .../statusbar/policy/RemoteInputViewTest.java | 2 +- .../policy/RotationLockControllerImplTest.java | 113 + .../statusbar/policy/SecurityControllerTest.java | 5 +- .../statusbar/policy/UserSwitcherControllerTest.kt | 140 +- .../policy/ZenModeControllerImplTest.java | 10 +- .../systemui/theme/ThemeOverlayControllerTest.java | 207 +- .../com/android/systemui/toast/ToastUITest.java | 2 +- .../unfold/TestUnfoldTransitionProvider.kt | 32 + .../UnfoldTransitionWallpaperControllerTest.kt | 51 + .../unfold/updates/DeviceFoldStateProviderTest.kt | 296 ++ .../NaturalRotationUnfoldProgressProviderTest.kt | 139 + .../util/ScaleAwareUnfoldProgressProviderTest.kt | 139 + .../systemui/usb/UsbPermissionActivityTest.kt | 5 +- .../com/android/systemui/util/ChannelsTest.java | 48 - .../com/android/systemui/util/ListenerSetTest.kt | 135 + .../systemui/util/WallpaperControllerTest.kt | 145 + .../util/concurrency/MessageRouterImplTest.java | 371 +++ .../systemui/util/leak/GarbageMonitorTest.java | 115 +- .../systemui/util/leak/LeakDetectorTest.java | 6 +- .../systemui/util/mockito/KotlinMockitoHelpers.kt | 21 + .../systemui/util/sensors/FakeProximitySensor.java | 17 +- .../systemui/util/sensors/FakeSensorManager.java | 8 +- .../systemui/util/sensors/FakeThresholdSensor.java | 10 + .../PostureDependentProximitySensorTest.java | 114 + .../systemui/util/sensors/ProximityCheckTest.java | 10 +- .../util/sensors/ProximitySensorDualTest.java | 443 --- .../util/sensors/ProximitySensorImplDualTest.java | 443 +++ .../sensors/ProximitySensorImplSingleTest.java | 244 ++ .../util/sensors/ProximitySensorSingleTest.java | 244 -- .../util/sensors/ThresholdSensorImplTest.java | 2 +- .../systemui/util/settings/FakeSettings.java | 4 +- .../systemui/util/settings/FakeSettingsTest.java | 21 +- .../utils/leaks/FakeNetworkController.java | 5 +- .../systemui/utils/leaks/FakePluginManager.java | 22 +- .../utils/leaks/FakeRotationLockController.java | 5 - .../systemui/utils/leaks/LeakCheckedTest.java | 2 +- .../systemui/volume/VolumeDialogImplTest.java | 41 +- .../wallet/ui/WalletScreenControllerTest.java | 11 +- .../com/android/systemui/wmshell/BubblesTest.java | 192 +- .../wmshell/NewNotifPipelineBubblesTest.java | 215 +- .../systemui/wmshell/TestableBubbleController.java | 6 +- .../com/android/systemui/wmshell/WMShellTest.java | 33 +- packages/VpnDialogs/res/values-ar/strings.xml | 3 +- packages/VpnDialogs/res/values-as/strings.xml | 7 +- packages/VpnDialogs/res/values-az/strings.xml | 3 +- packages/VpnDialogs/res/values-be/strings.xml | 3 +- packages/VpnDialogs/res/values-bn/strings.xml | 3 +- packages/VpnDialogs/res/values-ca/strings.xml | 3 +- packages/VpnDialogs/res/values-et/strings.xml | 3 +- packages/VpnDialogs/res/values-eu/strings.xml | 4 +- packages/VpnDialogs/res/values-fa/strings.xml | 3 +- packages/VpnDialogs/res/values-fr/strings.xml | 3 +- packages/VpnDialogs/res/values-gu/strings.xml | 5 +- packages/VpnDialogs/res/values-hi/strings.xml | 3 +- packages/VpnDialogs/res/values-hu/strings.xml | 3 +- packages/VpnDialogs/res/values-hy/strings.xml | 3 +- packages/VpnDialogs/res/values-in/strings.xml | 10 +- packages/VpnDialogs/res/values-is/strings.xml | 3 +- packages/VpnDialogs/res/values-iw/strings.xml | 3 +- packages/VpnDialogs/res/values-kk/strings.xml | 3 +- packages/VpnDialogs/res/values-kn/strings.xml | 3 +- packages/VpnDialogs/res/values-ky/strings.xml | 3 +- packages/VpnDialogs/res/values-lt/strings.xml | 3 +- packages/VpnDialogs/res/values-lv/strings.xml | 3 +- packages/VpnDialogs/res/values-ml/strings.xml | 3 +- packages/VpnDialogs/res/values-mr/strings.xml | 3 +- packages/VpnDialogs/res/values-my/strings.xml | 3 +- packages/VpnDialogs/res/values-nb/strings.xml | 3 +- packages/VpnDialogs/res/values-ne/strings.xml | 3 +- packages/VpnDialogs/res/values-or/strings.xml | 3 +- packages/VpnDialogs/res/values-pl/strings.xml | 3 +- packages/VpnDialogs/res/values-sl/strings.xml | 3 +- packages/VpnDialogs/res/values-sq/strings.xml | 3 +- packages/VpnDialogs/res/values-sv/strings.xml | 3 +- packages/VpnDialogs/res/values-ta/strings.xml | 3 +- packages/VpnDialogs/res/values-te/strings.xml | 5 +- packages/VpnDialogs/res/values-ur/strings.xml | 3 +- packages/VpnDialogs/res/values-vi/strings.xml | 3 +- packages/VpnDialogs/res/values-zh-rCN/strings.xml | 3 +- packages/VpnDialogs/res/values-zh-rTW/strings.xml | 3 +- packages/VpnDialogs/res/values-zu/strings.xml | 3 +- .../res/values-af/strings.xml | 2 +- .../res/values-am/strings.xml | 2 +- .../res/values-ar/strings.xml | 21 - .../res/values-as/strings.xml | 21 - .../res/values-az/strings.xml | 21 - .../res/values-b+sr+Latn/strings.xml | 2 +- .../res/values-be/strings.xml | 21 - .../res/values-bg/strings.xml | 2 +- .../res/values-bn/strings.xml | 21 - .../res/values-bs/strings.xml | 2 +- .../res/values-ca/strings.xml | 21 - .../res/values-cs/strings.xml | 2 +- .../res/values-da/strings.xml | 2 +- .../res/values-de/strings.xml | 2 +- .../res/values-el/strings.xml | 2 +- .../res/values-en-rAU/strings.xml | 2 +- .../res/values-en-rCA/strings.xml | 2 +- .../res/values-en-rGB/strings.xml | 2 +- .../res/values-en-rIN/strings.xml | 2 +- .../res/values-en-rXC/strings.xml | 2 +- .../res/values-es-rUS/strings.xml | 2 +- .../res/values-es/strings.xml | 2 +- .../res/values-et/strings.xml | 21 - .../res/values-eu/strings.xml | 2 +- .../res/values-fa/strings.xml | 21 - .../res/values-fi/strings.xml | 2 +- .../res/values-fr-rCA/strings.xml | 2 +- .../res/values-fr/strings.xml | 21 - .../res/values-gl/strings.xml | 2 +- .../res/values-gu/strings.xml | 21 - .../res/values-hi/strings.xml | 21 - .../res/values-hr/strings.xml | 2 +- .../res/values-hu/strings.xml | 21 - .../res/values-hy/strings.xml | 21 - .../res/values-in/strings.xml | 2 +- .../res/values-is/strings.xml | 21 - .../res/values-it/strings.xml | 2 +- .../res/values-iw/strings.xml | 21 - .../res/values-ja/strings.xml | 2 +- .../res/values-ka/strings.xml | 2 +- .../res/values-kk/strings.xml | 21 - .../res/values-km/strings.xml | 2 +- .../res/values-kn/strings.xml | 21 - .../res/values-ko/strings.xml | 2 +- .../res/values-ky/strings.xml | 21 - .../res/values-lo/strings.xml | 2 +- .../res/values-lt/strings.xml | 21 - .../res/values-lv/strings.xml | 21 - .../res/values-mk/strings.xml | 2 +- .../res/values-ml/strings.xml | 21 - .../res/values-mn/strings.xml | 2 +- .../res/values-mr/strings.xml | 21 - .../res/values-ms/strings.xml | 2 +- .../res/values-my/strings.xml | 21 - .../res/values-nb/strings.xml | 21 - .../res/values-ne/strings.xml | 21 - .../res/values-nl/strings.xml | 2 +- .../res/values-or/strings.xml | 21 - .../res/values-pa/strings.xml | 2 +- .../res/values-pl/strings.xml | 21 - .../res/values-pt-rBR/strings.xml | 2 +- .../res/values-pt-rPT/strings.xml | 2 +- .../res/values-pt/strings.xml | 2 +- .../res/values-ro/strings.xml | 2 +- .../res/values-ru/strings.xml | 2 +- .../res/values-si/strings.xml | 2 +- .../res/values-sk/strings.xml | 2 +- .../res/values-sl/strings.xml | 21 - .../res/values-sq/strings.xml | 21 - .../res/values-sr/strings.xml | 2 +- .../res/values-sv/strings.xml | 21 - .../res/values-sw/strings.xml | 2 +- .../res/values-ta/strings.xml | 21 - .../res/values-te/strings.xml | 21 - .../res/values-th/strings.xml | 2 +- .../res/values-tl/strings.xml | 2 +- .../res/values-tr/strings.xml | 2 +- .../res/values-uk/strings.xml | 2 +- .../res/values-ur/strings.xml | 21 - .../res/values-uz/strings.xml | 2 +- .../res/values-vi/strings.xml | 21 - .../res/values-zh-rCN/strings.xml | 21 - .../res/values-zh-rHK/strings.xml | 2 +- .../res/values-zh-rTW/strings.xml | 21 - .../res/values-zu/strings.xml | 21 - .../res/values-land/config.xml | 22 - .../res/values/config.xml | 8 - .../res/values-land/config.xml | 22 - .../res/values/config.xml | 8 - .../res/values-land/config.xml | 22 - .../res/values/config.xml | 8 - .../res/values-land/config.xml | 22 - .../res/values/config.xml | 8 - .../res/values-land/config.xml | 22 - .../res/values/config.xml | 8 - .../res/values-land/config.xml | 22 - .../res/values/config.xml | 10 - .../res/values-land/config.xml | 22 - .../res/values/config.xml | 8 - .../NoCutoutOverlay/res/values-ar/strings.xml | 21 - .../NoCutoutOverlay/res/values-as/strings.xml | 21 - .../NoCutoutOverlay/res/values-az/strings.xml | 21 - .../NoCutoutOverlay/res/values-be/strings.xml | 21 - .../NoCutoutOverlay/res/values-bn/strings.xml | 21 - .../NoCutoutOverlay/res/values-ca/strings.xml | 21 - .../NoCutoutOverlay/res/values-et/strings.xml | 21 - .../NoCutoutOverlay/res/values-fa/strings.xml | 21 - .../NoCutoutOverlay/res/values-fr/strings.xml | 21 - .../NoCutoutOverlay/res/values-gu/strings.xml | 21 - .../NoCutoutOverlay/res/values-hi/strings.xml | 21 - .../NoCutoutOverlay/res/values-hu/strings.xml | 21 - .../NoCutoutOverlay/res/values-hy/strings.xml | 21 - .../NoCutoutOverlay/res/values-is/strings.xml | 21 - .../NoCutoutOverlay/res/values-iw/strings.xml | 21 - .../NoCutoutOverlay/res/values-kk/strings.xml | 21 - .../NoCutoutOverlay/res/values-kn/strings.xml | 21 - .../NoCutoutOverlay/res/values-ky/strings.xml | 21 - .../NoCutoutOverlay/res/values-lt/strings.xml | 21 - .../NoCutoutOverlay/res/values-lv/strings.xml | 21 - .../NoCutoutOverlay/res/values-ml/strings.xml | 21 - .../NoCutoutOverlay/res/values-mr/strings.xml | 21 - .../NoCutoutOverlay/res/values-my/strings.xml | 21 - .../NoCutoutOverlay/res/values-nb/strings.xml | 21 - .../NoCutoutOverlay/res/values-ne/strings.xml | 21 - .../NoCutoutOverlay/res/values-or/strings.xml | 21 - .../NoCutoutOverlay/res/values-pl/strings.xml | 21 - .../NoCutoutOverlay/res/values-sl/strings.xml | 21 - .../NoCutoutOverlay/res/values-sq/strings.xml | 21 - .../NoCutoutOverlay/res/values-sv/strings.xml | 21 - .../NoCutoutOverlay/res/values-ta/strings.xml | 21 - .../NoCutoutOverlay/res/values-te/strings.xml | 21 - .../NoCutoutOverlay/res/values-ur/strings.xml | 21 - .../NoCutoutOverlay/res/values-vi/strings.xml | 21 - .../NoCutoutOverlay/res/values-zh-rCN/strings.xml | 21 - .../NoCutoutOverlay/res/values-zh-rTW/strings.xml | 21 - .../NoCutoutOverlay/res/values-zu/strings.xml | 21 - .../overlays/NoCutoutOverlay/res/values/config.xml | 8 - .../CameraExtensionsProxy/AndroidManifest.xml | 6 + .../CameraExtensionsProxyService.java | 36 +- .../src/com/android/pacprocessor/PacService.java | 57 +- proto/src/task_snapshot.proto | 4 + .../AbstractAccessibilityServiceConnection.java | 316 ++- .../accessibility/AccessibilityInputFilter.java | 327 ++- .../accessibility/AccessibilityManagerService.java | 272 +- .../AccessibilityServiceConnection.java | 53 +- .../accessibility/AccessibilityShellCommand.java | 2 +- .../server/accessibility/AccessibilityTrace.java | 66 - .../accessibility/AccessibilityTraceManager.java | 194 +- .../accessibility/AccessibilityUserState.java | 8 +- .../accessibility/AccessibilityWindowManager.java | 85 +- .../server/accessibility/AutoclickController.java | 13 +- .../server/accessibility/KeyboardInterceptor.java | 6 + .../server/accessibility/MotionEventInjector.java | 14 +- .../accessibility/SystemActionPerformer.java | 17 - .../server/accessibility/UiAutomationManager.java | 9 + .../accessibility/gestures/TouchExplorer.java | 30 + .../FullScreenMagnificationController.java | 55 +- .../FullScreenMagnificationGestureHandler.java | 4 +- .../magnification/MagnificationController.java | 3 +- .../magnification/MagnificationGestureHandler.java | 11 + .../WindowMagnificationConnectionWrapper.java | 72 +- .../WindowMagnificationGestureHandler.java | 4 +- .../magnification/WindowMagnificationManager.java | 46 +- .../appprediction/AppPredictionPerUserService.java | 2 +- .../server/backup/UserBackupManagerService.java | 12 +- .../companion/CompanionDeviceManagerService.java | 13 +- .../ContentCaptureManagerService.java | 2 +- .../ContentCapturePerUserService.java | 58 +- .../ContentCaptureServerSession.java | 2 +- services/core/Android.bp | 2 +- .../android/server/BluetoothManagerService.java | 25 +- .../java/com/android/server/TelephonyRegistry.java | 283 +- .../com/android/server/UiModeManagerService.java | 9 +- .../core/java/com/android/server/Watchdog.java | 2 + .../java/com/android/server/am/ActiveServices.java | 27 +- .../android/server/am/ActivityManagerService.java | 103 +- .../server/am/ActivityManagerShellCommand.java | 40 +- .../core/java/com/android/server/am/AppErrors.java | 6 +- .../java/com/android/server/am/AppProfiler.java | 65 +- .../server/am/BatteryExternalStatsWorker.java | 28 +- .../com/android/server/am/BatteryStatsService.java | 4 +- .../java/com/android/server/am/BroadcastQueue.java | 12 +- .../com/android/server/am/CachedAppOptimizer.java | 35 +- .../android/server/am/MeasuredEnergySnapshot.java | 11 +- .../java/com/android/server/am/OomAdjuster.java | 23 +- .../com/android/server/am/PhantomProcessList.java | 6 + .../java/com/android/server/am/ProcessList.java | 65 +- .../java/com/android/server/am/ProcessRecord.java | 11 +- .../java/com/android/server/am/ServiceRecord.java | 4 +- .../java/com/android/server/am/UserController.java | 91 +- .../core/java/com/android/server/am/UserState.java | 7 + .../AppHibernationManagerInternal.java | 5 + .../apphibernation/AppHibernationService.java | 85 +- .../com/android/server/appop/AppOpsService.java | 1 + .../android/server/audio/AudioDeviceBroker.java | 2 +- .../android/server/audio/AudioDeviceInventory.java | 24 +- .../com/android/server/audio/AudioService.java | 309 ++- .../android/server/audio/AudioSystemAdapter.java | 44 +- .../com/android/server/audio/RotationHelper.java | 35 +- .../android/server/audio/SpatializerHelper.java | 986 +++++++ .../com/android/server/biometrics/AuthService.java | 6 +- .../server/biometrics/BiometricService.java | 16 +- .../com/android/server/biometrics/PreAuthInfo.java | 96 +- .../java/com/android/server/biometrics/Utils.java | 19 +- .../biometrics/sensors/AuthenticationClient.java | 62 +- .../biometrics/sensors/BaseClientMonitor.java | 31 +- .../biometrics/sensors/BiometricScheduler.java | 3 + .../server/biometrics/sensors/EnrollClient.java | 13 + .../server/biometrics/sensors/SensorOverlays.java | 144 + .../face/aidl/FaceAuthenticationClient.java | 16 +- .../sensors/face/aidl/FaceDetectClient.java | 12 + .../sensors/face/aidl/FaceStartUserClient.java | 2 + .../face/hidl/FaceAuthenticationClient.java | 12 + .../sensors/fingerprint/FingerprintService.java | 9 +- .../fingerprint/FingerprintStateCallback.java | 6 +- .../sensors/fingerprint/SidefpsHelper.java | 60 - .../sensors/fingerprint/UdfpsHelper.java | 87 - .../aidl/FingerprintAuthenticationClient.java | 27 +- .../fingerprint/aidl/FingerprintDetectClient.java | 18 +- .../fingerprint/aidl/FingerprintEnrollClient.java | 39 +- .../fingerprint/aidl/FingerprintProvider.java | 56 +- .../aidl/FingerprintStartUserClient.java | 2 + .../sensors/fingerprint/hidl/Fingerprint21.java | 3 +- .../fingerprint/hidl/Fingerprint21UdfpsMock.java | 3 +- .../hidl/FingerprintAuthenticationClient.java | 23 +- .../fingerprint/hidl/FingerprintDetectClient.java | 16 +- .../fingerprint/hidl/FingerprintEnrollClient.java | 38 +- .../broadcastradio/BroadcastRadioService.java | 6 +- .../java/com/android/server/broadcastradio/OWNERS | 3 +- .../broadcastradio/hal1/BroadcastRadioService.java | 17 +- .../hal2/AnnouncementAggregator.java | 5 +- .../broadcastradio/hal2/BroadcastRadioService.java | 9 +- .../server/broadcastradio/hal2/RadioModule.java | 17 +- .../server/broadcastradio/hal2/TunerSession.java | 6 +- .../android/server/camera/CameraServiceProxy.java | 378 ++- .../com/android/server/compat/CompatChange.java | 79 +- .../com/android/server/compat/CompatConfig.java | 409 ++- .../com/android/server/compat/PlatformCompat.java | 10 +- .../compat/overrides/AppCompatOverridesParser.java | 337 +++ .../overrides/AppCompatOverridesService.java | 430 +++ .../com/android/server/compat/overrides/OWNERS | 2 + .../android/server/compat/overrides/TEST_MAPPING | 12 + .../connectivity/MultipathPolicyTracker.java | 2 +- .../java/com/android/server/connectivity/Vpn.java | 25 +- .../android/server/devicestate/DeviceState.java | 33 +- .../devicestate/DeviceStateManagerService.java | 529 ++-- .../DeviceStateManagerShellCommand.java | 33 +- .../server/devicestate/OverrideRequest.java | 58 + .../devicestate/OverrideRequestController.java | 322 +++ .../server/display/DeviceStateToLayoutMap.java | 4 +- .../com/android/server/display/DisplayDevice.java | 45 + .../server/display/DisplayDeviceRepository.java | 11 + .../server/display/DisplayManagerService.java | 234 +- .../server/display/DisplayManagerShellCommand.java | 2 +- .../server/display/DisplayModeDirector.java | 7 +- .../server/display/DisplayPowerController.java | 40 +- .../server/display/LocalDisplayAdapter.java | 17 +- .../com/android/server/display/LogicalDisplay.java | 7 + .../server/display/LogicalDisplayMapper.java | 45 +- .../server/display/PersistentDataStore.java | 79 +- .../server/display/VirtualDisplayAdapter.java | 28 + .../android/server/input/InputManagerService.java | 75 +- .../inputmethod/InputMethodManagerService.java | 77 +- .../MultiClientInputMethodManagerService.java | 2 +- .../server/location/geofence/GeofenceManager.java | 8 +- .../location/gnss/GnssListenerMultiplexer.java | 8 +- .../location/gnss/GnssMeasurementsProvider.java | 8 +- .../injector/LocationAttributionHelper.java | 99 +- .../injector/LocationPermissionsHelper.java | 6 +- .../location/provider/LocationProviderManager.java | 130 +- .../StationaryThrottlingLocationProvider.java | 5 +- .../android/server/media/MediaRouterService.java | 36 + .../android/server/media/MediaSessionService.java | 17 + .../media/metrics/MediaMetricsManagerService.java | 9 + .../server/net/NetworkPolicyManagerService.java | 4 +- .../server/notification/BadgeExtractor.java | 7 +- .../server/notification/ManagedServices.java | 44 +- .../notification/NotificationComparator.java | 2 +- .../notification/NotificationManagerService.java | 186 +- .../server/notification/NotificationRecord.java | 4 + .../server/notification/PreferencesHelper.java | 3 + .../server/notification/VibratorHelper.java | 83 +- .../android/server/os/NativeTombstoneManager.java | 2 +- .../com/android/server/pm/OtaDexoptService.java | 2 +- .../com/android/server/pm/PackageDexOptimizer.java | 53 +- .../android/server/pm/PackageInstallerService.java | 6 +- .../android/server/pm/PackageManagerService.java | 55 +- .../permission/DefaultPermissionGrantPolicy.java | 5 + .../verify/domain/DomainVerificationEnforcer.java | 7 +- .../verify/domain/DomainVerificationService.java | 3 +- .../server/policy/DeviceStateProviderImpl.java | 64 +- .../server/policy/DisplayFoldController.java | 27 +- .../server/policy/KeyCombinationManager.java | 43 +- .../android/server/policy/PhoneWindowManager.java | 103 +- .../android/server/policy/WindowManagerPolicy.java | 14 +- .../policy/keyguard/KeyguardServiceDelegate.java | 26 +- .../policy/keyguard/KeyguardServiceWrapper.java | 6 +- .../policy/keyguard/KeyguardStateMonitor.java | 10 - .../android/server/power/PowerManagerService.java | 7 + .../server/powerstats/PowerStatsLogger.java | 5 +- .../server/powerstats/PowerStatsService.java | 35 +- .../SoundTriggerHw2Watchdog.java | 25 +- .../SoundTriggerMiddlewarePermission.java | 2 + .../soundtrigger_middleware/UptimeTimer.java | 90 + .../server/stats/pull/StatsPullAtomService.java | 190 +- .../server/statusbar/StatusBarManagerInternal.java | 6 +- .../server/statusbar/StatusBarManagerService.java | 30 +- services/core/java/com/android/server/vcn/Vcn.java | 69 +- .../android/server/vcn/VcnGatewayConnection.java | 20 +- .../com/android/server/vibrator/Vibration.java | 2 + .../android/server/vibrator/VibrationThread.java | 83 +- .../server/vibrator/VibratorManagerService.java | 22 +- .../java/com/android/server/vr/Vr2dDisplay.java | 3 +- .../server/wallpaper/LocalColorRepository.java | 166 ++ .../server/wallpaper/WallpaperManagerService.java | 129 +- .../android/server/wm/AccessibilityController.java | 617 +++-- .../server/wm/ActivityClientController.java | 59 +- .../server/wm/ActivityInterceptorCallback.java | 98 + .../android/server/wm/ActivityMetricsLogger.java | 252 +- .../java/com/android/server/wm/ActivityRecord.java | 1193 ++++++--- .../wm/ActivityServiceConnectionsHolder.java | 4 +- .../android/server/wm/ActivityStartController.java | 28 + .../server/wm/ActivityStartInterceptor.java | 29 +- .../com/android/server/wm/ActivityStarter.java | 286 +- .../server/wm/ActivityTaskManagerInternal.java | 67 +- .../server/wm/ActivityTaskManagerService.java | 279 +- .../android/server/wm/ActivityTaskSupervisor.java | 330 ++- .../com/android/server/wm/AnimationAdapter.java | 3 +- .../java/com/android/server/wm/AnrController.java | 44 +- .../java/com/android/server/wm/AppTaskImpl.java | 10 +- .../java/com/android/server/wm/AppTransition.java | 287 +- .../android/server/wm/AppTransitionController.java | 420 ++- .../com/android/server/wm/BLASTSyncEngine.java | 35 + .../wm/BackgroundLaunchProcessController.java | 9 +- .../android/server/wm/ConfigurationContainer.java | 76 +- .../java/com/android/server/wm/DisplayArea.java | 4 +- .../server/wm/DisplayAreaPolicyBuilder.java | 7 +- .../java/com/android/server/wm/DisplayContent.java | 787 ++++-- .../java/com/android/server/wm/DisplayPolicy.java | 1086 +++++--- .../com/android/server/wm/DisplayRotation.java | 33 +- .../server/wm/DisplayWindowSettingsProvider.java | 8 +- .../server/wm/DockedTaskDividerController.java | 2 +- .../com/android/server/wm/DragDropController.java | 101 +- .../core/java/com/android/server/wm/DragState.java | 27 +- .../server/wm/EmbeddedWindowController.java | 27 +- .../server/wm/EnsureActivitiesVisibleHelper.java | 100 +- .../server/wm/FadeRotationAnimationController.java | 19 +- .../android/server/wm/ImeInsetsSourceProvider.java | 11 + .../server/wm/ImmersiveModeConfirmation.java | 3 +- .../android/server/wm/InputManagerCallback.java | 5 +- .../java/com/android/server/wm/InputMonitor.java | 102 +- .../java/com/android/server/wm/InputTarget.java | 40 + .../server/wm/InputWindowHandleWrapper.java | 9 + .../java/com/android/server/wm/InsetsPolicy.java | 117 +- .../android/server/wm/InsetsSourceProvider.java | 106 +- .../android/server/wm/InsetsStateController.java | 4 +- .../com/android/server/wm/KeyguardController.java | 41 +- .../core/java/com/android/server/wm/Letterbox.java | 121 +- .../android/server/wm/LetterboxConfiguration.java | 336 ++- .../android/server/wm/LetterboxUiController.java | 196 +- .../android/server/wm/LocalAnimationAdapter.java | 3 +- .../com/android/server/wm/LocaleOverlayHelper.java | 62 + .../com/android/server/wm/LockTaskController.java | 48 +- .../server/wm/NavBarFadeAnimationController.java | 3 +- .../server/wm/NonAppWindowAnimationAdapter.java | 38 +- .../android/server/wm/PackageConfigPersister.java | 93 +- .../server/wm/PackageConfigurationUpdaterImpl.java | 126 + .../android/server/wm/PinnedTaskController.java | 40 +- .../java/com/android/server/wm/RecentTasks.java | 24 +- .../com/android/server/wm/RecentsAnimation.java | 13 +- .../server/wm/RecentsAnimationController.java | 181 +- .../server/wm/RemoteAnimationController.java | 80 +- .../com/android/server/wm/RootWindowContainer.java | 151 +- .../java/com/android/server/wm/RunningTasks.java | 13 + .../com/android/server/wm/SafeActivityOptions.java | 23 + .../android/server/wm/ScreenRotationAnimation.java | 19 +- .../core/java/com/android/server/wm/Session.java | 31 +- .../core/java/com/android/server/wm/ShellRoot.java | 2 +- .../java/com/android/server/wm/StartingData.java | 6 + .../com/android/server/wm/StrictModeFlash.java | 3 +- .../com/android/server/wm/SurfaceAnimator.java | 51 +- .../java/com/android/server/wm/SurfaceFreezer.java | 124 +- services/core/java/com/android/server/wm/Task.java | 2825 ++++---------------- .../com/android/server/wm/TaskDisplayArea.java | 232 +- .../java/com/android/server/wm/TaskFragment.java | 2541 ++++++++++++++++++ .../server/wm/TaskFragmentOrganizerController.java | 624 +++++ .../server/wm/TaskLaunchParamsModifier.java | 44 +- .../android/server/wm/TaskOrganizerController.java | 344 ++- .../android/server/wm/TaskSnapshotController.java | 93 +- .../com/android/server/wm/TaskSnapshotLoader.java | 4 +- .../android/server/wm/TaskSnapshotPersister.java | 6 +- .../com/android/server/wm/TaskSnapshotSurface.java | 5 +- .../java/com/android/server/wm/Transition.java | 641 ++++- .../android/server/wm/TransitionController.java | 312 ++- .../server/wm/WallpaperAnimationAdapter.java | 25 +- .../com/android/server/wm/WallpaperController.java | 90 +- .../android/server/wm/WallpaperWindowToken.java | 13 +- .../core/java/com/android/server/wm/Watermark.java | 3 +- .../java/com/android/server/wm/WindowAnimator.java | 2 +- .../com/android/server/wm/WindowContainer.java | 398 ++- .../server/wm/WindowContextListenerController.java | 78 +- .../java/com/android/server/wm/WindowFrames.java | 5 + .../server/wm/WindowManagerDebugConfig.java | 1 - .../android/server/wm/WindowManagerInternal.java | 94 +- .../android/server/wm/WindowManagerService.java | 498 ++-- .../server/wm/WindowOrganizerController.java | 606 ++++- .../android/server/wm/WindowProcessController.java | 108 +- .../java/com/android/server/wm/WindowState.java | 438 ++- .../com/android/server/wm/WindowStateAnimator.java | 21 +- .../java/com/android/server/wm/WindowToken.java | 28 +- .../java/com/android/server/wm/WindowTracing.java | 3 +- .../com_android_server_am_CachedAppOptimizer.cpp | 22 + services/core/xsd/Android.bp | 2 +- .../device-state-config/device-state-config.xsd | 9 + .../xsd/device-state-config/schema/current.txt | 7 + .../display-layout-config.xsd | 2 +- .../xsd/display-layout-config/schema/current.txt | 6 +- .../server/devicepolicy/DevicePolicyCacheImpl.java | 15 +- .../devicepolicy/DevicePolicyManagerService.java | 397 ++- .../DevicePolicyManagerServiceShellCommand.java | 20 +- .../server/devicepolicy/OwnerShellData.java | 98 + .../com/android/server/devicepolicy/Owners.java | 28 +- services/java/com/android/server/SystemServer.java | 9 + ...versationStatusExpirationBroadcastReceiver.java | 2 + .../domain/DomainVerificationEnforcerTest.kt | 29 +- .../verify/domain/DomainVerificationPackageTest.kt | 85 +- .../android/server/am/MockingOomAdjusterTests.java | 31 + .../src/com/android/server/compat/OWNERS | 1 + .../overrides/AppCompatOverridesParserTest.java | 269 ++ .../overrides/AppCompatOverridesServiceTest.java | 726 +++++ .../src/com/android/server/compat/overrides/OWNERS | 1 + .../server/devicepolicy/FactoryResetterTest.java | 2 +- .../server/devicepolicy/OwnerShellDataTest.java | 129 + .../server/display/LocalDisplayAdapterTest.java | 14 + .../injector/LocationAttributionHelperTest.java | 134 +- .../provider/LocationProviderManagerTest.java | 42 + .../StationaryThrottlingLocationProviderTest.java | 31 +- .../pm/PackageManagerServiceHibernationTests.kt | 55 +- .../server/testables/TestableDeviceConfig.java | 33 +- .../server/testables/TestableDeviceConfigTest.java | 42 +- .../server/wallpaper/LocalColorRepositoryTest.java | 135 + .../wallpaper/WallpaperManagerServiceTests.java | 2 +- services/tests/servicestests/Android.bp | 1 + services/tests/servicestests/AndroidManifest.xml | 1 + services/tests/servicestests/AndroidTest.xml | 18 + ...AbstractAccessibilityServiceConnectionTest.java | 1 + .../AccessibilityInputFilterTest.java | 113 +- .../AccessibilityManagerServiceTest.java | 23 +- .../AccessibilityServiceConnectionTest.java | 1 + .../AccessibilityWindowManagerTest.java | 17 +- .../accessibility/KeyboardInterceptorTest.java | 2 + .../accessibility/MotionEventInjectorTest.java | 4 +- .../accessibility/SystemActionPerformerTest.java | 8 - .../accessibility/UiAutomationManagerTest.java | 1 + .../accessibility/gestures/TouchExplorerTest.java | 5 + .../FullScreenMagnificationControllerTest.java | 12 +- .../FullScreenMagnificationGestureHandlerTest.java | 11 +- .../magnification/MagnificationControllerTest.java | 5 +- .../MagnificationGestureHandlerTest.java | 10 +- .../WindowMagnificationConnectionWrapperTest.java | 6 +- .../WindowMagnificationGestureHandlerTest.java | 7 +- .../WindowMagnificationManagerTest.java | 5 +- .../server/am/BatteryExternalStatsWorkerTest.java | 24 +- .../server/am/MeasuredEnergySnapshotTest.java | 16 +- .../android/server/am/ServiceRestarterTest.java | 88 + .../apphibernation/AppHibernationServiceTest.java | 6 +- .../appsearch/AppSearchImplPlatformTest.java | 27 +- .../external/localstorage/AppSearchImplTest.java | 218 +- .../external/localstorage/AppSearchLoggerTest.java | 132 +- .../localstorage/stats/AppSearchStatsTest.java | 11 +- .../android/server/biometrics/AuthSessionTest.java | 62 +- .../biometrics/sensors/BiometricSchedulerTest.java | 54 +- .../biometrics/sensors/SensorOverlaysTest.java | 129 + .../sensors/face/aidl/FaceProviderTest.java | 23 +- .../fingerprint/aidl/FingerprintProviderTest.java | 34 +- .../server/camera/CameraServiceProxyTest.java | 102 + .../src/com/android/server/camera/OWNERS | 1 + .../android/server/compat/CompatConfigTest.java | 88 +- .../devicepolicy/DevicePolicyManagerTest.java | 78 +- .../devicestate/DeviceStateManagerServiceTest.java | 76 +- .../server/devicestate/DeviceStateTest.java | 10 +- .../devicestate/OverrideRequestControllerTest.java | 230 ++ .../server/display/DisplayManagerServiceTest.java | 55 + .../server/display/PersistentDataStoreTest.java | 94 +- .../server/pm/PackageManagerServiceTest.java | 37 + .../pm/parsing/AndroidPackageParsingTestBase.kt | 2 - .../server/policy/DeviceStateProviderImplTest.java | 81 +- .../server/powerstats/PowerStatsServiceTest.java | 7 +- .../soundtrigger_middleware/UptimeTimerTest.java | 59 + .../vibrator/VibratorManagerServiceTest.java | 40 +- .../SimpleServiceTestApp/AndroidManifest.xml | 1 + .../apps/simpleservicetestapp/SimpleService.java | 20 + .../servicestests/test-apps/StubApp/Android.bp | 37 + .../test-apps/StubApp/AndroidManifest.xml | 25 + .../servicestests/apps/stubapp/TestActivity.java | 22 + .../android/server/UiModeManagerServiceTest.java | 67 +- .../server/notification/BuzzBeepBlinkTest.java | 58 +- .../server/notification/ManagedServicesTest.java | 19 +- .../notification/NotificationAssistantsTest.java | 97 +- .../NotificationListenerServiceTest.java | 8 +- .../NotificationManagerServiceTest.java | 270 +- .../server/notification/PreferencesHelperTest.java | 15 +- .../server/notification/VibratorHelperTest.java | 12 + .../wm/ActivityMetricsLaunchObserverTests.java | 58 +- .../com/android/server/wm/ActivityOptionsTest.java | 6 +- .../com/android/server/wm/ActivityRecordTests.java | 463 +++- .../server/wm/ActivityStartInterceptorTest.java | 44 +- .../android/server/wm/ActivityStarterTests.java | 56 +- .../server/wm/ActivityTaskManagerServiceTests.java | 447 +++- .../server/wm/ActivityTaskSupervisorTests.java | 37 +- .../server/wm/AppTransitionControllerTest.java | 434 ++- .../com/android/server/wm/AppTransitionTests.java | 213 +- .../server/wm/AppWindowTokenAnimationTests.java | 10 +- .../server/wm/DisplayAreaPolicyBuilderTest.java | 2 +- .../src/com/android/server/wm/DisplayAreaTest.java | 26 + .../com/android/server/wm/DisplayContentTests.java | 241 +- .../server/wm/DisplayPolicyInsetsTests.java | 16 +- .../server/wm/DisplayPolicyLayoutTests.java | 43 +- .../com/android/server/wm/DisplayPolicyTests.java | 145 +- .../android/server/wm/DisplayPolicyTestsBase.java | 6 +- .../android/server/wm/DragDropControllerTests.java | 70 +- .../server/wm/InputMethodMenuControllerTest.java | 4 +- .../com/android/server/wm/InsetsPolicyTest.java | 54 +- .../server/wm/InsetsSourceProviderTest.java | 14 +- .../server/wm/InsetsStateControllerTest.java | 10 +- .../server/wm/LaunchParamsPersisterTests.java | 6 +- .../src/com/android/server/wm/LetterboxTest.java | 36 +- .../src/com/android/server/wm/RecentTasksTest.java | 89 +- .../server/wm/RecentsAnimationControllerTest.java | 38 +- .../android/server/wm/RecentsAnimationTest.java | 2 +- .../server/wm/RemoteAnimationControllerTest.java | 135 +- .../src/com/android/server/wm/RootTaskTests.java | 205 +- .../server/wm/RootWindowContainerTests.java | 58 +- .../com/android/server/wm/RunningTasksTest.java | 2 +- .../src/com/android/server/wm/SizeCompatTests.java | 348 ++- .../src/com/android/server/wm/StubTransaction.java | 5 + .../src/com/android/server/wm/SyncEngineTests.java | 18 +- .../android/server/wm/SystemServicesTestRule.java | 1 - .../android/server/wm/TaskDisplayAreaTests.java | 13 +- .../wm/TaskFragmentOrganizerControllerTest.java | 526 ++++ .../com/android/server/wm/TaskFragmentTest.java | 152 ++ .../server/wm/TaskLaunchParamsModifierTests.java | 112 +- .../server/wm/TaskSnapshotControllerTest.java | 5 +- .../server/wm/TaskSnapshotPersisterTestBase.java | 5 +- .../android/server/wm/TaskSnapshotSurfaceTest.java | 2 +- .../src/com/android/server/wm/TaskTests.java | 117 +- .../com/android/server/wm/TestDisplayContent.java | 20 + .../android/server/wm/TestWindowManagerPolicy.java | 6 +- .../src/com/android/server/wm/TransitionTests.java | 221 +- .../server/wm/WallpaperControllerTests.java | 3 +- .../android/server/wm/WindowAnimationSpecTest.java | 64 - .../android/server/wm/WindowContainerTests.java | 159 ++ .../wm/WindowContextListenerControllerTests.java | 85 +- .../com/android/server/wm/WindowFrameTests.java | 41 +- .../server/wm/WindowManagerServiceTests.java | 15 +- .../android/server/wm/WindowOrganizerTests.java | 85 +- .../server/wm/WindowProcessControllerTests.java | 27 +- .../com/android/server/wm/WindowStateTests.java | 29 +- .../src/com/android/server/wm/WindowTestsBase.java | 258 +- .../src/com/android/server/wm/ZOrderingTests.java | 154 +- .../com/android/server/usb/UsbDeviceManager.java | 9 +- .../server/usb/UsbUserPermissionManager.java | 10 +- .../HotwordDetectionConnection.java | 2 +- .../VoiceInteractionManagerService.java | 52 + .../VoiceInteractionManagerServiceImpl.java | 38 + .../VoiceInteractionSessionConnection.java | 161 ++ .../internal/telephony/TelephonyPermissions.java | 21 +- .../android/telephony/CarrierConfigManager.java | 69 +- .../android/telephony/SubscriptionManager.java | 9 + .../java/android/telephony/TelephonyManager.java | 9 +- .../android/telephony/TelephonyScanManager.java | 35 +- .../android/telephony/data/QosBearerFilter.java | 37 +- tests/FlickerTests/Android.bp | 22 +- .../android/server/wm/flicker/CommonAssertions.kt | 255 +- .../wm/flicker/close/CloseAppBackButtonTest.kt | 43 +- .../wm/flicker/close/CloseAppHomeButtonTest.kt | 44 +- .../server/wm/flicker/close/CloseAppTransition.kt | 114 +- .../server/wm/flicker/helpers/FlickerExtensions.kt | 1 + .../wm/flicker/helpers/ImeAppAutoFocusHelper.kt | 6 +- .../server/wm/flicker/helpers/ImeAppHelper.kt | 27 +- .../server/wm/flicker/helpers/NewTasksAppHelper.kt | 52 + .../wm/flicker/helpers/NonResizeableAppHelper.kt | 34 + .../flicker/helpers/SeamlessRotationAppHelper.kt | 6 +- .../server/wm/flicker/helpers/SimpleAppHelper.kt | 6 +- .../wm/flicker/helpers/TwoActivitiesAppHelper.kt | 52 + .../flicker/ime/CloseImeAutoOpenWindowToAppTest.kt | 83 +- .../ime/CloseImeAutoOpenWindowToHomeTest.kt | 95 +- .../wm/flicker/ime/CloseImeWindowToAppTest.kt | 50 +- .../wm/flicker/ime/CloseImeWindowToHomeTest.kt | 59 +- .../server/wm/flicker/ime/CommonAssertions.kt | 100 +- .../wm/flicker/ime/LaunchAppShowImeOnStartTest.kt | 153 ++ .../wm/flicker/ime/OpenImeWindowAndCloseTest.kt | 131 + .../server/wm/flicker/ime/OpenImeWindowTest.kt | 41 +- .../server/wm/flicker/ime/ReOpenImeWindowTest.kt | 127 +- .../ime/SwitchImeWindowsFromGestureNavTest.kt | 106 +- .../wm/flicker/launch/ActivitiesTransitionTest.kt | 161 ++ .../server/wm/flicker/launch/CommonAssertions.kt | 29 - .../server/wm/flicker/launch/OpenAppColdTest.kt | 67 +- .../wm/flicker/launch/OpenAppFromOverviewTest.kt | 66 +- .../wm/flicker/launch/OpenAppNonResizeableTest.kt | 283 ++ .../server/wm/flicker/launch/OpenAppTransition.kt | 134 +- .../server/wm/flicker/launch/OpenAppWarmTest.kt | 53 +- .../server/wm/flicker/launch/TaskTransitionTest.kt | 248 ++ .../QuickSwitchBetweenTwoAppsBackTest.kt | 330 +++ .../QuickSwitchBetweenTwoAppsForwardTest.kt | 347 +++ .../quickswitch/QuickSwitchFromLauncherTest.kt | 346 +++ .../wm/flicker/rotation/ChangeAppRotationTest.kt | 119 +- .../wm/flicker/rotation/RotationTransition.kt | 114 +- .../wm/flicker/rotation/SeamlessAppRotationTest.kt | 154 +- .../test-apps/flickerapp/AndroidManifest.xml | 31 + .../flickerapp/res/layout/activity_button.xml | 27 + .../flickerapp/res/layout/activity_ime.xml | 7 + .../res/layout/activity_non_resizeable.xml | 32 + .../flickerapp/res/layout/task_button.xml | 27 + .../server/wm/flicker/testapp/ActivityOptions.java | 15 + .../server/wm/flicker/testapp/ButtonActivity.java | 41 + .../server/wm/flicker/testapp/ImeActivity.java | 5 + .../wm/flicker/testapp/LaunchNewTaskActivity.java | 44 + .../wm/flicker/testapp/NonResizeableActivity.java | 37 + .../wm/test/filters/FrameworksTestsFilter.java | 5 +- .../VcnGatewayConnectionConnectedStateTest.java | 15 + tests/vcn/java/com/android/server/vcn/VcnTest.java | 130 +- tools/aapt/SdkConstants.h | 1 + tools/aapt2/SdkConstants.cpp | 3 +- tools/aapt2/SdkConstants.h | 1 + tools/aapt2/format/binary/BinaryResourceParser.cpp | 18 +- tools/aapt2/format/binary/BinaryResourceParser.h | 4 + tools/finalize_res/finalize_res.py | 35 +- 3153 files changed, 144459 insertions(+), 93013 deletions(-) create mode 100644 core/java/android/accessibilityservice/AccessibilityTrace.java delete mode 100644 core/java/android/app/ForegroundServiceDidNotStartInTimeException.java create mode 100644 core/java/android/app/StackTrace.java create mode 100644 core/java/android/app/admin/EnterprisePlatformSecurity_OWNERS create mode 100644 core/java/android/app/admin/EnterprisePlatform_OWNERS create mode 100644 core/java/android/app/admin/WorkDeviceExperience_OWNERS create mode 100644 core/java/android/hardware/biometrics/BiometricOverlayConstants.java create mode 100644 core/java/android/hardware/biometrics/SensorLocationInternal.aidl create mode 100644 core/java/android/hardware/biometrics/SensorLocationInternal.java create mode 100644 core/java/android/hardware/camera2/params/DeviceStateSensorOrientationMap.java create mode 100644 core/java/android/service/voice/VisibleActivityInfo.aidl create mode 100644 core/java/android/service/voice/VisibleActivityInfo.java create mode 100644 core/java/android/util/DisplayUtils.java create mode 100644 core/java/android/view/InsetsResizeAnimationRunner.java create mode 100644 core/java/android/view/InsetsVisibilities.aidl create mode 100644 core/java/android/view/InsetsVisibilities.java create mode 100644 core/java/android/view/InternalInsetsAnimationController.java create mode 100644 core/java/android/view/TaskTransitionSpec.aidl create mode 100644 core/java/android/view/TaskTransitionSpec.java create mode 100644 core/java/android/window/ConfigurationHelper.java create mode 100644 core/java/android/window/ITaskFragmentOrganizer.aidl create mode 100644 core/java/android/window/ITaskFragmentOrganizerController.aidl create mode 100644 core/java/android/window/ITransitionMetricsReporter.aidl create mode 100644 core/java/android/window/RemoteTransition.aidl create mode 100644 core/java/android/window/RemoteTransition.java create mode 100644 core/java/android/window/StartingWindowRemovalInfo.aidl create mode 100644 core/java/android/window/StartingWindowRemovalInfo.java create mode 100644 core/java/android/window/TaskFragmentCreationParams.aidl create mode 100644 core/java/android/window/TaskFragmentCreationParams.java create mode 100644 core/java/android/window/TaskFragmentInfo.aidl create mode 100644 core/java/android/window/TaskFragmentInfo.java create mode 100644 core/java/android/window/TaskFragmentOrganizer.java create mode 100644 core/java/android/window/TaskFragmentOrganizerToken.java create mode 100644 core/java/android/window/TransitionMetrics.java create mode 100644 core/java/android/window/WindowInfosListener.java create mode 100644 core/java/android/window/WindowProvider.java create mode 100644 core/java/com/android/internal/policy/SystemBarUtils.java create mode 100644 core/java/com/android/internal/view/WebViewCaptureHelper.java create mode 100644 core/jni/android_window_WindowInfosListener.cpp create mode 100644 core/res/res/anim/task_fragment_close_enter.xml create mode 100644 core/res/res/anim/task_fragment_close_exit.xml create mode 100644 core/res/res/anim/task_fragment_open_enter.xml create mode 100644 core/res/res/anim/task_fragment_open_exit.xml create mode 100644 core/tests/coretests/res/drawable/custom_drawable.xml create mode 100644 core/tests/coretests/src/android/view/InsetsVisibilitiesTest.java create mode 100644 core/tests/coretests/src/android/window/CustomDrawable.java create mode 100644 core/tests/mockingcoretests/src/android/window/ConfigurationHelperTest.java create mode 100644 core/tests/mockingcoretests/src/android/window/SizeConfigurationBucketsTest.java create mode 100644 data/etc/car/com.google.android.car.adaslocation.xml delete mode 100644 libs/WindowManager/Jetpack/src/androidx/window/extensions/ExtensionProvider.java delete mode 100644 libs/WindowManager/Jetpack/src/androidx/window/extensions/SampleExtensionImpl.java delete mode 100644 libs/WindowManager/Jetpack/src/androidx/window/extensions/StubExtension.java create mode 100644 libs/WindowManager/Jetpack/src/androidx/window/extensions/WindowExtensionsImpl.java create mode 100644 libs/WindowManager/Jetpack/src/androidx/window/extensions/WindowExtensionsProvider.java create mode 100644 libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizer.java create mode 100644 libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitContainer.java create mode 100644 libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java create mode 100644 libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java create mode 100644 libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationAdapter.java create mode 100644 libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationController.java create mode 100644 libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationRunner.java create mode 100644 libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationSpec.java create mode 100644 libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java create mode 100644 libs/WindowManager/Jetpack/src/androidx/window/extensions/layout/WindowLayoutComponentImpl.java delete mode 100644 libs/WindowManager/Shell/OWNERS create mode 100644 libs/WindowManager/Shell/res/color/size_compat_background_ripple.xml create mode 100644 libs/WindowManager/Shell/res/color/split_divider_background.xml create mode 100644 libs/WindowManager/Shell/res/color/taskbar_background.xml create mode 100644 libs/WindowManager/Shell/res/color/unfold_transition_background.xml create mode 100644 libs/WindowManager/Shell/res/drawable/compat_hint_bubble.xml create mode 100644 libs/WindowManager/Shell/res/drawable/compat_hint_point.xml create mode 100644 libs/WindowManager/Shell/res/drawable/pip_split.xml create mode 100644 libs/WindowManager/Shell/res/drawable/size_compat_restart_button_ripple.xml create mode 100644 libs/WindowManager/Shell/res/layout/compat_mode_hint.xml create mode 100644 libs/WindowManager/Shell/res/layout/compat_ui_layout.xml delete mode 100644 libs/WindowManager/Shell/res/layout/size_compat_mode_hint.xml delete mode 100644 libs/WindowManager/Shell/res/layout/size_compat_ui.xml create mode 100644 libs/WindowManager/Shell/res/layout/split_decor.xml create mode 100644 libs/WindowManager/Shell/res/layout/split_outline.xml delete mode 100644 libs/WindowManager/Shell/src/com/android/wm/shell/FullscreenTaskListener.java create mode 100644 libs/WindowManager/Shell/src/com/android/wm/shell/RootDisplayAreaOrganizer.java create mode 100644 libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/OWNERS create mode 100644 libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/OWNERS create mode 100644 libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayInsetsController.java create mode 100644 libs/WindowManager/Shell/src/com/android/wm/shell/common/SingleInstanceRemoteListener.java create mode 100644 libs/WindowManager/Shell/src/com/android/wm/shell/common/annotations/ExternalMainThread.java create mode 100644 libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerRoundedCorner.java create mode 100644 libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitDecorManager.java create mode 100644 libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitScreenConstants.java create mode 100644 libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUI.java create mode 100644 libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java create mode 100644 libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUILayout.java create mode 100644 libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManager.java create mode 100644 libs/WindowManager/Shell/src/com/android/wm/shell/dagger/DynamicOverride.java create mode 100644 libs/WindowManager/Shell/src/com/android/wm/shell/dagger/README.txt create mode 100644 libs/WindowManager/Shell/src/com/android/wm/shell/dagger/TvPipModule.java create mode 100644 libs/WindowManager/Shell/src/com/android/wm/shell/dagger/TvWMShellModule.java create mode 100644 libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java create mode 100644 libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellConcurrencyModule.java create mode 100644 libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java create mode 100644 libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMSingleton.java create mode 100644 libs/WindowManager/Shell/src/com/android/wm/shell/displayareahelper/DisplayAreaHelper.java create mode 100644 libs/WindowManager/Shell/src/com/android/wm/shell/displayareahelper/DisplayAreaHelperController.java create mode 100644 libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDrop.java create mode 100644 libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropEventLogger.java create mode 100644 libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DropZoneView.java create mode 100644 libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java create mode 100644 libs/WindowManager/Shell/src/com/android/wm/shell/fullscreen/FullscreenTaskListener.java create mode 100644 libs/WindowManager/Shell/src/com/android/wm/shell/fullscreen/FullscreenUnfoldController.java create mode 100644 libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OWNERS create mode 100644 libs/WindowManager/Shell/src/com/android/wm/shell/pip/OWNERS create mode 100644 libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionState.java create mode 100644 libs/WindowManager/Shell/src/com/android/wm/shell/recents/IRecentTasks.aidl create mode 100644 libs/WindowManager/Shell/src/com/android/wm/shell/recents/IRecentTasksListener.aidl create mode 100644 libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasks.java create mode 100644 libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java delete mode 100644 libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatHintPopup.java delete mode 100644 libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatRestartButton.java delete mode 100644 libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUIController.java delete mode 100644 libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUILayout.java delete mode 100644 libs/WindowManager/Shell/src/com/android/wm/shell/sizecompatui/SizeCompatUIWindowManager.java create mode 100644 libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/OWNERS create mode 100644 libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitscreenEventLogger.java create mode 100644 libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskUnfoldController.java create mode 100644 libs/WindowManager/Shell/src/com/android/wm/shell/stagesplit/ISplitScreen.aidl create mode 100644 libs/WindowManager/Shell/src/com/android/wm/shell/stagesplit/ISplitScreenListener.aidl create mode 100644 libs/WindowManager/Shell/src/com/android/wm/shell/stagesplit/MainStage.java create mode 100644 libs/WindowManager/Shell/src/com/android/wm/shell/stagesplit/OWNERS create mode 100644 libs/WindowManager/Shell/src/com/android/wm/shell/stagesplit/OutlineManager.java create mode 100644 libs/WindowManager/Shell/src/com/android/wm/shell/stagesplit/OutlineView.java create mode 100644 libs/WindowManager/Shell/src/com/android/wm/shell/stagesplit/SideStage.java create mode 100644 libs/WindowManager/Shell/src/com/android/wm/shell/stagesplit/SplitScreen.java create mode 100644 libs/WindowManager/Shell/src/com/android/wm/shell/stagesplit/SplitScreenController.java create mode 100644 libs/WindowManager/Shell/src/com/android/wm/shell/stagesplit/SplitScreenTransitions.java create mode 100644 libs/WindowManager/Shell/src/com/android/wm/shell/stagesplit/SplitscreenEventLogger.java create mode 100644 libs/WindowManager/Shell/src/com/android/wm/shell/stagesplit/StageCoordinator.java create mode 100644 libs/WindowManager/Shell/src/com/android/wm/shell/stagesplit/StageTaskListener.java create mode 100644 libs/WindowManager/Shell/src/com/android/wm/shell/stagesplit/StageTaskUnfoldController.java create mode 100644 libs/WindowManager/Shell/src/com/android/wm/shell/transition/LegacyTransitions.java create mode 100644 libs/WindowManager/Shell/src/com/android/wm/shell/transition/ScreenRotationAnimation.java create mode 100644 libs/WindowManager/Shell/src/com/android/wm/shell/transition/WindowThumbnail.java create mode 100644 libs/WindowManager/Shell/src/com/android/wm/shell/unfold/ShellUnfoldProgressProvider.java create mode 100644 libs/WindowManager/Shell/src/com/android/wm/shell/unfold/UnfoldBackgroundController.java create mode 100644 libs/WindowManager/Shell/src/com/android/wm/shell/util/CounterRotator.java create mode 100644 libs/WindowManager/Shell/src/com/android/wm/shell/util/GroupedRecentTaskInfo.aidl create mode 100644 libs/WindowManager/Shell/src/com/android/wm/shell/util/GroupedRecentTaskInfo.java create mode 100644 libs/WindowManager/Shell/src/com/android/wm/shell/util/StagedSplitBounds.java create mode 100644 libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/BaseBubbleScreen.kt create mode 100644 libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/DismissBubbleScreen.kt create mode 100644 libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/ExpandBubbleScreen.kt create mode 100644 libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/LaunchBubbleScreen.kt create mode 100644 libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/MultiBubblesScreen.kt create mode 100644 libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/LaunchBubbleHelper.kt delete mode 100644 libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterExitPipTest.kt create mode 100644 libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppTransition.kt create mode 100644 libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipTransition.kt create mode 100644 libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaExpandButtonClickTest.kt create mode 100644 libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaIntentTest.kt create mode 100644 libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipWithDismissButtonTest.kt create mode 100644 libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipWithSwipeDownTest.kt create mode 100644 libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt delete mode 100644 libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/Extensions.kt create mode 100644 libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipDownShelfHeightChangeTest.kt create mode 100644 libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipShelfHeightTransition.kt create mode 100644 libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipUpShelfHeightChangeTest.kt delete mode 100644 libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipCloseTransition.kt delete mode 100644 libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipCloseWithDismissButtonTest.kt delete mode 100644 libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipCloseWithSwipeTest.kt delete mode 100644 libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipShelfHeightTest.kt delete mode 100644 libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipToAppTest.kt create mode 100644 libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/res/drawable/bg.png create mode 100644 libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/res/drawable/ic_bubble.xml create mode 100644 libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/res/drawable/ic_message.xml create mode 100644 libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/res/layout/activity_bubble.xml create mode 100644 libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/res/layout/activity_main.xml create mode 100644 libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/src/com/android/wm/shell/flicker/testapp/BubbleActivity.java create mode 100644 libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/src/com/android/wm/shell/flicker/testapp/BubbleHelper.java create mode 100644 libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/src/com/android/wm/shell/flicker/testapp/LaunchBubbleActivity.java create mode 100644 libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayInsetsControllerTest.java create mode 100644 libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIControllerTest.java create mode 100644 libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUILayoutTest.java create mode 100644 libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIWindowManagerTest.java create mode 100644 libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropControllerTest.java create mode 100644 libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/fullscreen/FullscreenTaskListenerTest.java create mode 100644 libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java create mode 100644 libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/StagedSplitBoundsTest.java delete mode 100644 libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sizecompatui/SizeCompatHintPopupTest.java delete mode 100644 libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sizecompatui/SizeCompatRestartButtonTest.java delete mode 100644 libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sizecompatui/SizeCompatUIControllerTest.java delete mode 100644 libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sizecompatui/SizeCompatUILayoutTest.java create mode 100644 libs/hwui/renderthread/RenderEffectCapabilityQuery.cpp create mode 100644 libs/hwui/renderthread/RenderEffectCapabilityQuery.h create mode 100644 libs/hwui/tests/unit/RenderEffectCapabilityQueryTests.cpp create mode 100644 media/java/android/media/ISpatializerCallback.aidl create mode 100644 media/java/android/media/ISpatializerHeadToSoundStagePoseCallback.aidl create mode 100644 media/java/android/media/ISpatializerHeadTrackingModeCallback.aidl create mode 100644 media/java/android/media/ISpatializerOutputCallback.aidl create mode 100644 media/java/android/media/Spatializer.java create mode 100644 packages/SettingsLib/ActivityEmbedding/Android.bp create mode 100644 packages/SettingsLib/ActivityEmbedding/AndroidManifest.xml create mode 100644 packages/SettingsLib/ActivityEmbedding/src/com/android/settingslib/activityembedding/ActivityEmbeddingUtils.java create mode 100644 packages/SettingsLib/src/com/android/settingslib/applications/RecentAppOpsAccess.java delete mode 100644 packages/SettingsLib/src/com/android/settingslib/location/RecentLocationAccesses.java create mode 100644 packages/SettingsLib/src/com/android/settingslib/wifi/WifiRestrictionsCache.java create mode 100644 packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/RecentAppOpsAccessesTest.java delete mode 100644 packages/SettingsLib/tests/robotests/src/com/android/settingslib/location/RecentLocationAccessesTest.java create mode 100644 packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiRestrictionsCacheTest.java create mode 100644 packages/SystemUI/animation/res/anim/launch_dialog_enter.xml create mode 100644 packages/SystemUI/animation/res/anim/launch_dialog_exit.xml delete mode 100644 packages/SystemUI/animation/res/interpolator/launch_animation_interpolator_x.xml delete mode 100644 packages/SystemUI/animation/res/interpolator/launch_animation_interpolator_y.xml create mode 100644 packages/SystemUI/animation/res/values/ids.xml create mode 100644 packages/SystemUI/animation/res/values/styles.xml create mode 100644 packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt create mode 100644 packages/SystemUI/animation/src/com/android/systemui/animation/LaunchAnimator.kt create mode 100644 packages/SystemUI/animation/src/com/android/systemui/animation/LaunchableView.kt create mode 100644 packages/SystemUI/animation/src/com/android/systemui/animation/ShadeInterpolation.kt create mode 100644 packages/SystemUI/docs/keyguard.md create mode 100644 packages/SystemUI/docs/keyguard/aod.md create mode 100644 packages/SystemUI/docs/keyguard/bouncer.md create mode 100644 packages/SystemUI/monet/Android.bp create mode 100644 packages/SystemUI/monet/AndroidManifest.xml create mode 100644 packages/SystemUI/monet/src/com/android/systemui/monet/ColorScheme.kt create mode 100644 packages/SystemUI/monet/src/com/android/systemui/monet/Shades.java create mode 100644 packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSContainerController.kt create mode 100644 packages/SystemUI/res-keyguard/color/numpad_key_color_secondary.xml delete mode 100644 packages/SystemUI/res-keyguard/drawable/bubble_manage_user_education_bg.xml delete mode 100644 packages/SystemUI/res-keyguard/drawable/circle_white.xml delete mode 100644 packages/SystemUI/res-keyguard/drawable/face_auth_wallpaper.png create mode 100644 packages/SystemUI/res-keyguard/drawable/fp_to_unlock.xml delete mode 100644 packages/SystemUI/res-keyguard/drawable/ic_done_black_24dp.xml create mode 100644 packages/SystemUI/res-keyguard/drawable/ic_fingerprint.xml create mode 100644 packages/SystemUI/res-keyguard/drawable/ic_lock.xml create mode 100644 packages/SystemUI/res-keyguard/drawable/ic_lock_aod.xml create mode 100644 packages/SystemUI/res-keyguard/drawable/ic_unlocked.xml create mode 100644 packages/SystemUI/res-keyguard/drawable/ic_unlocked_aod.xml create mode 100644 packages/SystemUI/res-keyguard/drawable/lock_aod_to_ls.xml create mode 100644 packages/SystemUI/res-keyguard/drawable/lock_ls_to_aod.xml create mode 100644 packages/SystemUI/res-keyguard/drawable/lock_to_unlock.xml delete mode 100644 packages/SystemUI/res-keyguard/drawable/ripple_drawable_pin.xml create mode 100644 packages/SystemUI/res-keyguard/drawable/super_lock_icon.xml create mode 100644 packages/SystemUI/res-keyguard/drawable/unlock_to_fp.xml create mode 100644 packages/SystemUI/res-keyguard/drawable/unlocked_aod_to_ls.xml create mode 100644 packages/SystemUI/res-keyguard/drawable/unlocked_ls_to_aod.xml create mode 100644 packages/SystemUI/res-keyguard/drawable/unlocked_to_aod_lock.xml create mode 100644 packages/SystemUI/res-keyguard/layout/footer_actions.xml create mode 100644 packages/SystemUI/res-keyguard/layout/keyguard_slice_view.xml delete mode 100644 packages/SystemUI/res-keyguard/layout/keyguard_status_area.xml create mode 100644 packages/SystemUI/res-keyguard/values-land/donottranslate.xml delete mode 100644 packages/SystemUI/res-keyguard/values-land/integers.xml delete mode 100644 packages/SystemUI/res-keyguard/values-port/bools.xml delete mode 100644 packages/SystemUI/res-keyguard/values-port/integers.xml create mode 100644 packages/SystemUI/res-keyguard/values-sw600dp-land/donottranslate.xml delete mode 100644 packages/SystemUI/res-keyguard/values-sw600dp/bools.xml create mode 100644 packages/SystemUI/res-keyguard/values-sw720dp/bools.xml delete mode 100644 packages/SystemUI/res/anim/bottomsheet_in.xml delete mode 100644 packages/SystemUI/res/anim/bottomsheet_out.xml delete mode 100644 packages/SystemUI/res/anim/fp_to_unlock.xml delete mode 100644 packages/SystemUI/res/anim/lock_to_unlock.xml delete mode 100644 packages/SystemUI/res/anim/tv_pip_controls_focus_gain_animation.xml delete mode 100644 packages/SystemUI/res/anim/tv_pip_controls_focus_loss_animation.xml delete mode 100644 packages/SystemUI/res/anim/tv_pip_menu_fade_in_animation.xml delete mode 100644 packages/SystemUI/res/anim/tv_pip_menu_fade_out_animation.xml delete mode 100644 packages/SystemUI/res/color/notification_guts_buttons.xml delete mode 100644 packages/SystemUI/res/color/pin_delete_color.xml delete mode 100644 packages/SystemUI/res/color/pin_divider_color.xml delete mode 100644 packages/SystemUI/res/color/qs_user_detail_name.xml delete mode 100644 packages/SystemUI/res/color/screenrecord_switch_thumb_color.xml delete mode 100644 packages/SystemUI/res/color/screenrecord_switch_track_color.xml delete mode 100644 packages/SystemUI/res/color/settingslib_state_off.xml delete mode 100644 packages/SystemUI/res/drawable-hdpi/pip_dismiss_scrim.9.png delete mode 100644 packages/SystemUI/res/drawable-hdpi/screenshot_panel.9.png delete mode 100644 packages/SystemUI/res/drawable-hdpi/search_bg_transparent.9.png delete mode 100644 packages/SystemUI/res/drawable-mcc310-mnc004/ic_5g_plus_mobiledata.xml delete mode 100644 packages/SystemUI/res/drawable-mcc311-mnc480/ic_5g_plus_mobiledata.xml delete mode 100644 packages/SystemUI/res/drawable-mdpi/one_handed_tutorial.png delete mode 100644 packages/SystemUI/res/drawable-mdpi/pip_dismiss_scrim.9.png delete mode 100644 packages/SystemUI/res/drawable-mdpi/screenshot_panel.9.png delete mode 100644 packages/SystemUI/res/drawable-mdpi/search_bg_transparent.9.png delete mode 100644 packages/SystemUI/res/drawable-nodpi/android_11_dial.xml delete mode 100644 packages/SystemUI/res/drawable-nodpi/work_challenge_background.png delete mode 100644 packages/SystemUI/res/drawable-xhdpi/one_handed_tutorial.png delete mode 100644 packages/SystemUI/res/drawable-xhdpi/pip_dismiss_scrim.9.png delete mode 100644 packages/SystemUI/res/drawable-xhdpi/remote.png delete mode 100644 packages/SystemUI/res/drawable-xhdpi/search_bg_transparent.9.png delete mode 100644 packages/SystemUI/res/drawable-xxhdpi/one_handed_tutorial.png delete mode 100644 packages/SystemUI/res/drawable-xxhdpi/pip_dismiss_scrim.9.png delete mode 100644 packages/SystemUI/res/drawable-xxhdpi/search_bg_transparent.9.png delete mode 100644 packages/SystemUI/res/drawable-xxxhdpi/one_handed_tutorial.png delete mode 100644 packages/SystemUI/res/drawable-xxxhdpi/pip_dismiss_scrim.9.png delete mode 100644 packages/SystemUI/res/drawable/assist_orb_navbar_scrim.xml delete mode 100644 packages/SystemUI/res/drawable/assist_orb_scrim.xml delete mode 100644 packages/SystemUI/res/drawable/circle_blue_40dp.xml delete mode 100644 packages/SystemUI/res/drawable/circle_white_40dp.xml delete mode 100644 packages/SystemUI/res/drawable/floating_dismiss_gradient_transition.xml delete mode 100644 packages/SystemUI/res/drawable/ic_add_to_home.xml delete mode 100644 packages/SystemUI/res/drawable/ic_arrow_downward.xml delete mode 100644 packages/SystemUI/res/drawable/ic_camera.xml delete mode 100644 packages/SystemUI/res/drawable/ic_cancel_24.xml delete mode 100644 packages/SystemUI/res/drawable/ic_chevron_up.xml delete mode 100644 packages/SystemUI/res/drawable/ic_clear.xml delete mode 100644 packages/SystemUI/res/drawable/ic_demote_conversation.xml delete mode 100644 packages/SystemUI/res/drawable/ic_drag_handle.xml delete mode 100644 packages/SystemUI/res/drawable/ic_exit_to_app.xml delete mode 100644 packages/SystemUI/res/drawable/ic_fingerprint.xml delete mode 100644 packages/SystemUI/res/drawable/ic_fullscreen_white_24dp.xml delete mode 100644 packages/SystemUI/res/drawable/ic_important.xml create mode 100644 packages/SystemUI/res/drawable/ic_kg_fingerprint.xml delete mode 100644 packages/SystemUI/res/drawable/ic_notification_block.xml delete mode 100644 packages/SystemUI/res/drawable/ic_notification_gentle.xml delete mode 100644 packages/SystemUI/res/drawable/ic_notification_interruptive.xml delete mode 100644 packages/SystemUI/res/drawable/ic_pause_white.xml delete mode 100644 packages/SystemUI/res/drawable/ic_photo_camera.xml delete mode 100644 packages/SystemUI/res/drawable/ic_play_arrow_white.xml delete mode 100644 packages/SystemUI/res/drawable/ic_power_settings_new_gm2_24px.xml delete mode 100644 packages/SystemUI/res/drawable/ic_qs_bluetooth_on.xml delete mode 100644 packages/SystemUI/res/drawable/ic_qs_no_internet_airplane.xml delete mode 100644 packages/SystemUI/res/drawable/ic_qs_screenrecord.xml delete mode 100644 packages/SystemUI/res/drawable/ic_qs_wifi_0.xml delete mode 100644 packages/SystemUI/res/drawable/ic_settings_16dp.xml delete mode 100644 packages/SystemUI/res/drawable/ic_tune_black_16dp.xml delete mode 100644 packages/SystemUI/res/drawable/ic_unlock.xml delete mode 100644 packages/SystemUI/res/drawable/ic_volume_voice.xml delete mode 100644 packages/SystemUI/res/drawable/ic_width.xml delete mode 100644 packages/SystemUI/res/drawable/internet_dialog_background.xml delete mode 100644 packages/SystemUI/res/drawable/internet_dialog_footer_background.xml delete mode 100644 packages/SystemUI/res/drawable/internet_dialog_rounded_top_corner_background.xml delete mode 100644 packages/SystemUI/res/drawable/media_output_dialog_background.xml create mode 100644 packages/SystemUI/res/drawable/media_output_dialog_button_background.xml delete mode 100644 packages/SystemUI/res/drawable/pip_icon.xml delete mode 100644 packages/SystemUI/res/drawable/pip_resize_handle.xml delete mode 100644 packages/SystemUI/res/drawable/qs_bg_gradient.xml create mode 100644 packages/SystemUI/res/drawable/qs_dialog_btn_filled.xml create mode 100644 packages/SystemUI/res/drawable/qs_dialog_btn_outline.xml delete mode 100644 packages/SystemUI/res/drawable/qs_dual_tile_caret.xml delete mode 100644 packages/SystemUI/res/drawable/rounded_bg_bottom_background.xml delete mode 100644 packages/SystemUI/res/drawable/rounded_bg_top.xml create mode 100644 packages/SystemUI/res/drawable/rounded_corner_bottom_secondary.xml create mode 100644 packages/SystemUI/res/drawable/rounded_corner_top_secondary.xml create mode 100644 packages/SystemUI/res/drawable/rounded_secondary.xml delete mode 100644 packages/SystemUI/res/drawable/screenrecord_button_background_outline.xml delete mode 100644 packages/SystemUI/res/drawable/screenrecord_switch_thumb.xml delete mode 100644 packages/SystemUI/res/drawable/screenrecord_switch_track.xml delete mode 100644 packages/SystemUI/res/drawable/screenshot_rounded_corners.xml delete mode 100644 packages/SystemUI/res/drawable/settingslib_switch_bar_bg_disabled.xml delete mode 100644 packages/SystemUI/res/drawable/stat_notify_image.xml delete mode 100644 packages/SystemUI/res/drawable/stat_sys_camera.xml delete mode 100644 packages/SystemUI/res/drawable/stat_sys_location.xml delete mode 100644 packages/SystemUI/res/drawable/stat_sys_mic_none.xml delete mode 100644 packages/SystemUI/res/drawable/tv_ic_mic_white.xml create mode 100644 packages/SystemUI/res/drawable/udfps_enroll_checkmark.xml delete mode 100644 packages/SystemUI/res/interpolator/assist_disclosure_trace.xml delete mode 100644 packages/SystemUI/res/interpolator/error_to_trustedstate_animation_interpolator_0.xml delete mode 100644 packages/SystemUI/res/interpolator/error_to_trustedstate_animation_interpolator_1.xml delete mode 100644 packages/SystemUI/res/interpolator/error_to_trustedstate_animation_interpolator_2.xml delete mode 100644 packages/SystemUI/res/interpolator/error_to_trustedstate_animation_interpolator_3.xml delete mode 100644 packages/SystemUI/res/interpolator/error_to_trustedstate_animation_interpolator_4.xml delete mode 100644 packages/SystemUI/res/interpolator/error_to_trustedstate_animation_interpolator_5.xml delete mode 100644 packages/SystemUI/res/interpolator/error_to_trustedstate_animation_interpolator_6.xml delete mode 100644 packages/SystemUI/res/interpolator/ic_caret_down_animation_interpolator_0.xml delete mode 100644 packages/SystemUI/res/interpolator/ic_caret_up_animation_interpolator_0.xml delete mode 100644 packages/SystemUI/res/interpolator/ic_fingerprint_toerror_animation_interpolator_0.xml delete mode 100644 packages/SystemUI/res/interpolator/ic_fingerprint_toerror_animation_interpolator_1.xml delete mode 100644 packages/SystemUI/res/interpolator/ic_fingerprint_toerror_animation_interpolator_2.xml delete mode 100644 packages/SystemUI/res/interpolator/ic_fingerprint_toerror_animation_interpolator_3.xml delete mode 100644 packages/SystemUI/res/interpolator/ic_fingerprint_toerror_animation_interpolator_4.xml delete mode 100644 packages/SystemUI/res/interpolator/ic_fingerprint_toerror_animation_interpolator_5.xml delete mode 100644 packages/SystemUI/res/interpolator/ic_fingerprint_toerror_animation_interpolator_6.xml delete mode 100644 packages/SystemUI/res/interpolator/ic_fingerprint_tofp_animation_interpolator_0.xml delete mode 100644 packages/SystemUI/res/interpolator/ic_fingerprint_tofp_animation_interpolator_1.xml delete mode 100644 packages/SystemUI/res/interpolator/ic_fingerprint_tofp_animation_interpolator_2.xml delete mode 100644 packages/SystemUI/res/interpolator/ic_fingerprint_tofp_animation_interpolator_3.xml delete mode 100644 packages/SystemUI/res/interpolator/ic_fingerprint_tofp_animation_interpolator_4.xml delete mode 100644 packages/SystemUI/res/interpolator/ic_fingerprint_tofp_animation_interpolator_5.xml delete mode 100644 packages/SystemUI/res/interpolator/ic_landscape_to_rotate_animation_interpolator_0.xml delete mode 100644 packages/SystemUI/res/interpolator/ic_rotate_to_landscape_animation_interpolator_0.xml delete mode 100644 packages/SystemUI/res/interpolator/ic_rotate_to_portrait_animation_interpolator_0.xml delete mode 100644 packages/SystemUI/res/interpolator/lockscreen_fingerprint_draw_off_animation_interpolator_0.xml delete mode 100644 packages/SystemUI/res/interpolator/lockscreen_fingerprint_draw_off_animation_interpolator_1.xml delete mode 100644 packages/SystemUI/res/interpolator/lockscreen_fingerprint_draw_on_animation_interpolator_0.xml delete mode 100644 packages/SystemUI/res/interpolator/lockscreen_fingerprint_draw_on_animation_interpolator_1.xml delete mode 100644 packages/SystemUI/res/interpolator/trusted_state_to_error_animation_interpolator_0.xml delete mode 100644 packages/SystemUI/res/interpolator/trusted_state_to_error_animation_interpolator_1.xml delete mode 100644 packages/SystemUI/res/interpolator/trusted_state_to_error_animation_interpolator_2.xml delete mode 100644 packages/SystemUI/res/interpolator/trusted_state_to_error_animation_interpolator_3.xml delete mode 100644 packages/SystemUI/res/interpolator/trusted_state_to_error_animation_interpolator_4.xml delete mode 100644 packages/SystemUI/res/interpolator/trusted_state_to_error_animation_interpolator_5.xml delete mode 100644 packages/SystemUI/res/interpolator/wireless_charging_animation_interpolator_0.xml delete mode 100644 packages/SystemUI/res/interpolator/wireless_charging_animation_interpolator_1.xml delete mode 100644 packages/SystemUI/res/layout-land/global_actions_column_seascape.xml delete mode 100644 packages/SystemUI/res/layout-land/global_actions_grid_item.xml delete mode 100644 packages/SystemUI/res/layout-land/global_actions_grid_seascape.xml delete mode 100644 packages/SystemUI/res/layout-sw600dp-land/global_actions_grid_v2.xml delete mode 100644 packages/SystemUI/res/layout-sw600dp/global_actions_grid_v2.xml create mode 100644 packages/SystemUI/res/layout/alert_dialog_button_bar_systemui.xml create mode 100644 packages/SystemUI/res/layout/alert_dialog_systemui.xml create mode 100644 packages/SystemUI/res/layout/alert_dialog_title_systemui.xml delete mode 100644 packages/SystemUI/res/layout/app_ops_info.xml delete mode 100644 packages/SystemUI/res/layout/assist_orb.xml create mode 100644 packages/SystemUI/res/layout/combined_qs_header.xml delete mode 100644 packages/SystemUI/res/layout/controls_icon.xml delete mode 100644 packages/SystemUI/res/layout/global_actions_change_panel.xml delete mode 100644 packages/SystemUI/res/layout/global_actions_grid_item.xml delete mode 100644 packages/SystemUI/res/layout/global_actions_grid_v2.xml delete mode 100644 packages/SystemUI/res/layout/global_actions_item.xml delete mode 100644 packages/SystemUI/res/layout/global_actions_lock_view.xml delete mode 100644 packages/SystemUI/res/layout/horizontal_divider.xml delete mode 100644 packages/SystemUI/res/layout/mland.xml delete mode 100644 packages/SystemUI/res/layout/mland_scorefield.xml delete mode 100644 packages/SystemUI/res/layout/nav_control_widget.xml delete mode 100644 packages/SystemUI/res/layout/nav_width_view.xml delete mode 100644 packages/SystemUI/res/layout/navigation_bar_app_item.xml delete mode 100644 packages/SystemUI/res/layout/people_space_widget.xml delete mode 100644 packages/SystemUI/res/layout/people_space_widget_item.xml delete mode 100644 packages/SystemUI/res/layout/preference_widget_settings.xml delete mode 100644 packages/SystemUI/res/layout/punctuation_layout.xml delete mode 100644 packages/SystemUI/res/layout/qs_add_tiles_list.xml delete mode 100644 packages/SystemUI/res/layout/qs_page_indicator.xml delete mode 100644 packages/SystemUI/res/layout/qs_tile_layout.xml create mode 100644 packages/SystemUI/res/layout/qs_user_dialog_content.xml delete mode 100644 packages/SystemUI/res/layout/recents_onboarding.xml delete mode 100644 packages/SystemUI/res/layout/remember_permission_checkbox.xml delete mode 100644 packages/SystemUI/res/layout/rounded_corners.xml delete mode 100644 packages/SystemUI/res/layout/shelf_menu_anchor.xml create mode 100644 packages/SystemUI/res/layout/split_shade_header.xml create mode 100644 packages/SystemUI/res/layout/udfps_aod_lock_icon.xml delete mode 100644 packages/SystemUI/res/layout/udfps_surface_view.xml delete mode 100644 packages/SystemUI/res/mipmap-hdpi/ic_daydreams.png delete mode 100644 packages/SystemUI/res/mipmap-mdpi/ic_daydreams.png delete mode 100644 packages/SystemUI/res/mipmap-xhdpi/ic_daydreams.png create mode 100644 packages/SystemUI/res/raw/sfps_pulse.json create mode 100644 packages/SystemUI/res/raw/sfps_pulse_landscape.json delete mode 100644 packages/SystemUI/res/transition/tv_privacy_chip_collapse.xml delete mode 100644 packages/SystemUI/res/transition/tv_privacy_chip_expand.xml delete mode 100644 packages/SystemUI/res/values-h560dp-xhdpi/config.xml delete mode 100644 packages/SystemUI/res/values-sw410dp/config.xml create mode 100644 packages/SystemUI/res/values-sw600dp-land/dimens.xml create mode 100644 packages/SystemUI/res/values-sw600dp-port/config.xml create mode 100644 packages/SystemUI/res/values-sw720dp-land/config.xml create mode 100644 packages/SystemUI/res/values-sw720dp-port/config.xml delete mode 100644 packages/SystemUI/res/values-sw720dp/config.xml delete mode 100644 packages/SystemUI/res/values/arrays_tv.xml delete mode 100644 packages/SystemUI/res/values/mland_strings.xml create mode 100644 packages/SystemUI/res/xml/combined_qs_header_scene.xml create mode 100644 packages/SystemUI/res/xml/qqs_header.xml create mode 100644 packages/SystemUI/res/xml/qs_header.xml create mode 100644 packages/SystemUI/res/xml/split_header.xml create mode 100644 packages/SystemUI/shared/src/com/android/systemui/flags/Flag.kt create mode 100644 packages/SystemUI/shared/src/com/android/systemui/flags/FlagManager.kt create mode 100644 packages/SystemUI/shared/src/com/android/systemui/flags/FlagReader.kt create mode 100644 packages/SystemUI/shared/src/com/android/systemui/navigationbar/buttons/KeyButtonRipple.java create mode 100644 packages/SystemUI/shared/src/com/android/systemui/shared/animation/UnfoldMoveFromCenterAnimator.kt create mode 100644 packages/SystemUI/shared/src/com/android/systemui/shared/navigationbar/RegionSamplingHelper.java create mode 100644 packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginActionManager.java delete mode 100644 packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInitializer.java create mode 100644 packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInstance.java delete mode 100644 packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInstanceManager.java create mode 100644 packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/ViewRippler.java create mode 100644 packages/SystemUI/shared/src/com/android/systemui/shared/rotation/FloatingRotationButton.java create mode 100644 packages/SystemUI/shared/src/com/android/systemui/shared/rotation/FloatingRotationButtonPositionCalculator.kt create mode 100644 packages/SystemUI/shared/src/com/android/systemui/shared/rotation/FloatingRotationButtonView.java create mode 100644 packages/SystemUI/shared/src/com/android/systemui/shared/rotation/RotationButton.java create mode 100644 packages/SystemUI/shared/src/com/android/systemui/shared/rotation/RotationButtonController.java create mode 100644 packages/SystemUI/shared/src/com/android/systemui/statusbar/policy/CallbackController.java create mode 100644 packages/SystemUI/shared/src/com/android/systemui/unfold/UnfoldTransitionFactory.kt create mode 100644 packages/SystemUI/shared/src/com/android/systemui/unfold/UnfoldTransitionProgressProvider.kt create mode 100644 packages/SystemUI/shared/src/com/android/systemui/unfold/config/ResourceUnfoldTransitionConfig.kt create mode 100644 packages/SystemUI/shared/src/com/android/systemui/unfold/config/UnfoldTransitionConfig.kt create mode 100644 packages/SystemUI/shared/src/com/android/systemui/unfold/progress/FixedTimingTransitionProgressProvider.kt create mode 100644 packages/SystemUI/shared/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProvider.kt create mode 100644 packages/SystemUI/shared/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt create mode 100644 packages/SystemUI/shared/src/com/android/systemui/unfold/updates/FoldStateProvider.kt create mode 100644 packages/SystemUI/shared/src/com/android/systemui/unfold/updates/hinge/EmptyHingeAngleProvider.kt create mode 100644 packages/SystemUI/shared/src/com/android/systemui/unfold/updates/hinge/HingeAngleProvider.kt create mode 100644 packages/SystemUI/shared/src/com/android/systemui/unfold/updates/hinge/HingeSensorAngleProvider.kt create mode 100644 packages/SystemUI/shared/src/com/android/systemui/unfold/updates/screen/ScreenStatusProvider.kt create mode 100644 packages/SystemUI/shared/src/com/android/systemui/unfold/util/NaturalRotationUnfoldProgressProvider.kt create mode 100644 packages/SystemUI/shared/src/com/android/systemui/unfold/util/ScaleAwareTransitionProgressProvider.kt create mode 100644 packages/SystemUI/shared/src/com/android/systemui/unfold/util/ScopedUnfoldTransitionProgressProvider.java create mode 100644 packages/SystemUI/src-debug/com/android/systemui/flags/FeatureFlagManager.java create mode 100644 packages/SystemUI/src-debug/com/android/systemui/flags/FlagsModule.kt create mode 100644 packages/SystemUI/src-release/com/android/systemui/flags/FeatureFlagManager.java create mode 100644 packages/SystemUI/src-release/com/android/systemui/flags/FlagsModule.kt create mode 100644 packages/SystemUI/src/com/android/keyguard/KeyguardUnfoldTransition.kt delete mode 100644 packages/SystemUI/src/com/android/systemui/BatteryMeterView.java delete mode 100644 packages/SystemUI/src/com/android/systemui/assist/AssistOrbContainer.java delete mode 100644 packages/SystemUI/src/com/android/systemui/assist/AssistOrbController.java delete mode 100644 packages/SystemUI/src/com/android/systemui/assist/AssistOrbView.java create mode 100644 packages/SystemUI/src/com/android/systemui/battery/BatteryMeterView.java create mode 100644 packages/SystemUI/src/com/android/systemui/battery/BatteryMeterViewController.java create mode 100644 packages/SystemUI/src/com/android/systemui/biometrics/BiometricDisplayListener.kt delete mode 100644 packages/SystemUI/src/com/android/systemui/biometrics/BiometricOrientationEventListener.kt delete mode 100644 packages/SystemUI/src/com/android/systemui/biometrics/SidefpsController.java create mode 100644 packages/SystemUI/src/com/android/systemui/biometrics/SidefpsController.kt delete mode 100644 packages/SystemUI/src/com/android/systemui/biometrics/SidefpsView.java delete mode 100644 packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollProgressBarSegment.java delete mode 100644 packages/SystemUI/src/com/android/systemui/dagger/WMSingleton.java delete mode 100644 packages/SystemUI/src/com/android/systemui/egg/MLand.java delete mode 100644 packages/SystemUI/src/com/android/systemui/egg/MLandActivity.java delete mode 100644 packages/SystemUI/src/com/android/systemui/flags/FeatureFlagReader.java create mode 100644 packages/SystemUI/src/com/android/systemui/flags/FeatureFlags.java create mode 100644 packages/SystemUI/src/com/android/systemui/flags/FlagWriter.kt create mode 100644 packages/SystemUI/src/com/android/systemui/flags/Flags.java delete mode 100644 packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java delete mode 100644 packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsInfoProvider.kt delete mode 100644 packages/SystemUI/src/com/android/systemui/keyguard/FaceAuthScreenBrightnessController.kt create mode 100644 packages/SystemUI/src/com/android/systemui/keyguard/LifecycleScreenStatusProvider.kt create mode 100644 packages/SystemUI/src/com/android/systemui/log/dagger/CollapsedSbFragmentLog.java create mode 100644 packages/SystemUI/src/com/android/systemui/log/dagger/LSShadeTransitionLog.java create mode 100644 packages/SystemUI/src/com/android/systemui/log/dagger/QSFragmentDisableLog.java create mode 100644 packages/SystemUI/src/com/android/systemui/log/dagger/SwipeStatusBarAwayLog.java create mode 100644 packages/SystemUI/src/com/android/systemui/navigationbar/NavBarHelper.java delete mode 100644 packages/SystemUI/src/com/android/systemui/navigationbar/RotationButton.java delete mode 100644 packages/SystemUI/src/com/android/systemui/navigationbar/RotationButtonController.java delete mode 100644 packages/SystemUI/src/com/android/systemui/navigationbar/buttons/KeyButtonRipple.java delete mode 100644 packages/SystemUI/src/com/android/systemui/navigationbar/gestural/FloatingRotationButton.java delete mode 100644 packages/SystemUI/src/com/android/systemui/navigationbar/gestural/RegionSamplingHelper.java delete mode 100644 packages/SystemUI/src/com/android/systemui/plugins/PluginInitializerImpl.java create mode 100644 packages/SystemUI/src/com/android/systemui/plugins/PluginsModule.java create mode 100644 packages/SystemUI/src/com/android/systemui/qs/FooterActionsController.kt create mode 100644 packages/SystemUI/src/com/android/systemui/qs/FooterActionsControllerBuilder.kt create mode 100644 packages/SystemUI/src/com/android/systemui/qs/FooterActionsView.kt create mode 100644 packages/SystemUI/src/com/android/systemui/qs/HeaderPrivacyIconsController.kt create mode 100644 packages/SystemUI/src/com/android/systemui/qs/QSFragmentDisableFlagsLogger.kt create mode 100644 packages/SystemUI/src/com/android/systemui/qs/QSSquishinessController.kt create mode 100644 packages/SystemUI/src/com/android/systemui/qs/QuickQSBrightnessController.kt create mode 100644 packages/SystemUI/src/com/android/systemui/qs/user/UserSwitchDialogController.kt create mode 100644 packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessMirrorHandler.kt delete mode 100644 packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSlider.java create mode 100644 packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSliderController.java create mode 100644 packages/SystemUI/src/com/android/systemui/settings/brightness/MirroredBrightnessController.kt create mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/DisableFlagsLogger.kt delete mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java create mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/OperatorNameViewController.java create mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputNotificationRebuilder.java delete mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/SuperStatusBarViewFactory.java create mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/charging/DwellRippleShader.kt create mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/connectivity/AccessPointController.kt create mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/connectivity/AccessPointControllerImpl.java create mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/connectivity/CallbackHandler.java create mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/connectivity/ConnectivityState.kt create mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/connectivity/EthernetIcons.java create mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/connectivity/EthernetSignalController.java create mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/connectivity/MobileSignalController.java create mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/connectivity/MobileState.kt create mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/connectivity/NetworkController.java create mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/connectivity/NetworkControllerImpl.java create mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/connectivity/SignalCallback.kt create mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/connectivity/SignalController.java create mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/connectivity/WifiIcons.java create mode 100755 packages/SystemUI/src/com/android/systemui/statusbar/connectivity/WifiSignalController.java create mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/connectivity/WifiState.kt create mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/gesture/SwipeStatusBarAwayGestureHandler.kt create mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/gesture/SwipeStatusBarAwayGestureLogger.kt create mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationFadeAware.java create mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/GutsCoordinator.kt create mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/GutsCoordinatorLogger.kt delete mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.java create mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.kt create mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RemoteInputCoordinator.kt create mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinator.kt create mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ShadeEventCoordinator.kt create mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ShadeEventCoordinatorLogger.kt create mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ViewConfigCoordinator.kt create mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/dagger/CoordinatorsModule.kt create mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/LegacyNotificationPresenterExtensions.java create mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/Invalidator.java create mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/InternalNotifUpdater.java create mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/SelfTrackingLifetimeExtender.kt create mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NodeSpecBuilder.kt create mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifGutsViewListener.kt create mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifGutsViewManager.kt create mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifShadeEventSource.kt create mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowDragController.java create mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationPriorityBucket.kt delete mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java create mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/phone/LSShadeTransitionLogger.kt create mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQSContainerController.kt delete mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java delete mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelExpansionListener.java create mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt create mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/phone/SplitShadeHeaderController.kt create mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarCommandQueueCallbacks.java create mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarDemoMode.java create mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeadsUpChangeListener.java create mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHideIconsForBouncerManager.kt create mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarMoveFromCenterAnimationController.kt delete mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java delete mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java create mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialogManager.java create mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java create mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentLogger.kt create mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/dagger/StatusBarFragmentComponent.java create mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/dagger/StatusBarFragmentModule.java create mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/dagger/StatusBarFragmentScope.java create mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/phone/panelstate/PanelExpansionListener.java create mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/phone/panelstate/PanelExpansionStateManager.kt create mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/phone/panelstate/PanelStateListener.kt delete mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessPointControllerImpl.java delete mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/policy/CallbackController.java delete mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/policy/CallbackHandler.java create mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/policy/DevicePostureController.java create mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/policy/DevicePostureControllerImpl.java delete mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerImpl.java create mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerImpl.kt create mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingController.java delete mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/policy/EthernetIcons.java delete mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/policy/EthernetSignalController.java delete mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java delete mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java delete mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputQuickSettingsDisabler.java create mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputQuickSettingsDisabler.kt delete mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/policy/SignalController.java delete mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiIcons.java delete mode 100755 packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java create mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowController.java create mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowModule.kt create mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowView.java create mode 100644 packages/SystemUI/src/com/android/systemui/unfold/SysUIUnfoldModule.kt create mode 100644 packages/SystemUI/src/com/android/systemui/unfold/UnfoldLightRevealOverlayAnimation.kt create mode 100644 packages/SystemUI/src/com/android/systemui/unfold/UnfoldProgressProvider.kt create mode 100644 packages/SystemUI/src/com/android/systemui/unfold/UnfoldTransitionModule.kt create mode 100644 packages/SystemUI/src/com/android/systemui/unfold/UnfoldTransitionWallpaperController.kt create mode 100644 packages/SystemUI/src/com/android/systemui/util/DumpUtils.kt delete mode 100644 packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java create mode 100644 packages/SystemUI/src/com/android/systemui/util/ListenerSet.kt create mode 100644 packages/SystemUI/src/com/android/systemui/util/TraceUtils.kt create mode 100644 packages/SystemUI/src/com/android/systemui/util/WallpaperController.kt create mode 100644 packages/SystemUI/src/com/android/systemui/util/concurrency/MessageRouter.java create mode 100644 packages/SystemUI/src/com/android/systemui/util/concurrency/MessageRouterImpl.java create mode 100644 packages/SystemUI/src/com/android/systemui/util/sensors/PostureDependentProximitySensor.java create mode 100644 packages/SystemUI/src/com/android/systemui/util/sensors/ProximityCheck.java create mode 100644 packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensorImpl.java create mode 100644 packages/SystemUI/src/com/android/systemui/util/sensors/ThresholdSensorEvent.java create mode 100644 packages/SystemUI/src/com/android/systemui/util/wrapper/RotationPolicyWrapper.kt create mode 100644 packages/SystemUI/src/com/android/systemui/util/wrapper/UtilWrapperModule.kt delete mode 100644 packages/SystemUI/src/com/android/systemui/wmshell/TvPipModule.java delete mode 100644 packages/SystemUI/src/com/android/systemui/wmshell/TvWMShellModule.java delete mode 100644 packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java delete mode 100644 packages/SystemUI/src/com/android/systemui/wmshell/WMShellConcurrencyModule.java delete mode 100644 packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java create mode 100644 packages/SystemUI/tests/src/com/android/keyguard/KeyguardUnfoldTransitionTest.kt create mode 100644 packages/SystemUI/tests/src/com/android/systemui/animation/DialogLaunchAnimatorTest.kt create mode 100644 packages/SystemUI/tests/src/com/android/systemui/animation/TestValues.kt create mode 100644 packages/SystemUI/tests/src/com/android/systemui/battery/BatteryMeterViewControllerTest.java create mode 100644 packages/SystemUI/tests/src/com/android/systemui/battery/BatteryMeterViewTest.kt create mode 100644 packages/SystemUI/tests/src/com/android/systemui/controls/ui/DetailDialogTest.kt create mode 100644 packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagManagerTest.java delete mode 100644 packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagReaderTest.java create mode 100644 packages/SystemUI/tests/src/com/android/systemui/flags/FlagsTest.java create mode 100644 packages/SystemUI/tests/src/com/android/systemui/fragments/FragmentServiceTest.kt delete mode 100644 packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogTest.java delete mode 100644 packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsInfoProviderTest.kt delete mode 100644 packages/SystemUI/tests/src/com/android/systemui/keyguard/FaceAuthScreenBrightnessControllerTest.kt create mode 100644 packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardUnlockAnimationControllerTest.kt create mode 100644 packages/SystemUI/tests/src/com/android/systemui/media/MediaCarouselControllerTest.kt create mode 100644 packages/SystemUI/tests/src/com/android/systemui/monet/ColorSchemeTest.java create mode 100644 packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavBarHelperTest.java create mode 100644 packages/SystemUI/tests/src/com/android/systemui/navigationbar/gestural/FloatingRotationButtonPositionCalculatorTest.kt create mode 100644 packages/SystemUI/tests/src/com/android/systemui/qs/FooterActionsControllerTest.kt create mode 100644 packages/SystemUI/tests/src/com/android/systemui/qs/HeaderPrivacyIconsControllerTest.kt create mode 100644 packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentDisableFlagsLoggerTest.kt delete mode 100644 packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.java create mode 100644 packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.kt create mode 100644 packages/SystemUI/tests/src/com/android/systemui/qs/QSSquishinessControllerTest.kt create mode 100644 packages/SystemUI/tests/src/com/android/systemui/qs/QuickQSBrightnessControllerTest.kt create mode 100644 packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ColorInversionTileTest.java create mode 100644 packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DndTileTest.kt delete mode 100644 packages/SystemUI/tests/src/com/android/systemui/qs/tiles/RotationLockTileTest.java create mode 100644 packages/SystemUI/tests/src/com/android/systemui/qs/user/UserSwitchDialogControllerTest.kt create mode 100644 packages/SystemUI/tests/src/com/android/systemui/settings/brightness/BrightnessSliderControllerTest.kt delete mode 100644 packages/SystemUI/tests/src/com/android/systemui/settings/brightness/BrightnessSliderTest.kt create mode 100644 packages/SystemUI/tests/src/com/android/systemui/shared/animation/UnfoldMoveFromCenterAnimatorTest.kt create mode 100644 packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginActionManagerTest.java delete mode 100644 packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginInstanceManagerTest.java create mode 100644 packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginInstanceTest.java create mode 100644 packages/SystemUI/tests/src/com/android/systemui/statusbar/DisableFlagsLoggerTest.kt create mode 100644 packages/SystemUI/tests/src/com/android/systemui/statusbar/LSShadeTransitionLoggerTest.kt create mode 100644 packages/SystemUI/tests/src/com/android/systemui/statusbar/RemoteInputNotificationRebuilderTest.java create mode 100644 packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/AccessPointControllerImplTest.kt create mode 100644 packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/CallbackHandlerTest.java create mode 100644 packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/MobileStateTest.java create mode 100644 packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerBaseTest.java create mode 100644 packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerDataTest.java create mode 100644 packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerEthernetTest.java create mode 100644 packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerSignalTest.java create mode 100644 packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerWifiTest.java create mode 100644 packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/GutsCoordinatorTest.kt create mode 100644 packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RemoteInputCoordinatorTest.kt create mode 100644 packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinatorTest.kt create mode 100644 packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ShadeEventCoordinatorTest.kt create mode 100644 packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/notifcollection/SelfTrackingLifetimeExtenderTest.kt create mode 100644 packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/render/NodeSpecBuilderTest.kt create mode 100644 packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowDragControllerTest.java create mode 100644 packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java delete mode 100644 packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollerControllerTest.java create mode 100644 packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt delete mode 100644 packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragmentTest.java create mode 100644 packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java create mode 100644 packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewTest.java create mode 100644 packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationQSContainerControllerTest.kt create mode 100644 packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt create mode 100644 packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewTest.kt create mode 100644 packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/SplitShadeHeaderControllerTest.kt create mode 100644 packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarCommandQueueCallbacksTest.java create mode 100644 packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarMoveFromCenterAnimationControllerTest.kt create mode 100644 packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationControllerTest.kt create mode 100644 packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentLoggerTest.kt create mode 100644 packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java create mode 100644 packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/panelstate/PanelExpansionStateManagerTest.kt delete mode 100644 packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/AccessPointControllerImplTest.kt delete mode 100644 packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CallbackHandlerTest.java create mode 100644 packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerImplTest.kt create mode 100644 packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingControllerTest.java delete mode 100644 packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java delete mode 100644 packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java delete mode 100644 packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerEthernetTest.java delete mode 100644 packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java delete mode 100644 packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java delete mode 100644 packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputQuickSettingsDisablerTest.java create mode 100644 packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputQuickSettingsDisablerTest.kt create mode 100644 packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RotationLockControllerImplTest.java create mode 100644 packages/SystemUI/tests/src/com/android/systemui/unfold/TestUnfoldTransitionProvider.kt create mode 100644 packages/SystemUI/tests/src/com/android/systemui/unfold/UnfoldTransitionWallpaperControllerTest.kt create mode 100644 packages/SystemUI/tests/src/com/android/systemui/unfold/updates/DeviceFoldStateProviderTest.kt create mode 100644 packages/SystemUI/tests/src/com/android/systemui/unfold/util/NaturalRotationUnfoldProgressProviderTest.kt create mode 100644 packages/SystemUI/tests/src/com/android/systemui/unfold/util/ScaleAwareUnfoldProgressProviderTest.kt create mode 100644 packages/SystemUI/tests/src/com/android/systemui/util/ListenerSetTest.kt create mode 100644 packages/SystemUI/tests/src/com/android/systemui/util/WallpaperControllerTest.kt create mode 100644 packages/SystemUI/tests/src/com/android/systemui/util/concurrency/MessageRouterImplTest.java create mode 100644 packages/SystemUI/tests/src/com/android/systemui/util/sensors/PostureDependentProximitySensorTest.java delete mode 100644 packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximitySensorDualTest.java create mode 100644 packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximitySensorImplDualTest.java create mode 100644 packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximitySensorImplSingleTest.java delete mode 100644 packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximitySensorSingleTest.java delete mode 100644 packages/overlays/AvoidAppsInCutoutOverlay/res/values-ar/strings.xml delete mode 100644 packages/overlays/AvoidAppsInCutoutOverlay/res/values-as/strings.xml delete mode 100644 packages/overlays/AvoidAppsInCutoutOverlay/res/values-az/strings.xml delete mode 100644 packages/overlays/AvoidAppsInCutoutOverlay/res/values-be/strings.xml delete mode 100644 packages/overlays/AvoidAppsInCutoutOverlay/res/values-bn/strings.xml delete mode 100644 packages/overlays/AvoidAppsInCutoutOverlay/res/values-ca/strings.xml delete mode 100644 packages/overlays/AvoidAppsInCutoutOverlay/res/values-et/strings.xml delete mode 100644 packages/overlays/AvoidAppsInCutoutOverlay/res/values-fa/strings.xml delete mode 100644 packages/overlays/AvoidAppsInCutoutOverlay/res/values-fr/strings.xml delete mode 100644 packages/overlays/AvoidAppsInCutoutOverlay/res/values-gu/strings.xml delete mode 100644 packages/overlays/AvoidAppsInCutoutOverlay/res/values-hi/strings.xml delete mode 100644 packages/overlays/AvoidAppsInCutoutOverlay/res/values-hu/strings.xml delete mode 100644 packages/overlays/AvoidAppsInCutoutOverlay/res/values-hy/strings.xml delete mode 100644 packages/overlays/AvoidAppsInCutoutOverlay/res/values-is/strings.xml delete mode 100644 packages/overlays/AvoidAppsInCutoutOverlay/res/values-iw/strings.xml delete mode 100644 packages/overlays/AvoidAppsInCutoutOverlay/res/values-kk/strings.xml delete mode 100644 packages/overlays/AvoidAppsInCutoutOverlay/res/values-kn/strings.xml delete mode 100644 packages/overlays/AvoidAppsInCutoutOverlay/res/values-ky/strings.xml delete mode 100644 packages/overlays/AvoidAppsInCutoutOverlay/res/values-lt/strings.xml delete mode 100644 packages/overlays/AvoidAppsInCutoutOverlay/res/values-lv/strings.xml delete mode 100644 packages/overlays/AvoidAppsInCutoutOverlay/res/values-ml/strings.xml delete mode 100644 packages/overlays/AvoidAppsInCutoutOverlay/res/values-mr/strings.xml delete mode 100644 packages/overlays/AvoidAppsInCutoutOverlay/res/values-my/strings.xml delete mode 100644 packages/overlays/AvoidAppsInCutoutOverlay/res/values-nb/strings.xml delete mode 100644 packages/overlays/AvoidAppsInCutoutOverlay/res/values-ne/strings.xml delete mode 100644 packages/overlays/AvoidAppsInCutoutOverlay/res/values-or/strings.xml delete mode 100644 packages/overlays/AvoidAppsInCutoutOverlay/res/values-pl/strings.xml delete mode 100644 packages/overlays/AvoidAppsInCutoutOverlay/res/values-sl/strings.xml delete mode 100644 packages/overlays/AvoidAppsInCutoutOverlay/res/values-sq/strings.xml delete mode 100644 packages/overlays/AvoidAppsInCutoutOverlay/res/values-sv/strings.xml delete mode 100644 packages/overlays/AvoidAppsInCutoutOverlay/res/values-ta/strings.xml delete mode 100644 packages/overlays/AvoidAppsInCutoutOverlay/res/values-te/strings.xml delete mode 100644 packages/overlays/AvoidAppsInCutoutOverlay/res/values-ur/strings.xml delete mode 100644 packages/overlays/AvoidAppsInCutoutOverlay/res/values-vi/strings.xml delete mode 100644 packages/overlays/AvoidAppsInCutoutOverlay/res/values-zh-rCN/strings.xml delete mode 100644 packages/overlays/AvoidAppsInCutoutOverlay/res/values-zh-rTW/strings.xml delete mode 100644 packages/overlays/AvoidAppsInCutoutOverlay/res/values-zu/strings.xml delete mode 100644 packages/overlays/DisplayCutoutEmulationCornerOverlay/res/values-land/config.xml delete mode 100644 packages/overlays/DisplayCutoutEmulationDoubleOverlay/res/values-land/config.xml delete mode 100644 packages/overlays/DisplayCutoutEmulationHoleOverlay/res/values-land/config.xml delete mode 100644 packages/overlays/DisplayCutoutEmulationNarrowOverlay/res/values-land/config.xml delete mode 100644 packages/overlays/DisplayCutoutEmulationTallOverlay/res/values-land/config.xml delete mode 100644 packages/overlays/DisplayCutoutEmulationWaterfallOverlay/res/values-land/config.xml delete mode 100644 packages/overlays/DisplayCutoutEmulationWideOverlay/res/values-land/config.xml delete mode 100644 packages/overlays/NoCutoutOverlay/res/values-ar/strings.xml delete mode 100644 packages/overlays/NoCutoutOverlay/res/values-as/strings.xml delete mode 100644 packages/overlays/NoCutoutOverlay/res/values-az/strings.xml delete mode 100644 packages/overlays/NoCutoutOverlay/res/values-be/strings.xml delete mode 100644 packages/overlays/NoCutoutOverlay/res/values-bn/strings.xml delete mode 100644 packages/overlays/NoCutoutOverlay/res/values-ca/strings.xml delete mode 100644 packages/overlays/NoCutoutOverlay/res/values-et/strings.xml delete mode 100644 packages/overlays/NoCutoutOverlay/res/values-fa/strings.xml delete mode 100644 packages/overlays/NoCutoutOverlay/res/values-fr/strings.xml delete mode 100644 packages/overlays/NoCutoutOverlay/res/values-gu/strings.xml delete mode 100644 packages/overlays/NoCutoutOverlay/res/values-hi/strings.xml delete mode 100644 packages/overlays/NoCutoutOverlay/res/values-hu/strings.xml delete mode 100644 packages/overlays/NoCutoutOverlay/res/values-hy/strings.xml delete mode 100644 packages/overlays/NoCutoutOverlay/res/values-is/strings.xml delete mode 100644 packages/overlays/NoCutoutOverlay/res/values-iw/strings.xml delete mode 100644 packages/overlays/NoCutoutOverlay/res/values-kk/strings.xml delete mode 100644 packages/overlays/NoCutoutOverlay/res/values-kn/strings.xml delete mode 100644 packages/overlays/NoCutoutOverlay/res/values-ky/strings.xml delete mode 100644 packages/overlays/NoCutoutOverlay/res/values-lt/strings.xml delete mode 100644 packages/overlays/NoCutoutOverlay/res/values-lv/strings.xml delete mode 100644 packages/overlays/NoCutoutOverlay/res/values-ml/strings.xml delete mode 100644 packages/overlays/NoCutoutOverlay/res/values-mr/strings.xml delete mode 100644 packages/overlays/NoCutoutOverlay/res/values-my/strings.xml delete mode 100644 packages/overlays/NoCutoutOverlay/res/values-nb/strings.xml delete mode 100644 packages/overlays/NoCutoutOverlay/res/values-ne/strings.xml delete mode 100644 packages/overlays/NoCutoutOverlay/res/values-or/strings.xml delete mode 100644 packages/overlays/NoCutoutOverlay/res/values-pl/strings.xml delete mode 100644 packages/overlays/NoCutoutOverlay/res/values-sl/strings.xml delete mode 100644 packages/overlays/NoCutoutOverlay/res/values-sq/strings.xml delete mode 100644 packages/overlays/NoCutoutOverlay/res/values-sv/strings.xml delete mode 100644 packages/overlays/NoCutoutOverlay/res/values-ta/strings.xml delete mode 100644 packages/overlays/NoCutoutOverlay/res/values-te/strings.xml delete mode 100644 packages/overlays/NoCutoutOverlay/res/values-ur/strings.xml delete mode 100644 packages/overlays/NoCutoutOverlay/res/values-vi/strings.xml delete mode 100644 packages/overlays/NoCutoutOverlay/res/values-zh-rCN/strings.xml delete mode 100644 packages/overlays/NoCutoutOverlay/res/values-zh-rTW/strings.xml delete mode 100644 packages/overlays/NoCutoutOverlay/res/values-zu/strings.xml delete mode 100644 services/accessibility/java/com/android/server/accessibility/AccessibilityTrace.java create mode 100644 services/core/java/com/android/server/audio/SpatializerHelper.java create mode 100644 services/core/java/com/android/server/biometrics/sensors/SensorOverlays.java delete mode 100644 services/core/java/com/android/server/biometrics/sensors/fingerprint/SidefpsHelper.java create mode 100644 services/core/java/com/android/server/compat/overrides/AppCompatOverridesParser.java create mode 100644 services/core/java/com/android/server/compat/overrides/AppCompatOverridesService.java create mode 100644 services/core/java/com/android/server/compat/overrides/OWNERS create mode 100644 services/core/java/com/android/server/compat/overrides/TEST_MAPPING create mode 100644 services/core/java/com/android/server/devicestate/OverrideRequest.java create mode 100644 services/core/java/com/android/server/devicestate/OverrideRequestController.java create mode 100644 services/core/java/com/android/server/soundtrigger_middleware/UptimeTimer.java create mode 100644 services/core/java/com/android/server/wallpaper/LocalColorRepository.java create mode 100644 services/core/java/com/android/server/wm/ActivityInterceptorCallback.java create mode 100644 services/core/java/com/android/server/wm/InputTarget.java create mode 100644 services/core/java/com/android/server/wm/LocaleOverlayHelper.java create mode 100644 services/core/java/com/android/server/wm/PackageConfigurationUpdaterImpl.java create mode 100644 services/core/java/com/android/server/wm/TaskFragment.java create mode 100644 services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java create mode 100644 services/devicepolicy/java/com/android/server/devicepolicy/OwnerShellData.java create mode 100644 services/tests/mockingservicestests/src/com/android/server/compat/OWNERS create mode 100644 services/tests/mockingservicestests/src/com/android/server/compat/overrides/AppCompatOverridesParserTest.java create mode 100644 services/tests/mockingservicestests/src/com/android/server/compat/overrides/AppCompatOverridesServiceTest.java create mode 100644 services/tests/mockingservicestests/src/com/android/server/compat/overrides/OWNERS create mode 100644 services/tests/mockingservicestests/src/com/android/server/devicepolicy/OwnerShellDataTest.java create mode 100644 services/tests/mockingservicestests/src/com/android/server/wallpaper/LocalColorRepositoryTest.java create mode 100644 services/tests/servicestests/src/com/android/server/biometrics/sensors/SensorOverlaysTest.java create mode 100644 services/tests/servicestests/src/com/android/server/camera/CameraServiceProxyTest.java create mode 100644 services/tests/servicestests/src/com/android/server/camera/OWNERS create mode 100644 services/tests/servicestests/src/com/android/server/devicestate/OverrideRequestControllerTest.java create mode 100644 services/tests/servicestests/src/com/android/server/soundtrigger_middleware/UptimeTimerTest.java create mode 100644 services/tests/servicestests/test-apps/StubApp/Android.bp create mode 100644 services/tests/servicestests/test-apps/StubApp/AndroidManifest.xml create mode 100644 services/tests/servicestests/test-apps/StubApp/src/com/android/servicestests/apps/stubapp/TestActivity.java create mode 100644 services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java create mode 100644 services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java create mode 100644 tests/FlickerTests/src/com/android/server/wm/flicker/helpers/NewTasksAppHelper.kt create mode 100644 tests/FlickerTests/src/com/android/server/wm/flicker/helpers/NonResizeableAppHelper.kt create mode 100644 tests/FlickerTests/src/com/android/server/wm/flicker/helpers/TwoActivitiesAppHelper.kt create mode 100644 tests/FlickerTests/src/com/android/server/wm/flicker/ime/LaunchAppShowImeOnStartTest.kt create mode 100644 tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowAndCloseTest.kt create mode 100644 tests/FlickerTests/src/com/android/server/wm/flicker/launch/ActivitiesTransitionTest.kt delete mode 100644 tests/FlickerTests/src/com/android/server/wm/flicker/launch/CommonAssertions.kt create mode 100644 tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt create mode 100644 tests/FlickerTests/src/com/android/server/wm/flicker/launch/TaskTransitionTest.kt create mode 100644 tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest.kt create mode 100644 tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest.kt create mode 100644 tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchFromLauncherTest.kt create mode 100644 tests/FlickerTests/test-apps/flickerapp/res/layout/activity_button.xml create mode 100644 tests/FlickerTests/test-apps/flickerapp/res/layout/activity_non_resizeable.xml create mode 100644 tests/FlickerTests/test-apps/flickerapp/res/layout/task_button.xml create mode 100644 tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ButtonActivity.java create mode 100644 tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/LaunchNewTaskActivity.java create mode 100644 tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/NonResizeableActivity.java diff --git a/Android.bp b/Android.bp index 2f34f8c0a7aa..8e3874cf45b7 100755 --- a/Android.bp +++ b/Android.bp @@ -112,6 +112,7 @@ filegroup { ":framework_native_aidl", ":gatekeeper_aidl", ":gsiservice_aidl", + ":guiconstants_aidl", ":idmap2_aidl", ":idmap2_core_aidl", ":incidentcompanion_aidl", @@ -362,6 +363,8 @@ java_defaults { "modules-utils-preconditions", "modules-utils-os", "framework-permission-aidl-java", + "spatializer-aidl-java", + "audiopolicy-types-aidl-java", ], } diff --git a/apct-tests/perftests/autofill/AndroidManifest.xml b/apct-tests/perftests/autofill/AndroidManifest.xml index 57595a213d20..de2a3f2c4bfc 100644 --- a/apct-tests/perftests/autofill/AndroidManifest.xml +++ b/apct-tests/perftests/autofill/AndroidManifest.xml @@ -16,6 +16,16 @@ + + + + + + + + + + { return Collections.unmodifiableMap(mAll); } + /** + * Asserts that this {@link AppSearchBatchResult} has no failures. + * + * @hide + */ + public void checkSuccess() { + if (!isSuccess()) { + throw new IllegalStateException("AppSearchBatchResult has failures: " + this); + } + } + @Override @NonNull public String toString() { diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/util/SchemaMigrationUtil.java b/apex/appsearch/framework/java/external/android/app/appsearch/util/SchemaMigrationUtil.java index 10e014bf9c9a..d6d53155b131 100644 --- a/apex/appsearch/framework/java/external/android/app/appsearch/util/SchemaMigrationUtil.java +++ b/apex/appsearch/framework/java/external/android/app/appsearch/util/SchemaMigrationUtil.java @@ -71,7 +71,7 @@ public final class SchemaMigrationUtil { /** * Checks the setSchema() call won't delete any types or has incompatible types after all {@link - * Migrator} has been triggered.. + * Migrator} has been triggered. */ public static void checkDeletedAndIncompatibleAfterMigration( @NonNull SetSchemaResponse setSchemaResponse, @NonNull Set activeMigrators) 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 db23a6dc3047..d4e32396187d 100644 --- a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java +++ b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java @@ -332,17 +332,20 @@ public class AppSearchManagerService extends SystemService { long totalLatencyStartTimeMillis = SystemClock.elapsedRealtime(); int callingUid = Binder.getCallingUid(); - UserHandle callingUser = handleIncomingUser(userHandle, callingUid); EXECUTOR.execute(() -> { @AppSearchResult.ResultCode int statusCode = AppSearchResult.RESULT_OK; AppSearchUserInstance instance = null; int operationSuccessCount = 0; int operationFailureCount = 0; try { - Context userContext = mContext.createContextAsUser(callingUser, /*flags=*/ 0); - verifyUserUnlocked(callingUser); - verifyCallingPackage(userContext, callingUser, callingUid, packageName); - verifyNotInstantApp(userContext, packageName); + verifyCaller(callingUid, packageName); + + // Obtain the user where the client wants to run the operations in. This should + // end up being the same as userHandle, assuming it is not a special user and + // the client is allowed to run operations in that user. + UserHandle targetUser = handleIncomingUser(userHandle, callingUid); + verifyUserUnlocked(targetUser); + List schemas = new ArrayList<>(schemaBundles.size()); for (int i = 0; i < schemaBundles.size(); i++) { schemas.add(new AppSearchSchema(schemaBundles.get(i))); @@ -359,7 +362,8 @@ public class AppSearchManagerService extends SystemService { } schemasVisibleToPackages.put(entry.getKey(), packageIdentifiers); } - instance = mAppSearchUserInstanceManager.getUserInstance(callingUser); + instance = mAppSearchUserInstanceManager.getUserInstance(targetUser); + // TODO(b/173532925): Implement logging for statsBuilder SetSchemaResponse setSchemaResponse = instance.getAppSearchImpl().setSchema( packageName, databaseName, @@ -368,7 +372,8 @@ public class AppSearchManagerService extends SystemService { schemasNotDisplayedBySystem, schemasVisibleToPackages, forceOverride, - schemaVersion); + schemaVersion, + /*setSchemaStatsBuilder=*/ null); ++operationSuccessCount; invokeCallbackOnResult(callback, AppSearchResult.newSuccessfulResult(setSchemaResponse.getBundle())); @@ -418,15 +423,18 @@ public class AppSearchManagerService extends SystemService { Objects.requireNonNull(callback); int callingUid = Binder.getCallingUid(); - UserHandle callingUser = handleIncomingUser(userHandle, callingUid); EXECUTOR.execute(() -> { try { - Context userContext = mContext.createContextAsUser(callingUser, /*flags=*/ 0); - verifyUserUnlocked(callingUser); - verifyCallingPackage(userContext, callingUser, callingUid, packageName); - verifyNotInstantApp(userContext, packageName); + verifyCaller(callingUid, packageName); + + // Obtain the user where the client wants to run the operations in. This should + // end up being the same as userHandle, assuming it is not a special user and + // the client is allowed to run operations in that user. + UserHandle targetUser = handleIncomingUser(userHandle, callingUid); + verifyUserUnlocked(targetUser); + AppSearchUserInstance instance = - mAppSearchUserInstanceManager.getUserInstance(callingUser); + mAppSearchUserInstanceManager.getUserInstance(targetUser); GetSchemaResponse response = instance.getAppSearchImpl().getSchema(packageName, databaseName); invokeCallbackOnResult( @@ -450,15 +458,18 @@ public class AppSearchManagerService extends SystemService { Objects.requireNonNull(callback); int callingUid = Binder.getCallingUid(); - UserHandle callingUser = handleIncomingUser(userHandle, callingUid); EXECUTOR.execute(() -> { try { - Context userContext = mContext.createContextAsUser(callingUser, /*flags=*/ 0); - verifyUserUnlocked(callingUser); - verifyCallingPackage(userContext, callingUser, callingUid, packageName); - verifyNotInstantApp(userContext, packageName); + verifyCaller(callingUid, packageName); + + // Obtain the user where the client wants to run the operations in. This should + // end up being the same as userHandle, assuming it is not a special user and + // the client is allowed to run operations in that user. + UserHandle targetUser = handleIncomingUser(userHandle, callingUid); + verifyUserUnlocked(targetUser); + AppSearchUserInstance instance = - mAppSearchUserInstanceManager.getUserInstance(callingUser); + mAppSearchUserInstanceManager.getUserInstance(targetUser); List namespaces = instance.getAppSearchImpl().getNamespaces(packageName, databaseName); invokeCallbackOnResult( @@ -485,20 +496,23 @@ public class AppSearchManagerService extends SystemService { long totalLatencyStartTimeMillis = SystemClock.elapsedRealtime(); int callingUid = Binder.getCallingUid(); - UserHandle callingUser = handleIncomingUser(userHandle, callingUid); EXECUTOR.execute(() -> { @AppSearchResult.ResultCode int statusCode = AppSearchResult.RESULT_OK; AppSearchUserInstance instance = null; int operationSuccessCount = 0; int operationFailureCount = 0; try { - Context userContext = mContext.createContextAsUser(callingUser, /*flags=*/ 0); - verifyUserUnlocked(callingUser); - verifyCallingPackage(userContext, callingUser, callingUid, packageName); - verifyNotInstantApp(userContext, packageName); + verifyCaller(callingUid, packageName); + + // Obtain the user where the client wants to run the operations in. This should + // end up being the same as userHandle, assuming it is not a special user and + // the client is allowed to run operations in that user. + UserHandle targetUser = handleIncomingUser(userHandle, callingUid); + verifyUserUnlocked(targetUser); + AppSearchBatchResult.Builder resultBuilder = new AppSearchBatchResult.Builder<>(); - instance = mAppSearchUserInstanceManager.getUserInstance(callingUser); + instance = mAppSearchUserInstanceManager.getUserInstance(targetUser); for (int i = 0; i < documentBundles.size(); i++) { GenericDocument document = new GenericDocument(documentBundles.get(i)); try { @@ -571,20 +585,23 @@ public class AppSearchManagerService extends SystemService { long totalLatencyStartTimeMillis = SystemClock.elapsedRealtime(); int callingUid = Binder.getCallingUid(); - UserHandle callingUser = handleIncomingUser(userHandle, callingUid); EXECUTOR.execute(() -> { @AppSearchResult.ResultCode int statusCode = AppSearchResult.RESULT_OK; AppSearchUserInstance instance = null; int operationSuccessCount = 0; int operationFailureCount = 0; try { - Context userContext = mContext.createContextAsUser(callingUser, /*flags=*/ 0); - verifyUserUnlocked(callingUser); - verifyCallingPackage(userContext, callingUser, callingUid, packageName); - verifyNotInstantApp(userContext, packageName); + verifyCaller(callingUid, packageName); + + // Obtain the user where the client wants to run the operations in. This should + // end up being the same as userHandle, assuming it is not a special user and + // the client is allowed to run operations in that user. + UserHandle targetUser = handleIncomingUser(userHandle, callingUid); + verifyUserUnlocked(targetUser); + AppSearchBatchResult.Builder resultBuilder = new AppSearchBatchResult.Builder<>(); - instance = mAppSearchUserInstanceManager.getUserInstance(callingUser); + instance = mAppSearchUserInstanceManager.getUserInstance(targetUser); for (int i = 0; i < ids.size(); i++) { String id = ids.get(i); try { @@ -652,18 +669,21 @@ public class AppSearchManagerService extends SystemService { long totalLatencyStartTimeMillis = SystemClock.elapsedRealtime(); int callingUid = Binder.getCallingUid(); - UserHandle callingUser = handleIncomingUser(userHandle, callingUid); EXECUTOR.execute(() -> { @AppSearchResult.ResultCode int statusCode = AppSearchResult.RESULT_OK; AppSearchUserInstance instance = null; int operationSuccessCount = 0; int operationFailureCount = 0; try { - Context userContext = mContext.createContextAsUser(callingUser, /*flags=*/ 0); - verifyUserUnlocked(callingUser); - verifyCallingPackage(userContext, callingUser, callingUid, packageName); - verifyNotInstantApp(userContext, packageName); - instance = mAppSearchUserInstanceManager.getUserInstance(callingUser); + verifyCaller(callingUid, packageName); + + // Obtain the user where the client wants to run the operations in. This should + // end up being the same as userHandle, assuming it is not a special user and + // the client is allowed to run operations in that user. + UserHandle targetUser = handleIncomingUser(userHandle, callingUid); + verifyUserUnlocked(targetUser); + + instance = mAppSearchUserInstanceManager.getUserInstance(targetUser); SearchResultPage searchResultPage = instance.getAppSearchImpl().query( packageName, databaseName, @@ -718,18 +738,21 @@ public class AppSearchManagerService extends SystemService { long totalLatencyStartTimeMillis = SystemClock.elapsedRealtime(); int callingUid = Binder.getCallingUid(); - UserHandle callingUser = handleIncomingUser(userHandle, callingUid); EXECUTOR.execute(() -> { @AppSearchResult.ResultCode int statusCode = AppSearchResult.RESULT_OK; AppSearchUserInstance instance = null; int operationSuccessCount = 0; int operationFailureCount = 0; try { - Context userContext = mContext.createContextAsUser(callingUser, /*flags=*/ 0); - verifyUserUnlocked(callingUser); - verifyCallingPackage(userContext, callingUser, callingUid, packageName); - verifyNotInstantApp(userContext, packageName); - instance = mAppSearchUserInstanceManager.getUserInstance(callingUser); + verifyCaller(callingUid, packageName); + + // Obtain the user where the client wants to run the operations in. This should + // end up being the same as userHandle, assuming it is not a special user and + // the client is allowed to run operations in that user. + UserHandle targetUser = handleIncomingUser(userHandle, callingUid); + verifyUserUnlocked(targetUser); + + instance = mAppSearchUserInstanceManager.getUserInstance(targetUser); boolean callerHasSystemAccess = instance.getVisibilityStore().doesCallerHaveSystemAccess(packageName); @@ -783,19 +806,22 @@ public class AppSearchManagerService extends SystemService { Objects.requireNonNull(callback); int callingUid = Binder.getCallingUid(); - UserHandle callingUser = handleIncomingUser(userHandle, callingUid); - // TODO(b/162450968) check nextPageToken is being advanced by the same uid as originally - // opened it EXECUTOR.execute(() -> { try { - Context userContext = mContext.createContextAsUser(callingUser, /*flags=*/ 0); - verifyUserUnlocked(callingUser); - verifyCallingPackage(userContext, callingUser, callingUid, packageName); - verifyNotInstantApp(userContext, packageName); + verifyCaller(callingUid, packageName); + + // Obtain the user where the client wants to run the operations in. This should + // end up being the same as userHandle, assuming it is not a special user and + // the client is allowed to run operations in that user. + UserHandle targetUser = handleIncomingUser(userHandle, callingUid); + verifyUserUnlocked(targetUser); + AppSearchUserInstance instance = - mAppSearchUserInstanceManager.getUserInstance(callingUser); + mAppSearchUserInstanceManager.getUserInstance(targetUser); + // TODO(b/173532925): Implement logging for statsBuilder SearchResultPage searchResultPage = - instance.getAppSearchImpl().getNextPage(packageName, nextPageToken); + instance.getAppSearchImpl().getNextPage( + packageName, nextPageToken, /*statsBuilder=*/ null); invokeCallbackOnResult( callback, AppSearchResult.newSuccessfulResult(searchResultPage.getBundle())); @@ -812,15 +838,18 @@ public class AppSearchManagerService extends SystemService { Objects.requireNonNull(userHandle); int callingUid = Binder.getCallingUid(); - UserHandle callingUser = handleIncomingUser(userHandle, callingUid); EXECUTOR.execute(() -> { try { - Context userContext = mContext.createContextAsUser(callingUser, /*flags=*/ 0); - verifyUserUnlocked(callingUser); - verifyCallingPackage(userContext, callingUser, callingUid, packageName); - verifyNotInstantApp(userContext, packageName); + verifyCaller(callingUid, packageName); + + // Obtain the user where the client wants to run the operations in. This should + // end up being the same as userHandle, assuming it is not a special user and + // the client is allowed to run operations in that user. + UserHandle targetUser = handleIncomingUser(userHandle, callingUid); + verifyUserUnlocked(targetUser); + AppSearchUserInstance instance = - mAppSearchUserInstanceManager.getUserInstance(callingUser); + mAppSearchUserInstanceManager.getUserInstance(targetUser); instance.getAppSearchImpl().invalidateNextPageToken(packageName, nextPageToken); } catch (Throwable t) { Log.e(TAG, "Unable to invalidate the query page token", t); @@ -846,15 +875,18 @@ public class AppSearchManagerService extends SystemService { Objects.requireNonNull(callback); int callingUid = Binder.getCallingUid(); - UserHandle callingUser = handleIncomingUser(userHandle, callingUid); EXECUTOR.execute(() -> { try { - Context userContext = mContext.createContextAsUser(callingUser, /*flags=*/ 0); - verifyUserUnlocked(callingUser); - verifyCallingPackage(userContext, callingUser, callingUid, packageName); - verifyNotInstantApp(userContext, packageName); + verifyCaller(callingUid, packageName); + + // Obtain the user where the client wants to run the operations in. This should + // end up being the same as userHandle, assuming it is not a special user and + // the client is allowed to run operations in that user. + UserHandle targetUser = handleIncomingUser(userHandle, callingUid); + verifyUserUnlocked(targetUser); + AppSearchUserInstance instance = - mAppSearchUserInstanceManager.getUserInstance(callingUser); + mAppSearchUserInstanceManager.getUserInstance(targetUser); // we don't need to append the file. The file is always brand new. try (DataOutputStream outputStream = new DataOutputStream( new FileOutputStream(fileDescriptor.getFileDescriptor()))) { @@ -870,8 +902,11 @@ public class AppSearchManagerService extends SystemService { outputStream, searchResultPage.getResults().get(i) .getGenericDocument().getBundle()); } + // TODO(b/173532925): Implement logging for statsBuilder searchResultPage = instance.getAppSearchImpl().getNextPage( - packageName, searchResultPage.getNextPageToken()); + packageName, + searchResultPage.getNextPageToken(), + /*statsBuilder=*/ null); } } invokeCallbackOnResult(callback, AppSearchResult.newSuccessfulResult(null)); @@ -895,15 +930,18 @@ public class AppSearchManagerService extends SystemService { Objects.requireNonNull(callback); int callingUid = Binder.getCallingUid(); - UserHandle callingUser = handleIncomingUser(userHandle, callingUid); EXECUTOR.execute(() -> { try { - Context userContext = mContext.createContextAsUser(callingUser, /*flags=*/ 0); - verifyUserUnlocked(callingUser); - verifyCallingPackage(userContext, callingUser, callingUid, packageName); - verifyNotInstantApp(userContext, packageName); + verifyCaller(callingUid, packageName); + + // Obtain the user where the client wants to run the operations in. This should + // end up being the same as userHandle, assuming it is not a special user and + // the client is allowed to run operations in that user. + UserHandle targetUser = handleIncomingUser(userHandle, callingUid); + verifyUserUnlocked(targetUser); + AppSearchUserInstance instance = - mAppSearchUserInstanceManager.getUserInstance(callingUser); + mAppSearchUserInstanceManager.getUserInstance(targetUser); GenericDocument document; ArrayList migrationFailureBundles = new ArrayList<>(); @@ -957,15 +995,18 @@ public class AppSearchManagerService extends SystemService { Objects.requireNonNull(callback); int callingUid = Binder.getCallingUid(); - UserHandle callingUser = handleIncomingUser(userHandle, callingUid); EXECUTOR.execute(() -> { try { - Context userContext = mContext.createContextAsUser(callingUser, /*flags=*/ 0); - verifyUserUnlocked(callingUser); - verifyCallingPackage(userContext, callingUser, callingUid, packageName); - verifyNotInstantApp(userContext, packageName); + verifyCaller(callingUid, packageName); + + // Obtain the user where the client wants to run the operations in. This should + // end up being the same as userHandle, assuming it is not a special user and + // the client is allowed to run operations in that user. + UserHandle targetUser = handleIncomingUser(userHandle, callingUid); + verifyUserUnlocked(targetUser); + AppSearchUserInstance instance = - mAppSearchUserInstanceManager.getUserInstance(callingUser); + mAppSearchUserInstanceManager.getUserInstance(targetUser); if (systemUsage && !instance.getVisibilityStore() @@ -1004,20 +1045,23 @@ public class AppSearchManagerService extends SystemService { long totalLatencyStartTimeMillis = SystemClock.elapsedRealtime(); int callingUid = Binder.getCallingUid(); - UserHandle callingUser = handleIncomingUser(userHandle, callingUid); EXECUTOR.execute(() -> { @AppSearchResult.ResultCode int statusCode = AppSearchResult.RESULT_OK; AppSearchUserInstance instance = null; int operationSuccessCount = 0; int operationFailureCount = 0; try { - Context userContext = mContext.createContextAsUser(callingUser, /*flags=*/ 0); - verifyUserUnlocked(callingUser); - verifyCallingPackage(userContext, callingUser, callingUid, packageName); - verifyNotInstantApp(userContext, packageName); + verifyCaller(callingUid, packageName); + + // Obtain the user where the client wants to run the operations in. This should + // end up being the same as userHandle, assuming it is not a special user and + // the client is allowed to run operations in that user. + UserHandle targetUser = handleIncomingUser(userHandle, callingUid); + verifyUserUnlocked(targetUser); + AppSearchBatchResult.Builder resultBuilder = new AppSearchBatchResult.Builder<>(); - instance = mAppSearchUserInstanceManager.getUserInstance(callingUser); + instance = mAppSearchUserInstanceManager.getUserInstance(targetUser); for (int i = 0; i < ids.size(); i++) { String id = ids.get(i); try { @@ -1090,18 +1134,21 @@ public class AppSearchManagerService extends SystemService { long totalLatencyStartTimeMillis = SystemClock.elapsedRealtime(); int callingUid = Binder.getCallingUid(); - UserHandle callingUser = handleIncomingUser(userHandle, callingUid); EXECUTOR.execute(() -> { @AppSearchResult.ResultCode int statusCode = AppSearchResult.RESULT_OK; AppSearchUserInstance instance = null; int operationSuccessCount = 0; int operationFailureCount = 0; try { - Context userContext = mContext.createContextAsUser(callingUser, /*flags=*/ 0); - verifyUserUnlocked(callingUser); - verifyCallingPackage(userContext, callingUser, callingUid, packageName); - verifyNotInstantApp(userContext, packageName); - instance = mAppSearchUserInstanceManager.getUserInstance(callingUser); + verifyCaller(callingUid, packageName); + + // Obtain the user where the client wants to run the operations in. This should + // end up being the same as userHandle, assuming it is not a special user and + // the client is allowed to run operations in that user. + UserHandle targetUser = handleIncomingUser(userHandle, callingUid); + verifyUserUnlocked(targetUser); + + instance = mAppSearchUserInstanceManager.getUserInstance(targetUser); instance.getAppSearchImpl().removeByQuery( packageName, databaseName, @@ -1154,15 +1201,18 @@ public class AppSearchManagerService extends SystemService { Objects.requireNonNull(callback); int callingUid = Binder.getCallingUid(); - UserHandle callingUser = handleIncomingUser(userHandle, callingUid); EXECUTOR.execute(() -> { try { - Context userContext = mContext.createContextAsUser(callingUser, /*flags=*/ 0); - verifyUserUnlocked(callingUser); - verifyCallingPackage(userContext, callingUser, callingUid, packageName); - verifyNotInstantApp(userContext, packageName); + verifyCaller(callingUid, packageName); + + // Obtain the user where the client wants to run the operations in. This should + // end up being the same as userHandle, assuming it is not a special user and + // the client is allowed to run operations in that user. + UserHandle targetUser = handleIncomingUser(userHandle, callingUid); + verifyUserUnlocked(targetUser); + AppSearchUserInstance instance = - mAppSearchUserInstanceManager.getUserInstance(callingUser); + mAppSearchUserInstanceManager.getUserInstance(targetUser); StorageInfo storageInfo = instance.getAppSearchImpl() .getStorageInfoForDatabase(packageName, databaseName); Bundle storageInfoBundle = storageInfo.getBundle(); @@ -1184,18 +1234,21 @@ public class AppSearchManagerService extends SystemService { long totalLatencyStartTimeMillis = SystemClock.elapsedRealtime(); int callingUid = Binder.getCallingUid(); - UserHandle callingUser = handleIncomingUser(userHandle, callingUid); EXECUTOR.execute(() -> { @AppSearchResult.ResultCode int statusCode = AppSearchResult.RESULT_OK; AppSearchUserInstance instance = null; int operationSuccessCount = 0; int operationFailureCount = 0; try { - Context userContext = mContext.createContextAsUser(callingUser, /*flags=*/ 0); - verifyUserUnlocked(callingUser); - verifyCallingPackage(userContext, callingUser, callingUid, packageName); - verifyNotInstantApp(userContext, packageName); - instance = mAppSearchUserInstanceManager.getUserInstance(callingUser); + verifyCaller(callingUid, packageName); + + // Obtain the user where the client wants to run the operations in. This should + // end up being the same as userHandle, assuming it is not a special user and + // the client is allowed to run operations in that user. + UserHandle targetUser = handleIncomingUser(userHandle, callingUid); + verifyUserUnlocked(targetUser); + + instance = mAppSearchUserInstanceManager.getUserInstance(targetUser); instance.getAppSearchImpl().persistToDisk(PersistType.Code.FULL); ++operationSuccessCount; } catch (Throwable t) { @@ -1236,7 +1289,6 @@ public class AppSearchManagerService extends SystemService { long totalLatencyStartTimeMillis = SystemClock.elapsedRealtime(); int callingUid = Binder.getCallingUid(); - UserHandle callingUser = handleIncomingUser(userHandle, callingUid); EXECUTOR.execute(() -> { @AppSearchResult.ResultCode int statusCode = AppSearchResult.RESULT_OK; @@ -1244,12 +1296,18 @@ public class AppSearchManagerService extends SystemService { int operationSuccessCount = 0; int operationFailureCount = 0; try { - Context userContext = mContext.createContextAsUser(callingUser, /*flags=*/ 0); - verifyUserUnlocked(callingUser); - verifyCallingPackage(userContext, callingUser, callingUid, packageName); - verifyNotInstantApp(userContext, packageName); + verifyCaller(callingUid, packageName); + + // Obtain the user where the client wants to run the operations in. This should + // end up being the same as userHandle, assuming it is not a special user and + // the client is allowed to run operations in that user. + UserHandle targetUser = handleIncomingUser(userHandle, callingUid); + verifyUserUnlocked(targetUser); + + Context targetUserContext = mContext.createContextAsUser(targetUser, + /*flags=*/ 0); instance = mAppSearchUserInstanceManager.getOrCreateUserInstance( - userContext, callingUser, AppSearchConfig.getInstance(EXECUTOR)); + targetUserContext, targetUser, AppSearchConfig.getInstance(EXECUTOR)); ++operationSuccessCount; invokeCallbackOnResult(callback, AppSearchResult.newSuccessfulResult(null)); } catch (Throwable t) { @@ -1278,29 +1336,6 @@ public class AppSearchManagerService extends SystemService { }); } - private void verifyCallingPackage( - @NonNull Context userContext, - @NonNull UserHandle actualCallingUser, - int actualCallingUid, - @NonNull String claimedCallingPackage) { - Objects.requireNonNull(actualCallingUser); - Objects.requireNonNull(claimedCallingPackage); - - int claimedCallingUid = PackageUtil.getPackageUid( - userContext, claimedCallingPackage); - if (claimedCallingUid == INVALID_UID) { - throw new SecurityException( - "Specified calling package [" + claimedCallingPackage + "] not found"); - } - if (claimedCallingUid != actualCallingUid) { - throw new SecurityException( - "Specified calling package [" - + claimedCallingPackage - + "] does not match the calling uid " - + actualCallingUid); - } - } - /** Invokes the {@link IAppSearchResultCallback} with the result. */ private void invokeCallbackOnResult( IAppSearchResultCallback callback, AppSearchResult result) { @@ -1354,33 +1389,72 @@ public class AppSearchManagerService extends SystemService { /** * Helper for dealing with incoming user arguments to system service calls. * - * @param requestedUser The user which the caller is requesting to execute as. + * @param targetUserHandle The user which the caller is requesting to execute as. * @param callingUid The actual uid of the caller as determined by Binder. * @return the user handle that the call should run as. Will always be a concrete user. */ @NonNull - private UserHandle handleIncomingUser(@NonNull UserHandle requestedUser, int callingUid) { - UserHandle callingUser = UserHandle.getUserHandleForUid(callingUid); - if (callingUser.equals(requestedUser)) { - return requestedUser; + private UserHandle handleIncomingUser(@NonNull UserHandle targetUserHandle, int callingUid) { + UserHandle callingUserHandle = UserHandle.getUserHandleForUid(callingUid); + if (callingUserHandle.equals(targetUserHandle)) { + return targetUserHandle; } // Duplicates UserController#ensureNotSpecialUser - if (requestedUser.getIdentifier() < 0) { + if (targetUserHandle.getIdentifier() < 0) { throw new IllegalArgumentException( - "Call does not support special user " + requestedUser); + "Call does not support special user " + targetUserHandle); } throw new SecurityException( - "Requested user, " + requestedUser + ", is not the same as the calling user, " - + callingUser + "."); + "Requested user, " + targetUserHandle + ", is not the same as the calling user, " + + callingUserHandle + "."); + } + + /** + * Verify various aspects of the calling user. + * + * @param callingUid Uid of the caller, usually retrieved from Binder for authenticity. + * @param claimedCallingPackage Package name the caller claims to be. + */ + private void verifyCaller(int callingUid, @NonNull String claimedCallingPackage) { + // Obtain the user where the client is running in. Note that this could be different from + // the userHandle where the client wants to run the AppSearch operation in. + UserHandle callingUserHandle = UserHandle.getUserHandleForUid(callingUid); + Context callingUserContext = mContext.createContextAsUser(callingUserHandle, + /*flags=*/ 0); + + verifyCallingPackage(callingUserContext, callingUid, claimedCallingPackage); + verifyNotInstantApp(callingUserContext, claimedCallingPackage); + } + + /** + * Check that the caller's supposed package name matches the uid making the call. + * + * @throws SecurityException if the package name and uid don't match. + */ + private void verifyCallingPackage( + @NonNull Context actualCallingUserContext, + int actualCallingUid, + @NonNull String claimedCallingPackage) { + int claimedCallingUid = PackageUtil.getPackageUid( + actualCallingUserContext, claimedCallingPackage); + if (claimedCallingUid == INVALID_UID) { + throw new SecurityException( + "Specified calling package [" + claimedCallingPackage + "] not found"); + } + if (claimedCallingUid != actualCallingUid) { + throw new SecurityException( + "Specified calling package [" + + claimedCallingPackage + + "] does not match the calling uid " + + actualCallingUid); + } } /** - * Helper for ensuring instant apps can't make calls to AppSearch. + * Ensure instant apps can't make calls to AppSearch. * - * @param userContext Context of the user making the call. - * @param packageName Package name of the caller. * @throws SecurityException if the caller is an instant app. */ private void verifyNotInstantApp(@NonNull Context userContext, @NonNull String packageName) { diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchImpl.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchImpl.java index 15916cc23c0f..324163f49fd3 100644 --- a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchImpl.java +++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchImpl.java @@ -59,6 +59,7 @@ import com.android.server.appsearch.external.localstorage.stats.OptimizeStats; import com.android.server.appsearch.external.localstorage.stats.PutDocumentStats; import com.android.server.appsearch.external.localstorage.stats.RemoveStats; import com.android.server.appsearch.external.localstorage.stats.SearchStats; +import com.android.server.appsearch.external.localstorage.stats.SetSchemaStats; import com.android.server.appsearch.external.localstorage.visibilitystore.VisibilityStore; import com.google.android.icing.IcingSearchEngine; @@ -393,6 +394,7 @@ public final class AppSearchImpl implements Closeable { * @param forceOverride Whether to force-apply the schema even if it is incompatible. Documents * which do not comply with the new schema will be deleted. * @param version The overall version number of the request. + * @param setSchemaStatsBuilder Builder for {@link SetSchemaStats} to hold stats for setSchema * @return The response contains deleted schema types and incompatible schema types of this * call. * @throws AppSearchException On IcingSearchEngine error. If the status code is @@ -408,7 +410,8 @@ public final class AppSearchImpl implements Closeable { @NonNull List schemasNotDisplayedBySystem, @NonNull Map> schemasVisibleToPackages, boolean forceOverride, - int version) + int version, + @Nullable SetSchemaStats.Builder setSchemaStatsBuilder) throws AppSearchException { mReadWriteLock.writeLock().lock(); try { @@ -438,6 +441,12 @@ public final class AppSearchImpl implements Closeable { mLogUtil.piiTrace( "setSchema, response", setSchemaResultProto.getStatus(), setSchemaResultProto); + if (setSchemaStatsBuilder != null) { + setSchemaStatsBuilder.setStatusCode( + statusProtoToResultCode(setSchemaResultProto.getStatus())); + AppSearchLoggerHelper.copyNativeStats(setSchemaResultProto, setSchemaStatsBuilder); + } + // Determine whether it succeeded. try { checkSuccess(setSchemaResultProto.getStatus()); @@ -1127,8 +1136,13 @@ public final class AppSearchImpl implements Closeable { * @throws AppSearchException on IcingSearchEngine error or if can't advance on nextPageToken. */ @NonNull - public SearchResultPage getNextPage(@NonNull String packageName, long nextPageToken) + public SearchResultPage getNextPage( + @NonNull String packageName, + long nextPageToken, + @Nullable SearchStats.Builder statsBuilder) throws AppSearchException { + long totalLatencyStartMillis = SystemClock.elapsedRealtime(); + mReadWriteLock.readLock().lock(); try { throwIfClosedLocked(); @@ -1137,6 +1151,13 @@ public final class AppSearchImpl implements Closeable { checkNextPageToken(packageName, nextPageToken); SearchResultProto searchResultProto = mIcingSearchEngineLocked.getNextPage(nextPageToken); + + if (statsBuilder != null) { + statsBuilder.setStatusCode(statusProtoToResultCode(searchResultProto.getStatus())); + AppSearchLoggerHelper.copyNativeStats( + searchResultProto.getQueryStats(), statsBuilder); + } + mLogUtil.piiTrace( "getNextPage, response", searchResultProto.getResultsCount(), @@ -1152,9 +1173,22 @@ public final class AppSearchImpl implements Closeable { mNextPageTokensLocked.get(packageName).remove(nextPageToken); } } - return rewriteSearchResultProto(searchResultProto, mSchemaMapLocked); + long rewriteSearchResultLatencyStartMillis = SystemClock.elapsedRealtime(); + SearchResultPage resultPage = + rewriteSearchResultProto(searchResultProto, mSchemaMapLocked); + if (statsBuilder != null) { + statsBuilder.setRewriteSearchResultLatencyMillis( + (int) + (SystemClock.elapsedRealtime() + - rewriteSearchResultLatencyStartMillis)); + } + return resultPage; } finally { mReadWriteLock.readLock().unlock(); + if (statsBuilder != null) { + statsBuilder.setTotalLatencyMillis( + (int) (SystemClock.elapsedRealtime() - totalLatencyStartMillis)); + } } } @@ -1334,7 +1368,7 @@ public final class AppSearchImpl implements Closeable { statusProtoToResultCode(deleteResultProto.getStatus())); // TODO(b/187206766) also log query stats here once IcingLib returns it AppSearchLoggerHelper.copyNativeStats( - deleteResultProto.getDeleteStats(), removeStatsBuilder); + deleteResultProto.getDeleteByQueryStats(), removeStatsBuilder); } // It seems that the caller wants to get success if the data matching the query is @@ -1343,7 +1377,8 @@ public final class AppSearchImpl implements Closeable { deleteResultProto.getStatus(), StatusProto.Code.OK, StatusProto.Code.NOT_FOUND); // Update derived maps - int numDocumentsDeleted = deleteResultProto.getDeleteStats().getNumDocumentsDeleted(); + int numDocumentsDeleted = + deleteResultProto.getDeleteByQueryStats().getNumDocumentsDeleted(); updateDocumentCountAfterRemovalLocked(packageName, numDocumentsDeleted); } finally { mReadWriteLock.writeLock().unlock(); diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchLogger.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchLogger.java index 98cedc7e6b54..1f7d44e3b75a 100644 --- a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchLogger.java +++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchLogger.java @@ -24,6 +24,7 @@ import com.android.server.appsearch.external.localstorage.stats.OptimizeStats; import com.android.server.appsearch.external.localstorage.stats.PutDocumentStats; import com.android.server.appsearch.external.localstorage.stats.RemoveStats; import com.android.server.appsearch.external.localstorage.stats.SearchStats; +import com.android.server.appsearch.external.localstorage.stats.SetSchemaStats; /** * An interface for implementing client-defined logging AppSearch operations stats. @@ -54,5 +55,8 @@ public interface AppSearchLogger { /** Logs {@link OptimizeStats} */ void logStats(@NonNull OptimizeStats stats); + /** Logs {@link SetSchemaStats} */ + void logStats(@NonNull SetSchemaStats stats); + // TODO(b/173532925) Add remaining logStats once we add all the stats. } diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchLoggerHelper.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchLoggerHelper.java index cd653e569f11..c19ba1408ec9 100644 --- a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchLoggerHelper.java +++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchLoggerHelper.java @@ -23,12 +23,15 @@ import com.android.server.appsearch.external.localstorage.stats.OptimizeStats; import com.android.server.appsearch.external.localstorage.stats.PutDocumentStats; import com.android.server.appsearch.external.localstorage.stats.RemoveStats; import com.android.server.appsearch.external.localstorage.stats.SearchStats; +import com.android.server.appsearch.external.localstorage.stats.SetSchemaStats; +import com.google.android.icing.proto.DeleteByQueryStatsProto; import com.google.android.icing.proto.DeleteStatsProto; import com.google.android.icing.proto.InitializeStatsProto; import com.google.android.icing.proto.OptimizeStatsProto; import com.google.android.icing.proto.PutDocumentStatsProto; import com.google.android.icing.proto.QueryStatsProto; +import com.google.android.icing.proto.SetSchemaResultProto; import java.util.Objects; @@ -141,6 +144,26 @@ public final class AppSearchLoggerHelper { .setDeletedDocumentCount(fromNativeStats.getNumDocumentsDeleted()); } + /** + * Copies native DeleteByQuery stats to builder. + * + * @param fromNativeStats Stats copied from. + * @param toStatsBuilder Stats copied to. + */ + static void copyNativeStats( + @NonNull DeleteByQueryStatsProto fromNativeStats, + @NonNull RemoveStats.Builder toStatsBuilder) { + Objects.requireNonNull(fromNativeStats); + Objects.requireNonNull(toStatsBuilder); + + @SuppressWarnings("deprecation") + int deleteType = DeleteStatsProto.DeleteType.Code.DEPRECATED_QUERY.getNumber(); + toStatsBuilder + .setNativeLatencyMillis(fromNativeStats.getLatencyMs()) + .setDeleteType(deleteType) + .setDeletedDocumentCount(fromNativeStats.getNumDocumentsDeleted()); + } + /** * Copies native {@link OptimizeStatsProto} to builder. * @@ -164,4 +187,25 @@ public final class AppSearchLoggerHelper { .setStorageSizeAfterBytes(fromNativeStats.getStorageSizeAfter()) .setTimeSinceLastOptimizeMillis(fromNativeStats.getTimeSinceLastOptimizeMs()); } + + /* + * Copy SetSchema result stats to builder. + * + * @param fromProto Stats copied from. + * @param toStatsBuilder Stats copied to. + */ + static void copyNativeStats( + @NonNull SetSchemaResultProto fromProto, + @NonNull SetSchemaStats.Builder toStatsBuilder) { + Objects.requireNonNull(fromProto); + Objects.requireNonNull(toStatsBuilder); + toStatsBuilder + .setNewTypeCount(fromProto.getNewSchemaTypesCount()) + .setDeletedTypeCount(fromProto.getDeletedSchemaTypesCount()) + .setCompatibleTypeChangeCount(fromProto.getFullyCompatibleChangedSchemaTypesCount()) + .setIndexIncompatibleTypeChangeCount( + fromProto.getIndexIncompatibleChangedSchemaTypesCount()) + .setBackwardsIncompatibleTypeChangeCount( + fromProto.getIncompatibleSchemaTypesCount()); + } } diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/SearchStats.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/SearchStats.java index d7904f3ca49f..75ae2d0accfd 100644 --- a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/SearchStats.java +++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/SearchStats.java @@ -40,6 +40,7 @@ public final class SearchStats { VISIBILITY_SCOPE_LOCAL, // Searches the global documents. Including platform surfaceable and 3p-access. VISIBILITY_SCOPE_GLOBAL, + VISIBILITY_SCOPE_UNKNOWN, // TODO(b/173532925) Add THIRD_PARTY_ACCESS once we can distinguish platform // surfaceable from 3p access(right both of them are categorized as // VISIBILITY_SCOPE_GLOBAL) @@ -51,6 +52,7 @@ public final class SearchStats { public static final int VISIBILITY_SCOPE_LOCAL = 1; // Searches the global documents. Including platform surfaceable and 3p-access. public static final int VISIBILITY_SCOPE_GLOBAL = 2; + public static final int VISIBILITY_SCOPE_UNKNOWN = 3; // TODO(b/173532925): Add a field searchType to indicate where the search is used(normal // query vs in removeByQuery vs during migration) diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/SetSchemaStats.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/SetSchemaStats.java index 9d789a894855..3e5a80f88f5f 100644 --- a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/SetSchemaStats.java +++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/SetSchemaStats.java @@ -47,9 +47,6 @@ public final class SetSchemaStats { private final int mTotalLatencyMillis; - /** Overall time used for the native function call. */ - private final int mNativeLatencyMillis; - /** Number of newly added schema types. */ private final int mNewTypeCount; @@ -72,7 +69,6 @@ public final class SetSchemaStats { mStatusCode = builder.mStatusCode; mSchemaMigrationStats = builder.mSchemaMigrationStats; mTotalLatencyMillis = builder.mTotalLatencyMillis; - mNativeLatencyMillis = builder.mNativeLatencyMillis; mNewTypeCount = builder.mNewTypeCount; mDeletedTypeCount = builder.mDeletedTypeCount; mCompatibleTypeChangeCount = builder.mCompatibleTypeChangeCount; @@ -112,11 +108,6 @@ public final class SetSchemaStats { return mTotalLatencyMillis; } - /** Returns overall time used for the native function call. */ - public int getNativeLatencyMillis() { - return mNativeLatencyMillis; - } - /** Returns number of newly added schema types. */ public int getNewTypeCount() { return mNewTypeCount; @@ -159,7 +150,6 @@ public final class SetSchemaStats { @AppSearchResult.ResultCode int mStatusCode; @Nullable SchemaMigrationStats mSchemaMigrationStats; int mTotalLatencyMillis; - int mNativeLatencyMillis; int mNewTypeCount; int mDeletedTypeCount; int mCompatibleTypeChangeCount; @@ -193,13 +183,6 @@ public final class SetSchemaStats { return this; } - /** Sets native latency in milliseconds. */ - @NonNull - public Builder setNativeLatencyMillis(int nativeLatencyMillis) { - mNativeLatencyMillis = nativeLatencyMillis; - return this; - } - /** Sets number of new types. */ @NonNull public Builder setNewTypeCount(int newTypeCount) { diff --git a/apex/appsearch/service/java/com/android/server/appsearch/stats/PlatformLogger.java b/apex/appsearch/service/java/com/android/server/appsearch/stats/PlatformLogger.java index fdf6a008b10c..4c29ece3dd03 100644 --- a/apex/appsearch/service/java/com/android/server/appsearch/stats/PlatformLogger.java +++ b/apex/appsearch/service/java/com/android/server/appsearch/stats/PlatformLogger.java @@ -36,6 +36,7 @@ import com.android.server.appsearch.external.localstorage.stats.OptimizeStats; import com.android.server.appsearch.external.localstorage.stats.PutDocumentStats; import com.android.server.appsearch.external.localstorage.stats.RemoveStats; import com.android.server.appsearch.external.localstorage.stats.SearchStats; +import com.android.server.appsearch.external.localstorage.stats.SetSchemaStats; import com.android.server.appsearch.util.PackageUtil; import java.io.UnsupportedEncodingException; @@ -180,6 +181,11 @@ public final class PlatformLogger implements AppSearchLogger { } } + @Override + public void logStats(@NonNull SetSchemaStats stats) { + // TODO(b/173532925): Log stats + } + /** * Removes cached UID for package. * diff --git a/apex/appsearch/service/java/com/android/server/appsearch/visibilitystore/VisibilityStoreImpl.java b/apex/appsearch/service/java/com/android/server/appsearch/visibilitystore/VisibilityStoreImpl.java index ce142d646d1c..c4d10169f9fc 100644 --- a/apex/appsearch/service/java/com/android/server/appsearch/visibilitystore/VisibilityStoreImpl.java +++ b/apex/appsearch/service/java/com/android/server/appsearch/visibilitystore/VisibilityStoreImpl.java @@ -126,7 +126,8 @@ public class VisibilityStoreImpl implements VisibilityStore { /*schemasNotDisplayedBySystem=*/ Collections.emptyList(), /*schemasVisibleToPackages=*/ Collections.emptyMap(), /*forceOverride=*/ false, - /*version=*/ SCHEMA_VERSION); + /*version=*/ SCHEMA_VERSION, + /*setSchemaStatsBuilder=*/ null); } // Populate visibility settings set diff --git a/apex/appsearch/synced_jetpack_changeid.txt b/apex/appsearch/synced_jetpack_changeid.txt index a81d7d8022b2..4db8355076cf 100644 --- a/apex/appsearch/synced_jetpack_changeid.txt +++ b/apex/appsearch/synced_jetpack_changeid.txt @@ -1 +1 @@ -Ie04f1ecc033faae8085afcb51eb9e40a298998d5 +bd53b062816070b64feb992c2bf58f3afa3d420e diff --git a/apex/appsearch/testing/Android.bp b/apex/appsearch/testing/Android.bp index 5407cb4ccec7..f78d98ae115a 100644 --- a/apex/appsearch/testing/Android.bp +++ b/apex/appsearch/testing/Android.bp @@ -28,6 +28,7 @@ java_library { "framework", "framework-appsearch", "guava", + "service-appsearch", "truth-prebuilt", ], visibility: [ diff --git a/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/AppSearchTestUtils.java b/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/AppSearchTestUtils.java index ec9a42eaa276..4d8e8e9e7b1a 100644 --- a/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/AppSearchTestUtils.java +++ b/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/AppSearchTestUtils.java @@ -19,6 +19,8 @@ package com.android.server.appsearch.testing; import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertWithMessage; +import android.annotation.NonNull; +import android.annotation.Nullable; import android.app.appsearch.AppSearchBatchResult; import android.app.appsearch.AppSearchSessionShim; import android.app.appsearch.GenericDocument; @@ -26,12 +28,66 @@ import android.app.appsearch.GetByDocumentIdRequest; import android.app.appsearch.SearchResult; import android.app.appsearch.SearchResultsShim; +import com.android.server.appsearch.external.localstorage.AppSearchLogger; +import com.android.server.appsearch.external.localstorage.stats.CallStats; +import com.android.server.appsearch.external.localstorage.stats.InitializeStats; +import com.android.server.appsearch.external.localstorage.stats.OptimizeStats; +import com.android.server.appsearch.external.localstorage.stats.PutDocumentStats; +import com.android.server.appsearch.external.localstorage.stats.RemoveStats; +import com.android.server.appsearch.external.localstorage.stats.SearchStats; +import com.android.server.appsearch.external.localstorage.stats.SetSchemaStats; + import java.util.ArrayList; import java.util.List; import java.util.Set; import java.util.concurrent.Future; public class AppSearchTestUtils { + // Non-thread-safe logger implementation for testing + public static class TestLogger implements AppSearchLogger { + @Nullable public CallStats mCallStats; + @Nullable public PutDocumentStats mPutDocumentStats; + @Nullable public InitializeStats mInitializeStats; + @Nullable public SearchStats mSearchStats; + @Nullable public RemoveStats mRemoveStats; + @Nullable public OptimizeStats mOptimizeStats; + @Nullable public SetSchemaStats mSetSchemaStats; + + @Override + public void logStats(@NonNull CallStats stats) { + mCallStats = stats; + } + + @Override + public void logStats(@NonNull PutDocumentStats stats) { + mPutDocumentStats = stats; + } + + @Override + public void logStats(@NonNull InitializeStats stats) { + mInitializeStats = stats; + } + + @Override + public void logStats(@NonNull SearchStats stats) { + mSearchStats = stats; + } + + @Override + public void logStats(@NonNull RemoveStats stats) { + mRemoveStats = stats; + } + + @Override + public void logStats(@NonNull OptimizeStats stats) { + mOptimizeStats = stats; + } + + @Override + public void logStats(@NonNull SetSchemaStats stats) { + mSetSchemaStats = stats; + } + } public static AppSearchBatchResult checkIsBatchResultSuccess( Future> future) throws Exception { diff --git a/core/api/current.txt b/core/api/current.txt index 1de47b548a5c..1dd401d04e2b 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -99,6 +99,7 @@ package android { field public static final String INTERACT_ACROSS_PROFILES = "android.permission.INTERACT_ACROSS_PROFILES"; field public static final String INTERNET = "android.permission.INTERNET"; field public static final String KILL_BACKGROUND_PROCESSES = "android.permission.KILL_BACKGROUND_PROCESSES"; + field public static final String LAUNCH_MULTI_PANE_SETTINGS_DEEP_LINK = "android.permission.LAUNCH_MULTI_PANE_SETTINGS_DEEP_LINK"; field public static final String LOADER_USAGE_STATS = "android.permission.LOADER_USAGE_STATS"; field public static final String LOCATION_HARDWARE = "android.permission.LOCATION_HARDWARE"; field public static final String MANAGE_DOCUMENTS = "android.permission.MANAGE_DOCUMENTS"; @@ -1297,6 +1298,7 @@ package android { field public static final int shortcutLongLabel = 16844074; // 0x101052a field public static final int shortcutShortLabel = 16844073; // 0x1010529 field public static final int shouldDisableView = 16843246; // 0x10101ee + field public static final int shouldUseDefaultUnfoldTransition = 16844364; // 0x101064c field public static final int showAsAction = 16843481; // 0x10102d9 field public static final int showDefault = 16843258; // 0x10101fa field public static final int showDividers = 16843561; // 0x1010329 @@ -2012,6 +2014,9 @@ package android { public static final class R.id { ctor public R.id(); field public static final int accessibilityActionContextClick = 16908348; // 0x102003c + field public static final int accessibilityActionDragCancel = 16908375; // 0x1020057 + field public static final int accessibilityActionDragDrop = 16908374; // 0x1020056 + field public static final int accessibilityActionDragStart = 16908373; // 0x1020055 field public static final int accessibilityActionHideTooltip = 16908357; // 0x1020045 field public static final int accessibilityActionImeEnter = 16908372; // 0x1020054 field public static final int accessibilityActionMoveWindow = 16908354; // 0x1020042 @@ -6707,6 +6712,7 @@ package android.app { } public class TaskInfo { + method public boolean isVisible(); field @Nullable public android.content.ComponentName baseActivity; field @NonNull public android.content.Intent baseIntent; field public boolean isRunning; @@ -6922,6 +6928,7 @@ package android.app { method public android.graphics.drawable.Drawable loadIcon(android.content.pm.PackageManager); method public CharSequence loadLabel(android.content.pm.PackageManager); method public android.graphics.drawable.Drawable loadThumbnail(android.content.pm.PackageManager); + method public boolean shouldUseDefaultUnfoldTransition(); method public boolean supportsMultipleDisplays(); method public void writeToParcel(android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator CREATOR; @@ -17943,6 +17950,7 @@ package android.hardware.camera2 { field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key EDGE_AVAILABLE_EDGE_MODES; field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key FLASH_INFO_AVAILABLE; field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key HOT_PIXEL_AVAILABLE_HOT_PIXEL_MODES; + field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key INFO_DEVICE_STATE_SENSOR_ORIENTATION_MAP; field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key INFO_SUPPORTED_HARDWARE_LEVEL; field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key INFO_VERSION; field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key JPEG_AVAILABLE_THUMBNAIL_SIZES; @@ -18637,6 +18645,12 @@ package android.hardware.camera2.params { method public android.util.Rational getElement(int, int); } + public final class DeviceStateSensorOrientationMap { + method public int getSensorOrientation(long); + field public static final long FOLDED = 4L; // 0x4L + field public static final long NORMAL = 0L; // 0x0L + } + public final class ExtensionSessionConfiguration { ctor public ExtensionSessionConfiguration(int, @NonNull java.util.List, @NonNull java.util.concurrent.Executor, @NonNull android.hardware.camera2.CameraExtensionSession.StateCallback); method @NonNull public java.util.concurrent.Executor getExecutor(); @@ -20178,8 +20192,10 @@ package android.media { method public int getAllowedCapturePolicy(); method public int getContentType(); method public int getFlags(); + method public int getSpatializationBehavior(); method public int getUsage(); method public int getVolumeControlStream(); + method public boolean isContentSpatialized(); method public void writeToParcel(android.os.Parcel, int); field public static final int ALLOW_CAPTURE_BY_ALL = 1; // 0x1 field public static final int ALLOW_CAPTURE_BY_NONE = 3; // 0x3 @@ -20193,6 +20209,8 @@ package android.media { field public static final int FLAG_AUDIBILITY_ENFORCED = 1; // 0x1 field public static final int FLAG_HW_AV_SYNC = 16; // 0x10 field @Deprecated public static final int FLAG_LOW_LATENCY = 256; // 0x100 + field public static final int SPATIALIZATION_BEHAVIOR_AUTO = 0; // 0x0 + field public static final int SPATIALIZATION_BEHAVIOR_NEVER = 1; // 0x1 field public static final int USAGE_ALARM = 4; // 0x4 field public static final int USAGE_ASSISTANCE_ACCESSIBILITY = 11; // 0xb field public static final int USAGE_ASSISTANCE_NAVIGATION_GUIDANCE = 12; // 0xc @@ -20219,7 +20237,9 @@ package android.media { method public android.media.AudioAttributes.Builder setContentType(int); method public android.media.AudioAttributes.Builder setFlags(int); method @NonNull public android.media.AudioAttributes.Builder setHapticChannelsMuted(boolean); + method @NonNull public android.media.AudioAttributes.Builder setIsContentSpatialized(boolean); method public android.media.AudioAttributes.Builder setLegacyStreamType(int); + method @NonNull public android.media.AudioAttributes.Builder setSpatializationBehavior(int); method public android.media.AudioAttributes.Builder setUsage(int); } @@ -20336,24 +20356,45 @@ package android.media { field public static final int CHANNEL_IN_Y_AXIS = 4096; // 0x1000 field public static final int CHANNEL_IN_Z_AXIS = 8192; // 0x2000 field public static final int CHANNEL_OUT_5POINT1 = 252; // 0xfc + field public static final int CHANNEL_OUT_5POINT1POINT2 = 3145980; // 0x3000fc + field public static final int CHANNEL_OUT_5POINT1POINT4 = 737532; // 0xb40fc field @Deprecated public static final int CHANNEL_OUT_7POINT1 = 1020; // 0x3fc + field public static final int CHANNEL_OUT_7POINT1POINT2 = 3152124; // 0x3018fc + field public static final int CHANNEL_OUT_7POINT1POINT4 = 743676; // 0xb58fc field public static final int CHANNEL_OUT_7POINT1_SURROUND = 6396; // 0x18fc + field public static final int CHANNEL_OUT_9POINT1POINT4 = 202070268; // 0xc0b58fc + field public static final int CHANNEL_OUT_9POINT1POINT6 = 205215996; // 0xc3b58fc field public static final int CHANNEL_OUT_BACK_CENTER = 1024; // 0x400 field public static final int CHANNEL_OUT_BACK_LEFT = 64; // 0x40 field public static final int CHANNEL_OUT_BACK_RIGHT = 128; // 0x80 + field public static final int CHANNEL_OUT_BOTTOM_FRONT_CENTER = 8388608; // 0x800000 + field public static final int CHANNEL_OUT_BOTTOM_FRONT_LEFT = 4194304; // 0x400000 + field public static final int CHANNEL_OUT_BOTTOM_FRONT_RIGHT = 16777216; // 0x1000000 field public static final int CHANNEL_OUT_DEFAULT = 1; // 0x1 field public static final int CHANNEL_OUT_FRONT_CENTER = 16; // 0x10 field public static final int CHANNEL_OUT_FRONT_LEFT = 4; // 0x4 field public static final int CHANNEL_OUT_FRONT_LEFT_OF_CENTER = 256; // 0x100 field public static final int CHANNEL_OUT_FRONT_RIGHT = 8; // 0x8 field public static final int CHANNEL_OUT_FRONT_RIGHT_OF_CENTER = 512; // 0x200 + field public static final int CHANNEL_OUT_FRONT_WIDE_LEFT = 67108864; // 0x4000000 + field public static final int CHANNEL_OUT_FRONT_WIDE_RIGHT = 134217728; // 0x8000000 field public static final int CHANNEL_OUT_LOW_FREQUENCY = 32; // 0x20 + field public static final int CHANNEL_OUT_LOW_FREQUENCY_2 = 33554432; // 0x2000000 field public static final int CHANNEL_OUT_MONO = 4; // 0x4 field public static final int CHANNEL_OUT_QUAD = 204; // 0xcc field public static final int CHANNEL_OUT_SIDE_LEFT = 2048; // 0x800 field public static final int CHANNEL_OUT_SIDE_RIGHT = 4096; // 0x1000 field public static final int CHANNEL_OUT_STEREO = 12; // 0xc field public static final int CHANNEL_OUT_SURROUND = 1052; // 0x41c + field public static final int CHANNEL_OUT_TOP_BACK_CENTER = 262144; // 0x40000 + field public static final int CHANNEL_OUT_TOP_BACK_LEFT = 131072; // 0x20000 + field public static final int CHANNEL_OUT_TOP_BACK_RIGHT = 524288; // 0x80000 + field public static final int CHANNEL_OUT_TOP_CENTER = 8192; // 0x2000 + field public static final int CHANNEL_OUT_TOP_FRONT_CENTER = 32768; // 0x8000 + field public static final int CHANNEL_OUT_TOP_FRONT_LEFT = 16384; // 0x4000 + field public static final int CHANNEL_OUT_TOP_FRONT_RIGHT = 65536; // 0x10000 + field public static final int CHANNEL_OUT_TOP_SIDE_LEFT = 1048576; // 0x100000 + field public static final int CHANNEL_OUT_TOP_SIDE_RIGHT = 2097152; // 0x200000 field @NonNull public static final android.os.Parcelable.Creator CREATOR; field public static final int ENCODING_AAC_ELD = 15; // 0xf field public static final int ENCODING_AAC_HE_V1 = 11; // 0xb @@ -20423,6 +20464,7 @@ package android.media { method public String getProperty(String); method public int getRingerMode(); method @Deprecated public int getRouting(int); + method @NonNull public android.media.Spatializer getSpatializer(); method public int getStreamMaxVolume(int); method public int getStreamMinVolume(int); method public int getStreamVolume(int); @@ -22540,6 +22582,7 @@ package android.media { field public static final String KEY_MAX_FPS_TO_ENCODER = "max-fps-to-encoder"; field public static final String KEY_MAX_HEIGHT = "max-height"; field public static final String KEY_MAX_INPUT_SIZE = "max-input-size"; + field public static final String KEY_MAX_OUTPUT_CHANNEL_COUNT = "max-output-channel-count"; field public static final String KEY_MAX_PTS_GAP_TO_ENCODER = "max-pts-gap-to-encoder"; field public static final String KEY_MAX_WIDTH = "max-width"; field public static final String KEY_MIME = "mime"; @@ -23819,6 +23862,23 @@ package android.media { method public void onLoadComplete(android.media.SoundPool, int, int); } + public class Spatializer { + method public void addOnSpatializerStateChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.Spatializer.OnSpatializerStateChangedListener); + method public boolean canBeSpatialized(@NonNull android.media.AudioAttributes, @NonNull android.media.AudioFormat); + method public int getImmersiveAudioLevel(); + method public boolean isAvailable(); + method public boolean isEnabled(); + method public void removeOnSpatializerStateChangedListener(@NonNull android.media.Spatializer.OnSpatializerStateChangedListener); + field public static final int SPATIALIZER_IMMERSIVE_LEVEL_MULTICHANNEL = 1; // 0x1 + field public static final int SPATIALIZER_IMMERSIVE_LEVEL_NONE = 0; // 0x0 + field public static final int SPATIALIZER_IMMERSIVE_LEVEL_OTHER = -1; // 0xffffffff + } + + public static interface Spatializer.OnSpatializerStateChangedListener { + method public void onSpatializerAvailableChanged(@NonNull android.media.Spatializer, boolean); + method public void onSpatializerEnabledChanged(@NonNull android.media.Spatializer, boolean); + } + public final class SubtitleData { ctor public SubtitleData(int, long, long, @NonNull byte[]); method @NonNull public byte[] getData(); @@ -30797,6 +30857,7 @@ package android.os { field public static final int Q = 29; // 0x1d field public static final int R = 30; // 0x1e field public static final int S = 31; // 0x1f + field public static final int S_V2 = 32; // 0x20 } public final class Bundle extends android.os.BaseBundle implements java.lang.Cloneable android.os.Parcelable { @@ -31070,8 +31131,8 @@ package android.os { ctor public Environment(); method public static java.io.File getDataDirectory(); method public static java.io.File getDownloadCacheDirectory(); - method @Deprecated public static java.io.File getExternalStorageDirectory(); - method @Deprecated public static java.io.File getExternalStoragePublicDirectory(String); + method public static java.io.File getExternalStorageDirectory(); + method public static java.io.File getExternalStoragePublicDirectory(String); method public static String getExternalStorageState(); method public static String getExternalStorageState(java.io.File); method @NonNull public static java.io.File getRootDirectory(); @@ -35182,6 +35243,7 @@ package android.provider { field public static final String ACTION_SEARCH_SETTINGS = "android.search.action.SEARCH_SETTINGS"; field public static final String ACTION_SECURITY_SETTINGS = "android.settings.SECURITY_SETTINGS"; field public static final String ACTION_SETTINGS = "android.settings.SETTINGS"; + field public static final String ACTION_SETTINGS_EMBED_DEEP_LINK_ACTIVITY = "android.settings.SETTINGS_EMBED_DEEP_LINK_ACTIVITY"; field public static final String ACTION_SHOW_REGULATORY_INFO = "android.settings.SHOW_REGULATORY_INFO"; field public static final String ACTION_SHOW_WORK_POLICY_INFO = "android.settings.SHOW_WORK_POLICY_INFO"; field public static final String ACTION_SOUND_SETTINGS = "android.settings.SOUND_SETTINGS"; @@ -35222,6 +35284,8 @@ package android.provider { field public static final String EXTRA_EASY_CONNECT_ERROR_CODE = "android.provider.extra.EASY_CONNECT_ERROR_CODE"; field public static final String EXTRA_INPUT_METHOD_ID = "input_method_id"; field public static final String EXTRA_NOTIFICATION_LISTENER_COMPONENT_NAME = "android.provider.extra.NOTIFICATION_LISTENER_COMPONENT_NAME"; + field public static final String EXTRA_SETTINGS_EMBEDDED_DEEP_LINK_HIGHLIGHT_MENU_KEY = "android.provider.extra.SETTINGS_EMBEDDED_DEEP_LINK_HIGHLIGHT_MENU_KEY"; + field public static final String EXTRA_SETTINGS_EMBEDDED_DEEP_LINK_INTENT_URI = "android.provider.extra.SETTINGS_EMBEDDED_DEEP_LINK_INTENT_URI"; field public static final String EXTRA_SUB_ID = "android.provider.extra.SUB_ID"; field public static final String EXTRA_WIFI_NETWORK_LIST = "android.provider.extra.WIFI_NETWORK_LIST"; field public static final String EXTRA_WIFI_NETWORK_RESULT_LIST = "android.provider.extra.WIFI_NETWORK_RESULT_LIST"; @@ -38947,6 +39011,13 @@ package android.service.textservice { package android.service.voice { + public final class VisibleActivityInfo implements android.os.Parcelable { + method public int describeContents(); + method @NonNull public android.service.voice.VoiceInteractionSession.ActivityId getActivityId(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator CREATOR; + } + public class VoiceInteractionService extends android.app.Service { ctor public VoiceInteractionService(); method public int getDisabledShowContext(); @@ -39008,6 +39079,7 @@ package android.service.voice { method public void onTaskStarted(android.content.Intent, int); method public void onTrimMemory(int); method public final void performDirectAction(@NonNull android.app.DirectAction, @Nullable android.os.Bundle, @Nullable android.os.CancellationSignal, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer); + method public final void registerVisibleActivityCallback(@NonNull java.util.concurrent.Executor, @NonNull android.service.voice.VoiceInteractionSession.VisibleActivityCallback); method public final void requestDirectActions(@NonNull android.service.voice.VoiceInteractionSession.ActivityId, @Nullable android.os.CancellationSignal, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer>); method public void setContentView(android.view.View); method public void setDisabledShowContext(int); @@ -39017,6 +39089,7 @@ package android.service.voice { method public void show(android.os.Bundle, int); method public void startAssistantActivity(android.content.Intent); method public void startVoiceActivity(android.content.Intent); + method public final void unregisterVisibleActivityCallback(@NonNull android.service.voice.VoiceInteractionSession.VisibleActivityCallback); field public static final int SHOW_SOURCE_ACTIVITY = 16; // 0x10 field public static final int SHOW_SOURCE_APPLICATION = 8; // 0x8 field public static final int SHOW_SOURCE_ASSIST_GESTURE = 4; // 0x4 @@ -39090,6 +39163,11 @@ package android.service.voice { method public boolean isActive(); } + public static interface VoiceInteractionSession.VisibleActivityCallback { + method public default void onInvisible(@NonNull android.service.voice.VoiceInteractionSession.ActivityId); + method public default void onVisible(@NonNull android.service.voice.VisibleActivityInfo); + } + public abstract class VoiceInteractionSessionService extends android.app.Service { ctor public VoiceInteractionSessionService(); method public android.os.IBinder onBind(android.content.Intent); @@ -46837,8 +46915,15 @@ package android.view { } @UiThread public interface AttachedSurfaceControl { + method public default void addOnBufferTransformHintChangedListener(@NonNull android.view.AttachedSurfaceControl.OnBufferTransformHintChangedListener); method public boolean applyTransactionOnDraw(@NonNull android.view.SurfaceControl.Transaction); method @Nullable public android.view.SurfaceControl.Transaction buildReparentTransaction(@NonNull android.view.SurfaceControl); + method public default int getBufferTransformHint(); + method public default void removeOnBufferTransformHintChangedListener(@NonNull android.view.AttachedSurfaceControl.OnBufferTransformHintChangedListener); + } + + @UiThread public static interface AttachedSurfaceControl.OnBufferTransformHintChangedListener { + method public void onBufferTransformHintChanged(int); } public final class Choreographer { @@ -48328,6 +48413,12 @@ package android.view { method public void readFromParcel(android.os.Parcel); method public void release(); method public void writeToParcel(android.os.Parcel, int); + field public static final int BUFFER_TRANSFORM_IDENTITY = 0; // 0x0 + field public static final int BUFFER_TRANSFORM_MIRROR_HORIZONTAL = 1; // 0x1 + field public static final int BUFFER_TRANSFORM_MIRROR_VERTICAL = 2; // 0x2 + field public static final int BUFFER_TRANSFORM_ROTATE_180 = 3; // 0x3 + field public static final int BUFFER_TRANSFORM_ROTATE_270 = 7; // 0x7 + field public static final int BUFFER_TRANSFORM_ROTATE_90 = 4; // 0x4 field @NonNull public static final android.os.Parcelable.Creator CREATOR; } @@ -49190,6 +49281,7 @@ package android.view { field public static final int AUTOFILL_TYPE_NONE = 0; // 0x0 field public static final int AUTOFILL_TYPE_TEXT = 1; // 0x1 field public static final int AUTOFILL_TYPE_TOGGLE = 2; // 0x2 + field public static final int DRAG_FLAG_ACCESSIBILITY_ACTION = 1024; // 0x400 field public static final int DRAG_FLAG_GLOBAL = 256; // 0x100 field public static final int DRAG_FLAG_GLOBAL_PERSISTABLE_URI_PERMISSION = 64; // 0x40 field public static final int DRAG_FLAG_GLOBAL_PREFIX_URI_PERMISSION = 128; // 0x80 @@ -50616,6 +50708,9 @@ package android.view.accessibility { method public void setPackageName(CharSequence); method public void writeToParcel(android.os.Parcel, int); field public static final int CONTENT_CHANGE_TYPE_CONTENT_DESCRIPTION = 4; // 0x4 + field public static final int CONTENT_CHANGE_TYPE_DRAG_CANCELLED = 512; // 0x200 + field public static final int CONTENT_CHANGE_TYPE_DRAG_DROPPED = 256; // 0x100 + field public static final int CONTENT_CHANGE_TYPE_DRAG_STARTED = 128; // 0x80 field public static final int CONTENT_CHANGE_TYPE_PANE_APPEARED = 16; // 0x10 field public static final int CONTENT_CHANGE_TYPE_PANE_DISAPPEARED = 32; // 0x20 field public static final int CONTENT_CHANGE_TYPE_PANE_TITLE = 8; // 0x8 @@ -50914,6 +51009,9 @@ package android.view.accessibility { field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_COPY; field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_CUT; field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_DISMISS; + field @NonNull public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_DRAG_CANCEL; + field @NonNull public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_DRAG_DROP; + field @NonNull public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_DRAG_START; field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_EXPAND; field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_FOCUS; field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_HIDE_TOOLTIP; diff --git a/core/api/system-current.txt b/core/api/system-current.txt index f706f0a41c35..16c5253427a8 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -26,6 +26,7 @@ package android { field public static final String ADJUST_RUNTIME_PERMISSIONS_POLICY = "android.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY"; field public static final String ALLOCATE_AGGRESSIVE = "android.permission.ALLOCATE_AGGRESSIVE"; field public static final String ALLOW_ANY_CODEC_FOR_PLAYBACK = "android.permission.ALLOW_ANY_CODEC_FOR_PLAYBACK"; + field public static final String ALLOW_PLACE_IN_MULTI_PANE_SETTINGS = "android.permission.ALLOW_PLACE_IN_MULTI_PANE_SETTINGS"; field public static final String AMBIENT_WALLPAPER = "android.permission.AMBIENT_WALLPAPER"; field public static final String APPROVE_INCIDENT_REPORTS = "android.permission.APPROVE_INCIDENT_REPORTS"; field public static final String ASSOCIATE_COMPANION_DEVICES = "android.permission.ASSOCIATE_COMPANION_DEVICES"; @@ -436,6 +437,11 @@ package android.app { method public void onUidImportance(int, int); } + public class ActivityOptions { + method public int getLaunchTaskId(); + method @RequiresPermission("android.permission.START_TASKS_FROM_RECENTS") public void setLaunchTaskId(int); + } + public class AlarmManager { method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void set(int, long, long, long, android.app.PendingIntent, android.os.WorkSource); method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void set(int, long, long, long, android.app.AlarmManager.OnAlarmListener, android.os.Handler, android.os.WorkSource); @@ -3262,11 +3268,13 @@ package android.hardware.display { public final class DisplayManager { method @RequiresPermission(android.Manifest.permission.ACCESS_AMBIENT_LIGHT_STATS) public java.util.List getAmbientBrightnessStats(); method @RequiresPermission(android.Manifest.permission.CONFIGURE_DISPLAY_BRIGHTNESS) public android.hardware.display.BrightnessConfiguration getBrightnessConfiguration(); + method @Nullable @RequiresPermission(android.Manifest.permission.CONFIGURE_DISPLAY_BRIGHTNESS) public android.hardware.display.BrightnessConfiguration getBrightnessConfigurationForDisplay(@NonNull String); method @RequiresPermission(android.Manifest.permission.BRIGHTNESS_SLIDER_USAGE) public java.util.List getBrightnessEvents(); method @Nullable @RequiresPermission(android.Manifest.permission.CONFIGURE_DISPLAY_BRIGHTNESS) public android.hardware.display.BrightnessConfiguration getDefaultBrightnessConfiguration(); method public android.util.Pair getMinimumBrightnessCurve(); method public android.graphics.Point getStableDisplaySize(); method @RequiresPermission(android.Manifest.permission.CONFIGURE_DISPLAY_BRIGHTNESS) public void setBrightnessConfiguration(android.hardware.display.BrightnessConfiguration); + method @RequiresPermission(android.Manifest.permission.CONFIGURE_DISPLAY_BRIGHTNESS) public void setBrightnessConfigurationForDisplay(@NonNull android.hardware.display.BrightnessConfiguration, @NonNull String); method @Deprecated @RequiresPermission(android.Manifest.permission.CONTROL_DISPLAY_SATURATION) public void setSaturationLevel(float); } @@ -5370,6 +5378,46 @@ package android.media { field public static final android.media.RouteDiscoveryPreference EMPTY; } + public class Spatializer { + method @RequiresPermission("android.permission.MODIFY_DEFAULT_AUDIO_EFFECTS") public void addCompatibleAudioDevice(@NonNull android.media.AudioDeviceAttributes); + method @RequiresPermission("android.permission.MODIFY_DEFAULT_AUDIO_EFFECTS") public void addOnHeadTrackingModeChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.Spatializer.OnHeadTrackingModeChangedListener); + method @RequiresPermission("android.permission.MODIFY_DEFAULT_AUDIO_EFFECTS") public void clearOnHeadToSoundstagePoseUpdatedListener(); + method @RequiresPermission("android.permission.MODIFY_DEFAULT_AUDIO_EFFECTS") public void clearOnSpatializerOutputChangedListener(); + method @NonNull @RequiresPermission("android.permission.MODIFY_DEFAULT_AUDIO_EFFECTS") public java.util.List getCompatibleAudioDevices(); + method @RequiresPermission("android.permission.MODIFY_DEFAULT_AUDIO_EFFECTS") public int getDesiredHeadTrackingMode(); + method @RequiresPermission("android.permission.MODIFY_DEFAULT_AUDIO_EFFECTS") public void getEffectParameter(int, @NonNull byte[]); + method @RequiresPermission("android.permission.MODIFY_DEFAULT_AUDIO_EFFECTS") public int getHeadTrackingMode(); + method @IntRange(from=0) @RequiresPermission("android.permission.MODIFY_DEFAULT_AUDIO_EFFECTS") public int getOutput(); + method @NonNull @RequiresPermission("android.permission.MODIFY_DEFAULT_AUDIO_EFFECTS") public java.util.List getSupportedHeadTrackingModes(); + method @RequiresPermission("android.permission.MODIFY_DEFAULT_AUDIO_EFFECTS") public void recenterHeadTracker(); + method @RequiresPermission("android.permission.MODIFY_DEFAULT_AUDIO_EFFECTS") public void removeCompatibleAudioDevice(@NonNull android.media.AudioDeviceAttributes); + method @RequiresPermission("android.permission.MODIFY_DEFAULT_AUDIO_EFFECTS") public void removeOnHeadTrackingModeChangedListener(@NonNull android.media.Spatializer.OnHeadTrackingModeChangedListener); + method @RequiresPermission("android.permission.MODIFY_DEFAULT_AUDIO_EFFECTS") public void setDesiredHeadTrackingMode(int); + method @RequiresPermission("android.permission.MODIFY_DEFAULT_AUDIO_EFFECTS") public void setEffectParameter(int, @NonNull byte[]); + method @RequiresPermission("android.permission.MODIFY_DEFAULT_AUDIO_EFFECTS") public void setEnabled(boolean); + method @RequiresPermission("android.permission.MODIFY_DEFAULT_AUDIO_EFFECTS") public void setGlobalTransform(@NonNull float[]); + method @RequiresPermission("android.permission.MODIFY_DEFAULT_AUDIO_EFFECTS") public void setOnHeadToSoundstagePoseUpdatedListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.Spatializer.OnHeadToSoundstagePoseUpdatedListener); + method @RequiresPermission("android.permission.MODIFY_DEFAULT_AUDIO_EFFECTS") public void setOnSpatializerOutputChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.Spatializer.OnSpatializerOutputChangedListener); + field @RequiresPermission("android.permission.MODIFY_DEFAULT_AUDIO_EFFECTS") public static final int HEAD_TRACKING_MODE_DISABLED = -1; // 0xffffffff + field @RequiresPermission("android.permission.MODIFY_DEFAULT_AUDIO_EFFECTS") public static final int HEAD_TRACKING_MODE_OTHER = 0; // 0x0 + field @RequiresPermission("android.permission.MODIFY_DEFAULT_AUDIO_EFFECTS") public static final int HEAD_TRACKING_MODE_RELATIVE_DEVICE = 2; // 0x2 + field @RequiresPermission("android.permission.MODIFY_DEFAULT_AUDIO_EFFECTS") public static final int HEAD_TRACKING_MODE_RELATIVE_WORLD = 1; // 0x1 + field @RequiresPermission("android.permission.MODIFY_DEFAULT_AUDIO_EFFECTS") public static final int HEAD_TRACKING_MODE_UNSUPPORTED = -2; // 0xfffffffe + } + + public static interface Spatializer.OnHeadToSoundstagePoseUpdatedListener { + method public void onHeadToSoundstagePoseUpdated(@NonNull android.media.Spatializer, @NonNull float[]); + } + + public static interface Spatializer.OnHeadTrackingModeChangedListener { + method public void onDesiredHeadTrackingModeChanged(@NonNull android.media.Spatializer, int); + method public void onHeadTrackingModeChanged(@NonNull android.media.Spatializer, int); + } + + public static interface Spatializer.OnSpatializerOutputChangedListener { + method public void onSpatializerOutputChanged(@NonNull android.media.Spatializer, @IntRange(from=0) int); + } + } package android.media.audiofx { @@ -14415,6 +14463,7 @@ package android.view.contentcapture { method public int getFlags(); method @Nullable public android.view.contentcapture.ContentCaptureSessionId getParentSessionId(); method public int getTaskId(); + method @Nullable public android.os.IBinder getWindowToken(); field public static final int FLAG_DISABLED_BY_APP = 1; // 0x1 field public static final int FLAG_DISABLED_BY_FLAG_SECURE = 2; // 0x2 field public static final int FLAG_RECONNECTED = 4; // 0x4 @@ -14422,6 +14471,7 @@ package android.view.contentcapture { public final class ContentCaptureEvent implements android.os.Parcelable { method public int describeContents(); + method @Nullable public android.graphics.Rect getBounds(); method @Nullable public android.view.contentcapture.ContentCaptureContext getContentCaptureContext(); method public long getEventTime(); method @Nullable public android.view.autofill.AutofillId getId(); @@ -14441,6 +14491,7 @@ package android.view.contentcapture { field public static final int TYPE_VIEW_TEXT_CHANGED = 3; // 0x3 field public static final int TYPE_VIEW_TREE_APPEARED = 5; // 0x5 field public static final int TYPE_VIEW_TREE_APPEARING = 4; // 0x4 + field public static final int TYPE_WINDOW_BOUNDS_CHANGED = 10; // 0xa } public final class ContentCaptureManager { diff --git a/core/api/test-current.txt b/core/api/test-current.txt index ea6d0cecfd73..5c9da0bc97e6 100644 --- a/core/api/test-current.txt +++ b/core/api/test-current.txt @@ -113,6 +113,7 @@ package android.app { method @RequiresPermission(android.Manifest.permission.RESET_APP_ERRORS) public void resetAppErrors(); method public static void resumeAppSwitches() throws android.os.RemoteException; method @RequiresPermission(android.Manifest.permission.CHANGE_CONFIGURATION) public void scheduleApplicationInfoChanged(java.util.List, int); + method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}) public void setStopUserOnSwitch(int); method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) public boolean stopUser(int, boolean); method @RequiresPermission(android.Manifest.permission.CHANGE_CONFIGURATION) public boolean updateMccMncConfiguration(@NonNull String, @NonNull String); method @RequiresPermission(android.Manifest.permission.DUMP) public void waitForBroadcastIdle(); @@ -127,6 +128,9 @@ package android.app { field public static final int PROCESS_CAPABILITY_NONE = 0; // 0x0 field public static final int PROCESS_STATE_FOREGROUND_SERVICE = 4; // 0x4 field public static final int PROCESS_STATE_TOP = 2; // 0x2 + field public static final int STOP_USER_ON_SWITCH_DEFAULT = -1; // 0xffffffff + field public static final int STOP_USER_ON_SWITCH_FALSE = 0; // 0x0 + field public static final int STOP_USER_ON_SWITCH_TRUE = 1; // 0x1 } public static class ActivityManager.RunningAppProcessInfo implements android.os.Parcelable { @@ -144,7 +148,6 @@ package android.app { method @NonNull @RequiresPermission(android.Manifest.permission.START_TASKS_FROM_RECENTS) public static android.app.ActivityOptions makeCustomTaskAnimation(@NonNull android.content.Context, int, int, @Nullable android.os.Handler, @Nullable android.app.ActivityOptions.OnAnimationStartedListener, @Nullable android.app.ActivityOptions.OnAnimationFinishedListener); method public static void setExitTransitionTimeout(long); method public void setLaunchActivityType(int); - method public void setLaunchTaskId(int); method public void setLaunchWindowingMode(int); method public void setLaunchedFromBubble(boolean); method public void setTaskAlwaysOnTop(boolean); @@ -425,6 +428,7 @@ package android.app.admin { public class DevicePolicyManager { method public int checkProvisioningPreCondition(@Nullable String, @NonNull String); + method @RequiresPermission("android.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS") public void clearOrganizationId(); method @RequiresPermission(android.Manifest.permission.CLEAR_FREEZE_PERIOD) public void clearSystemUpdatePolicyFreezePeriodRecord(); method @Nullable public android.os.UserHandle createAndProvisionManagedProfile(@NonNull android.app.admin.ManagedProfileProvisioningParams) throws android.app.admin.ProvisioningException; method @RequiresPermission(android.Manifest.permission.FORCE_DEVICE_POLICY_MANAGER_LOGS) public long forceNetworkLogs(); @@ -447,6 +451,7 @@ package android.app.admin { method @RequiresPermission("android.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS") public void resetDefaultCrossProfileIntentFilters(int); method @RequiresPermission(allOf={"android.permission.MANAGE_DEVICE_ADMINS", android.Manifest.permission.INTERACT_ACROSS_USERS_FULL}) public void setActiveAdmin(@NonNull android.content.ComponentName, boolean, int); method @RequiresPermission("android.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS") public boolean setDeviceOwner(@NonNull android.content.ComponentName, @Nullable String, int); + method @RequiresPermission("android.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS") public boolean setDeviceOwnerOnly(@NonNull android.content.ComponentName, @Nullable String, int); method @RequiresPermission("android.permission.MANAGE_DEVICE_ADMINS") public void setNextOperationSafety(int, int); field public static final String ACTION_DATA_SHARING_RESTRICTION_APPLIED = "android.app.action.DATA_SHARING_RESTRICTION_APPLIED"; field public static final String ACTION_DEVICE_POLICY_CONSTANTS_CHANGED = "android.app.action.DEVICE_POLICY_CONSTANTS_CHANGED"; @@ -780,6 +785,7 @@ package android.content.pm { field public static final float OVERRIDE_MIN_ASPECT_RATIO_LARGE_VALUE = 1.7777778f; field public static final long OVERRIDE_MIN_ASPECT_RATIO_MEDIUM = 180326845L; // 0xabf91bdL field public static final float OVERRIDE_MIN_ASPECT_RATIO_MEDIUM_VALUE = 1.5f; + field public static final long OVERRIDE_MIN_ASPECT_RATIO_PORTRAIT_ONLY = 203647190L; // 0xc2368d6L field public static final int RESIZE_MODE_RESIZEABLE = 2; // 0x2 } @@ -1133,10 +1139,10 @@ package android.hardware.camera2 { package android.hardware.devicestate { public final class DeviceStateManager { - method @RequiresPermission(android.Manifest.permission.CONTROL_DEVICE_STATE) public void cancelRequest(@NonNull android.hardware.devicestate.DeviceStateRequest); + method @RequiresPermission(value=android.Manifest.permission.CONTROL_DEVICE_STATE, conditional=true) public void cancelRequest(@NonNull android.hardware.devicestate.DeviceStateRequest); method @NonNull public int[] getSupportedStates(); method public void registerCallback(@NonNull java.util.concurrent.Executor, @NonNull android.hardware.devicestate.DeviceStateManager.DeviceStateCallback); - method @RequiresPermission(android.Manifest.permission.CONTROL_DEVICE_STATE) public void requestState(@NonNull android.hardware.devicestate.DeviceStateRequest, @Nullable java.util.concurrent.Executor, @Nullable android.hardware.devicestate.DeviceStateRequest.Callback); + method @RequiresPermission(value=android.Manifest.permission.CONTROL_DEVICE_STATE, conditional=true) public void requestState(@NonNull android.hardware.devicestate.DeviceStateRequest, @Nullable java.util.concurrent.Executor, @Nullable android.hardware.devicestate.DeviceStateRequest.Callback); method public void unregisterCallback(@NonNull android.hardware.devicestate.DeviceStateManager.DeviceStateCallback); field public static final int MAXIMUM_DEVICE_STATE = 255; // 0xff field public static final int MINIMUM_DEVICE_STATE = 0; // 0x0 @@ -1281,6 +1287,12 @@ package android.hardware.soundtrigger { package android.inputmethodservice { + public abstract class AbstractInputMethodService extends android.window.WindowProviderService implements android.view.KeyEvent.Callback { + method public final int getInitialDisplayId(); + method @Nullable public final android.os.Bundle getWindowContextOptions(); + method public final int getWindowType(); + } + @UiContext public class InputMethodService extends android.inputmethodservice.AbstractInputMethodService { field public static final long FINISH_INPUT_NO_FALLBACK_CONNECTION = 156215187L; // 0x94fa793L } @@ -2121,6 +2133,7 @@ package android.provider { public final class DeviceConfig { field public static final String NAMESPACE_ALARM_MANAGER = "alarm_manager"; field public static final String NAMESPACE_ANDROID = "android"; + field public static final String NAMESPACE_APP_COMPAT_OVERRIDES = "app_compat_overrides"; field public static final String NAMESPACE_CONSTRAIN_DISPLAY_APIS = "constrain_display_apis"; field public static final String NAMESPACE_DEVICE_IDLE = "device_idle"; field public static final String NAMESPACE_JOB_SCHEDULER = "jobscheduler"; @@ -2383,6 +2396,10 @@ package android.service.voice { method @RequiresPermission(allOf={android.Manifest.permission.RECORD_AUDIO, android.Manifest.permission.CAPTURE_AUDIO_HOTWORD}) public void triggerHardwareRecognitionEventForTest(int, int, boolean, int, int, int, boolean, @NonNull android.media.AudioFormat, @Nullable byte[]); } + public final class VisibleActivityInfo implements android.os.Parcelable { + ctor public VisibleActivityInfo(int, @NonNull android.os.IBinder); + } + } package android.service.watchdog { @@ -3178,13 +3195,6 @@ package android.window { method @Nullable public android.view.View getBrandingView(); } - public final class StartingWindowInfo implements android.os.Parcelable { - ctor public StartingWindowInfo(); - method public int describeContents(); - method public void writeToParcel(@NonNull android.os.Parcel, int); - field @NonNull public static final android.os.Parcelable.Creator CREATOR; - } - public final class TaskAppearedInfo implements android.os.Parcelable { ctor public TaskAppearedInfo(@NonNull android.app.ActivityManager.RunningTaskInfo, @NonNull android.view.SurfaceControl); method public int describeContents(); @@ -3194,9 +3204,57 @@ package android.window { field @NonNull public static final android.os.Parcelable.Creator CREATOR; } + public final class TaskFragmentCreationParams implements android.os.Parcelable { + method @NonNull public android.os.IBinder getFragmentToken(); + method @NonNull public android.graphics.Rect getInitialBounds(); + method @NonNull public android.window.TaskFragmentOrganizerToken getOrganizer(); + method @NonNull public android.os.IBinder getOwnerToken(); + method public int getWindowingMode(); + field @NonNull public static final android.os.Parcelable.Creator CREATOR; + } + + public static final class TaskFragmentCreationParams.Builder { + ctor public TaskFragmentCreationParams.Builder(@NonNull android.window.TaskFragmentOrganizerToken, @NonNull android.os.IBinder, @NonNull android.os.IBinder); + method @NonNull public android.window.TaskFragmentCreationParams build(); + method @NonNull public android.window.TaskFragmentCreationParams.Builder setInitialBounds(@NonNull android.graphics.Rect); + method @NonNull public android.window.TaskFragmentCreationParams.Builder setWindowingMode(int); + } + + public final class TaskFragmentInfo implements android.os.Parcelable { + method public boolean equalsForTaskFragmentOrganizer(@Nullable android.window.TaskFragmentInfo); + method @NonNull public java.util.List getActivities(); + method @NonNull public android.content.res.Configuration getConfiguration(); + method @NonNull public android.os.IBinder getFragmentToken(); + method @NonNull public android.graphics.Point getPositionInParent(); + method public int getRunningActivityCount(); + method @NonNull public android.window.WindowContainerToken getToken(); + method public int getWindowingMode(); + method public boolean hasRunningActivity(); + method public boolean isEmpty(); + method public boolean isTaskClearedForReuse(); + method public boolean isVisible(); + field @NonNull public static final android.os.Parcelable.Creator CREATOR; + } + + public class TaskFragmentOrganizer extends android.window.WindowOrganizer { + ctor public TaskFragmentOrganizer(@NonNull java.util.concurrent.Executor); + method @NonNull public java.util.concurrent.Executor getExecutor(); + method @NonNull public android.window.TaskFragmentOrganizerToken getOrganizerToken(); + method public void onTaskFragmentAppeared(@NonNull android.window.TaskFragmentInfo); + method public void onTaskFragmentError(@NonNull android.os.IBinder, @NonNull Throwable); + method public void onTaskFragmentInfoChanged(@NonNull android.window.TaskFragmentInfo); + method public void onTaskFragmentParentInfoChanged(@NonNull android.os.IBinder, @NonNull android.content.res.Configuration); + method public void onTaskFragmentVanished(@NonNull android.window.TaskFragmentInfo); + method @CallSuper public void registerOrganizer(); + method @CallSuper public void unregisterOrganizer(); + } + + public final class TaskFragmentOrganizerToken implements android.os.Parcelable { + field @NonNull public static final android.os.Parcelable.Creator CREATOR; + } + public class TaskOrganizer extends android.window.WindowOrganizer { ctor public TaskOrganizer(); - method @BinderThread public void addStartingWindow(@NonNull android.window.StartingWindowInfo, @NonNull android.os.IBinder); method @BinderThread public void copySplashScreenView(int); method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public void createRootTask(int, int, @Nullable android.os.IBinder); method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public boolean deleteRootTask(@NonNull android.window.WindowContainerToken); @@ -3209,7 +3267,6 @@ package android.window { method @BinderThread public void onTaskInfoChanged(@NonNull android.app.ActivityManager.RunningTaskInfo); method @BinderThread public void onTaskVanished(@NonNull android.app.ActivityManager.RunningTaskInfo); method @CallSuper @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public java.util.List registerOrganizer(); - method @BinderThread public void removeStartingWindow(int, @Nullable android.view.SurfaceControl, @Nullable android.graphics.Rect, boolean); method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public void setInterceptBackPressedOnTaskRoot(@NonNull android.window.WindowContainerToken, boolean); method @CallSuper @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public void unregisterOrganizer(); } @@ -3222,26 +3279,42 @@ package android.window { public final class WindowContainerTransaction implements android.os.Parcelable { ctor public WindowContainerTransaction(); + method @NonNull public android.window.WindowContainerTransaction createTaskFragment(@NonNull android.window.TaskFragmentCreationParams); + method @NonNull public android.window.WindowContainerTransaction deleteTaskFragment(@NonNull android.window.WindowContainerToken); method public int describeContents(); method @NonNull public android.window.WindowContainerTransaction reorder(@NonNull android.window.WindowContainerToken, boolean); method @NonNull public android.window.WindowContainerTransaction reparent(@NonNull android.window.WindowContainerToken, @Nullable android.window.WindowContainerToken, boolean); + method @NonNull public android.window.WindowContainerTransaction reparentActivityToTaskFragment(@NonNull android.os.IBinder, @NonNull android.os.IBinder); + method @NonNull public android.window.WindowContainerTransaction reparentChildren(@NonNull android.window.WindowContainerToken, @Nullable android.window.WindowContainerToken); method @NonNull public android.window.WindowContainerTransaction reparentTasks(@Nullable android.window.WindowContainerToken, @Nullable android.window.WindowContainerToken, @Nullable int[], @Nullable int[], boolean); method @NonNull public android.window.WindowContainerTransaction scheduleFinishEnterPip(@NonNull android.window.WindowContainerToken, @NonNull android.graphics.Rect); method @NonNull public android.window.WindowContainerTransaction setActivityWindowingMode(@NonNull android.window.WindowContainerToken, int); - method @NonNull public android.window.WindowContainerTransaction setAdjacentRoots(@NonNull android.window.WindowContainerToken, @NonNull android.window.WindowContainerToken); + method @NonNull public android.window.WindowContainerTransaction setAdjacentRoots(@NonNull android.window.WindowContainerToken, @NonNull android.window.WindowContainerToken, boolean); + method @NonNull public android.window.WindowContainerTransaction setAdjacentTaskFragments(@NonNull android.os.IBinder, @Nullable android.os.IBinder, @Nullable android.window.WindowContainerTransaction.TaskFragmentAdjacentParams); method @NonNull public android.window.WindowContainerTransaction setAppBounds(@NonNull android.window.WindowContainerToken, @NonNull android.graphics.Rect); method @NonNull public android.window.WindowContainerTransaction setBounds(@NonNull android.window.WindowContainerToken, @NonNull android.graphics.Rect); method @NonNull public android.window.WindowContainerTransaction setBoundsChangeTransaction(@NonNull android.window.WindowContainerToken, @NonNull android.view.SurfaceControl.Transaction); + method @NonNull public android.window.WindowContainerTransaction setErrorCallbackToken(@NonNull android.os.IBinder); method @NonNull public android.window.WindowContainerTransaction setFocusable(@NonNull android.window.WindowContainerToken, boolean); method @NonNull public android.window.WindowContainerTransaction setHidden(@NonNull android.window.WindowContainerToken, boolean); method @NonNull public android.window.WindowContainerTransaction setLaunchRoot(@NonNull android.window.WindowContainerToken, @Nullable int[], @Nullable int[]); method @NonNull public android.window.WindowContainerTransaction setScreenSizeDp(@NonNull android.window.WindowContainerToken, int, int); method @NonNull public android.window.WindowContainerTransaction setSmallestScreenWidthDp(@NonNull android.window.WindowContainerToken, int); method @NonNull public android.window.WindowContainerTransaction setWindowingMode(@NonNull android.window.WindowContainerToken, int); + method @NonNull public android.window.WindowContainerTransaction startActivityInTaskFragment(@NonNull android.os.IBinder, @NonNull android.os.IBinder, @NonNull android.content.Intent, @Nullable android.os.Bundle); method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator CREATOR; } + public static class WindowContainerTransaction.TaskFragmentAdjacentParams { + ctor public WindowContainerTransaction.TaskFragmentAdjacentParams(); + ctor public WindowContainerTransaction.TaskFragmentAdjacentParams(@NonNull android.os.Bundle); + method public void setShouldDelayPrimaryLastActivityRemoval(boolean); + method public void setShouldDelaySecondaryLastActivityRemoval(boolean); + method public boolean shouldDelayPrimaryLastActivityRemoval(); + method public boolean shouldDelaySecondaryLastActivityRemoval(); + } + public abstract class WindowContainerTransactionCallback { ctor public WindowContainerTransactionCallback(); method public abstract void onTransactionReady(int, @NonNull android.view.SurfaceControl.Transaction); @@ -3249,14 +3322,15 @@ package android.window { public class WindowOrganizer { ctor public WindowOrganizer(); - method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public int applySyncTransaction(@NonNull android.window.WindowContainerTransaction, @NonNull android.window.WindowContainerTransactionCallback); - method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public void applyTransaction(@NonNull android.window.WindowContainerTransaction); + method @RequiresPermission(value=android.Manifest.permission.MANAGE_ACTIVITY_TASKS, conditional=true) public int applySyncTransaction(@NonNull android.window.WindowContainerTransaction, @NonNull android.window.WindowContainerTransactionCallback); + method @RequiresPermission(value=android.Manifest.permission.MANAGE_ACTIVITY_TASKS, conditional=true) public void applyTransaction(@NonNull android.window.WindowContainerTransaction); } @UiContext public abstract class WindowProviderService extends android.app.Service { ctor public WindowProviderService(); method public final void attachToWindowToken(@NonNull android.os.IBinder); - method @Nullable public android.os.Bundle getWindowContextOptions(); + method @NonNull public int getInitialDisplayId(); + method @CallSuper @Nullable public android.os.Bundle getWindowContextOptions(); method public abstract int getWindowType(); } diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java index e91209c1a273..7e382870b016 100644 --- a/core/java/android/accessibilityservice/AccessibilityService.java +++ b/core/java/android/accessibilityservice/AccessibilityService.java @@ -16,6 +16,8 @@ package android.accessibilityservice; +import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY; + import android.accessibilityservice.GestureDescription.MotionEventGenerator; import android.annotation.CallbackExecutor; import android.annotation.ColorInt; @@ -27,6 +29,7 @@ import android.annotation.TestApi; import android.app.Service; import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; +import android.content.ContextWrapper; import android.content.Intent; import android.content.pm.ParceledListSlice; import android.graphics.Bitmap; @@ -36,6 +39,7 @@ import android.graphics.Region; import android.hardware.HardwareBuffer; import android.hardware.display.DisplayManager; import android.os.Build; +import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.Looper; @@ -514,7 +518,9 @@ public abstract class AccessibilityService extends Service { public static final int GLOBAL_ACTION_POWER_DIALOG = 6; /** - * Action to toggle docking the current app's window + * Action to toggle docking the current app's window. + *

+ * Note: It is effective only if it appears in {@link #getSystemActions()}. */ public static final int GLOBAL_ACTION_TOGGLE_SPLIT_SCREEN = 7; @@ -961,30 +967,31 @@ public abstract class AccessibilityService extends Service { } } + @NonNull @Override public Context createDisplayContext(Display display) { - final Context context = super.createDisplayContext(display); - final int displayId = display.getDisplayId(); - setDefaultTokenInternal(context, displayId); - return context; + return new AccessibilityContext(super.createDisplayContext(display), mConnectionId); } - private void setDefaultTokenInternal(Context context, int displayId) { - final WindowManagerImpl wm = (WindowManagerImpl) context.getSystemService(WINDOW_SERVICE); - final IAccessibilityServiceConnection connection = - AccessibilityInteractionClient.getInstance(this).getConnection(mConnectionId); - IBinder token = null; - if (connection != null) { - synchronized (mLock) { - try { - token = connection.getOverlayWindowToken(displayId); - } catch (RemoteException re) { - Log.w(LOG_TAG, "Failed to get window token", re); - re.rethrowFromSystemServer(); - } - } - wm.setDefaultToken(token); + @NonNull + @Override + public Context createWindowContext(int type, @Nullable Bundle options) { + final Context context = super.createWindowContext(type, options); + if (type != TYPE_ACCESSIBILITY_OVERLAY) { + return context; } + return new AccessibilityContext(context, mConnectionId); + } + + @NonNull + @Override + public Context createWindowContext(@NonNull Display display, int type, + @Nullable Bundle options) { + final Context context = super.createWindowContext(display, type, options); + if (type != TYPE_ACCESSIBILITY_OVERLAY) { + return context; + } + return new AccessibilityContext(context, mConnectionId); } /** @@ -2069,6 +2076,10 @@ public abstract class AccessibilityService extends Service { if (WINDOW_SERVICE.equals(name)) { if (mWindowManager == null) { mWindowManager = (WindowManager) getBaseContext().getSystemService(name); + final WindowManagerImpl wm = (WindowManagerImpl) mWindowManager; + // Set e default token obtained from the connection to ensure client could use + // accessibility overlay. + wm.setDefaultToken(mWindowToken); } return mWindowManager; } @@ -2177,8 +2188,10 @@ public abstract class AccessibilityService extends Service { // The client may have already obtained the window manager, so // update the default token on whatever manager we gave them. - final WindowManagerImpl wm = (WindowManagerImpl) getSystemService(WINDOW_SERVICE); - wm.setDefaultToken(windowToken); + if (mWindowManager != null) { + final WindowManagerImpl wm = (WindowManagerImpl) mWindowManager; + wm.setDefaultToken(mWindowToken); + } } @Override @@ -2675,4 +2688,58 @@ public abstract class AccessibilityService extends Service { } } } + + private static class AccessibilityContext extends ContextWrapper { + private final int mConnectionId; + + private AccessibilityContext(Context base, int connectionId) { + super(base); + mConnectionId = connectionId; + setDefaultTokenInternal(this, getDisplayId()); + } + + @NonNull + @Override + public Context createDisplayContext(Display display) { + return new AccessibilityContext(super.createDisplayContext(display), mConnectionId); + } + + @NonNull + @Override + public Context createWindowContext(int type, @Nullable Bundle options) { + final Context context = super.createWindowContext(type, options); + if (type != TYPE_ACCESSIBILITY_OVERLAY) { + return context; + } + return new AccessibilityContext(context, mConnectionId); + } + + @NonNull + @Override + public Context createWindowContext(@NonNull Display display, int type, + @Nullable Bundle options) { + final Context context = super.createWindowContext(display, type, options); + if (type != TYPE_ACCESSIBILITY_OVERLAY) { + return context; + } + return new AccessibilityContext(context, mConnectionId); + } + + private void setDefaultTokenInternal(Context context, int displayId) { + final WindowManagerImpl wm = (WindowManagerImpl) context.getSystemService( + WINDOW_SERVICE); + final IAccessibilityServiceConnection connection = + AccessibilityInteractionClient.getConnection(mConnectionId); + IBinder token = null; + if (connection != null) { + try { + token = connection.getOverlayWindowToken(displayId); + } catch (RemoteException re) { + Log.w(LOG_TAG, "Failed to get window token", re); + re.rethrowFromSystemServer(); + } + wm.setDefaultToken(token); + } + } + } } diff --git a/core/java/android/accessibilityservice/AccessibilityTrace.java b/core/java/android/accessibilityservice/AccessibilityTrace.java new file mode 100644 index 000000000000..f28015ab4685 --- /dev/null +++ b/core/java/android/accessibilityservice/AccessibilityTrace.java @@ -0,0 +1,216 @@ +/** + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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.accessibilityservice; + +import java.util.AbstractMap; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * Interface to log accessibility trace. + * + * @hide + */ +public interface AccessibilityTrace { + String NAME_ACCESSIBILITY_SERVICE_CONNECTION = "IAccessibilityServiceConnection"; + String NAME_ACCESSIBILITY_SERVICE_CLIENT = "IAccessibilityServiceClient"; + String NAME_ACCESSIBILITY_MANAGER = "IAccessibilityManager"; + String NAME_ACCESSIBILITY_MANAGER_CLIENT = "IAccessibilityManagerClient"; + String NAME_ACCESSIBILITY_INTERACTION_CONNECTION = "IAccessibilityInteractionConnection"; + String NAME_ACCESSIBILITY_INTERACTION_CONNECTION_CALLBACK = + "IAccessibilityInteractionConnectionCallback"; + String NAME_REMOTE_MAGNIFICATION_ANIMATION_CALLBACK = "IRemoteMagnificationAnimationCallback"; + String NAME_WINDOW_MAGNIFICATION_CONNECTION = "IWindowMagnificationConnection"; + String NAME_WINDOW_MAGNIFICATION_CONNECTION_CALLBACK = "IWindowMagnificationConnectionCallback"; + String NAME_WINDOW_MANAGER_INTERNAL = "WindowManagerInternal"; + String NAME_WINDOWS_FOR_ACCESSIBILITY_CALLBACK = "WindowsForAccessibilityCallback"; + String NAME_MAGNIFICATION_CALLBACK = "MagnificationCallbacks"; + String NAME_INPUT_FILTER = "InputFilter"; + String NAME_GESTURE = "Gesture"; + String NAME_ACCESSIBILITY_SERVICE = "AccessibilityService"; + String NAME_PACKAGE_BROADCAST_RECEIVER = "PMBroadcastReceiver"; + String NAME_USER_BROADCAST_RECEIVER = "UserBroadcastReceiver"; + String NAME_FINGERPRINT = "FingerprintGesture"; + String NAME_ACCESSIBILITY_INTERACTION_CLIENT = "AccessibilityInteractionClient"; + + String NAME_ALL_LOGGINGS = "AllLoggings"; + String NAME_NONE = "None"; + + long FLAGS_ACCESSIBILITY_SERVICE_CONNECTION = 0x0000000000000001L; + long FLAGS_ACCESSIBILITY_SERVICE_CLIENT = 0x0000000000000002L; + long FLAGS_ACCESSIBILITY_MANAGER = 0x0000000000000004L; + long FLAGS_ACCESSIBILITY_MANAGER_CLIENT = 0x0000000000000008L; + long FLAGS_ACCESSIBILITY_INTERACTION_CONNECTION = 0x0000000000000010L; + long FLAGS_ACCESSIBILITY_INTERACTION_CONNECTION_CALLBACK = 0x0000000000000020L; + long FLAGS_REMOTE_MAGNIFICATION_ANIMATION_CALLBACK = 0x0000000000000040L; + long FLAGS_WINDOW_MAGNIFICATION_CONNECTION = 0x0000000000000080L; + long FLAGS_WINDOW_MAGNIFICATION_CONNECTION_CALLBACK = 0x0000000000000100L; + long FLAGS_WINDOW_MANAGER_INTERNAL = 0x0000000000000200L; + long FLAGS_WINDOWS_FOR_ACCESSIBILITY_CALLBACK = 0x0000000000000400L; + long FLAGS_MAGNIFICATION_CALLBACK = 0x0000000000000800L; + long FLAGS_INPUT_FILTER = 0x0000000000001000L; + long FLAGS_GESTURE = 0x0000000000002000L; + long FLAGS_ACCESSIBILITY_SERVICE = 0x0000000000004000L; + long FLAGS_PACKAGE_BROADCAST_RECEIVER = 0x0000000000008000L; + long FLAGS_USER_BROADCAST_RECEIVER = 0x0000000000010000L; + long FLAGS_FINGERPRINT = 0x0000000000020000L; + long FLAGS_ACCESSIBILITY_INTERACTION_CLIENT = 0x0000000000040000L; + + long FLAGS_LOGGING_NONE = 0x0000000000000000L; + long FLAGS_LOGGING_ALL = 0xFFFFFFFFFFFFFFFFL; + + long FLAGS_ACCESSIBILITY_MANAGER_CLIENT_STATES = FLAGS_ACCESSIBILITY_INTERACTION_CLIENT + | FLAGS_ACCESSIBILITY_SERVICE + | FLAGS_ACCESSIBILITY_INTERACTION_CONNECTION + | FLAGS_ACCESSIBILITY_INTERACTION_CONNECTION_CALLBACK; + + Map sNamesToFlags = Map.ofEntries( + new AbstractMap.SimpleEntry( + NAME_ACCESSIBILITY_SERVICE_CONNECTION, FLAGS_ACCESSIBILITY_SERVICE_CONNECTION), + new AbstractMap.SimpleEntry( + NAME_ACCESSIBILITY_SERVICE_CLIENT, FLAGS_ACCESSIBILITY_SERVICE_CLIENT), + new AbstractMap.SimpleEntry( + NAME_ACCESSIBILITY_MANAGER, FLAGS_ACCESSIBILITY_MANAGER), + new AbstractMap.SimpleEntry( + NAME_ACCESSIBILITY_MANAGER_CLIENT, FLAGS_ACCESSIBILITY_MANAGER_CLIENT), + new AbstractMap.SimpleEntry( + NAME_ACCESSIBILITY_INTERACTION_CONNECTION, + FLAGS_ACCESSIBILITY_INTERACTION_CONNECTION), + new AbstractMap.SimpleEntry( + NAME_ACCESSIBILITY_INTERACTION_CONNECTION_CALLBACK, + FLAGS_ACCESSIBILITY_INTERACTION_CONNECTION_CALLBACK), + new AbstractMap.SimpleEntry( + NAME_REMOTE_MAGNIFICATION_ANIMATION_CALLBACK, + FLAGS_REMOTE_MAGNIFICATION_ANIMATION_CALLBACK), + new AbstractMap.SimpleEntry( + NAME_WINDOW_MAGNIFICATION_CONNECTION, FLAGS_WINDOW_MAGNIFICATION_CONNECTION), + new AbstractMap.SimpleEntry( + NAME_WINDOW_MAGNIFICATION_CONNECTION_CALLBACK, + FLAGS_WINDOW_MAGNIFICATION_CONNECTION_CALLBACK), + new AbstractMap.SimpleEntry( + NAME_WINDOW_MANAGER_INTERNAL, FLAGS_WINDOW_MANAGER_INTERNAL), + new AbstractMap.SimpleEntry( + NAME_WINDOWS_FOR_ACCESSIBILITY_CALLBACK, + FLAGS_WINDOWS_FOR_ACCESSIBILITY_CALLBACK), + new AbstractMap.SimpleEntry( + NAME_MAGNIFICATION_CALLBACK, FLAGS_MAGNIFICATION_CALLBACK), + new AbstractMap.SimpleEntry(NAME_INPUT_FILTER, FLAGS_INPUT_FILTER), + new AbstractMap.SimpleEntry(NAME_GESTURE, FLAGS_GESTURE), + new AbstractMap.SimpleEntry( + NAME_ACCESSIBILITY_SERVICE, FLAGS_ACCESSIBILITY_SERVICE), + new AbstractMap.SimpleEntry( + NAME_PACKAGE_BROADCAST_RECEIVER, FLAGS_PACKAGE_BROADCAST_RECEIVER), + new AbstractMap.SimpleEntry( + NAME_USER_BROADCAST_RECEIVER, FLAGS_USER_BROADCAST_RECEIVER), + new AbstractMap.SimpleEntry(NAME_FINGERPRINT, FLAGS_FINGERPRINT), + new AbstractMap.SimpleEntry( + NAME_ACCESSIBILITY_INTERACTION_CLIENT, FLAGS_ACCESSIBILITY_INTERACTION_CLIENT), + new AbstractMap.SimpleEntry(NAME_NONE, FLAGS_LOGGING_NONE), + new AbstractMap.SimpleEntry(NAME_ALL_LOGGINGS, FLAGS_LOGGING_ALL)); + + /** + * Get the flags of the logging types by the given names. + * The names list contains logging type names in lower case. + */ + static long getLoggingFlagsFromNames(List names) { + long types = FLAGS_LOGGING_NONE; + for (String name : names) { + long flag = sNamesToFlags.get(name); + types |= flag; + } + return types; + } + + /** + * Get the list of the names of logging types by the given flags. + */ + static List getNamesOfLoggingTypes(long flags) { + List list = new ArrayList(); + + for (Map.Entry entry : sNamesToFlags.entrySet()) { + if ((entry.getValue() & flags) != FLAGS_LOGGING_NONE) { + list.add(entry.getKey()); + } + } + + return list; + } + + /** + * Whether the trace is enabled for any logging type. + */ + boolean isA11yTracingEnabled(); + + /** + * Whether the trace is enabled for any of the given logging type. + */ + boolean isA11yTracingEnabledForTypes(long typeIdFlags); + + /** + * Get trace state to be sent to AccessibilityManager. + */ + int getTraceStateForAccessibilityManagerClientState(); + + /** + * Start tracing for the given logging types. + */ + void startTrace(long flagss); + + /** + * Stop tracing. + */ + void stopTrace(); + + /** + * Log one trace entry. + * @param where A string to identify this log entry, which can be used to search through the + * tracing file. + * @param loggingFlags Flags to identify which logging types this entry belongs to. This + * can be used to filter the log entries when generating tracing file. + */ + void logTrace(String where, long loggingFlags); + + /** + * Log one trace entry. + * @param where A string to identify this log entry, which can be used to filter/search + * through the tracing file. + * @param loggingFlags Flags to identify which logging types this entry belongs to. This + * can be used to filter the log entries when generating tracing file. + * @param callingParams The parameters for the method to be logged. + */ + void logTrace(String where, long loggingFlags, String callingParams); + + /** + * Log one trace entry. Accessibility services using AccessibilityInteractionClient to + * make screen content related requests use this API to log entry when receive callback. + * @param timestamp The timestamp when a callback is received. + * @param where A string to identify this log entry, which can be used to filter/search + * through the tracing file. + * @param loggingFlags Flags to identify which logging types this entry belongs to. This + * can be used to filter the log entries when generating tracing file. + * @param callingParams The parameters for the callback. + * @param processId The process id of the calling component. + * @param threadId The threadId of the calling component. + * @param callingUid The calling uid of the callback. + * @param callStack The call stack of the callback. + * @param ignoreStackElements ignore these call stack element + */ + void logTrace(long timestamp, String where, long loggingFlags, String callingParams, + int processId, long threadId, int callingUid, StackTraceElement[] callStack, + Set ignoreStackElements); +} diff --git a/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl b/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl index 923b6f41414a..1e76bbf43370 100644 --- a/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl +++ b/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl @@ -118,6 +118,6 @@ interface IAccessibilityServiceConnection { void setFocusAppearance(int strokeWidth, int color); - oneway void logTrace(long timestamp, String where, String callingParams, int processId, - long threadId, int callingUid, in Bundle serializedCallingStackInBundle); + oneway void logTrace(long timestamp, String where, long loggingTypes, String callingParams, + int processId, long threadId, int callingUid, in Bundle serializedCallingStackInBundle); } diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index af59ea1d22ff..f453ba16043c 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -140,7 +140,6 @@ import android.widget.AdapterView; import android.widget.Toast; import android.widget.Toolbar; import android.window.SplashScreen; -import android.window.SplashScreenView; import com.android.internal.R; import com.android.internal.annotations.GuardedBy; @@ -969,7 +968,6 @@ public class Activity extends ContextThemeWrapper private UiTranslationController mUiTranslationController; private SplashScreen mSplashScreen; - private SplashScreenView mSplashScreenView; private final WindowControllerCallback mWindowControllerCallback = new WindowControllerCallback() { @@ -1538,6 +1536,17 @@ public class Activity extends ContextThemeWrapper getApplication().dispatchActivityPostDestroyed(this); } + private void dispatchActivityConfigurationChanged() { + getApplication().dispatchActivityConfigurationChanged(this); + Object[] callbacks = collectActivityLifecycleCallbacks(); + if (callbacks != null) { + for (int i = 0; i < callbacks.length; i++) { + ((Application.ActivityLifecycleCallbacks) callbacks[i]) + .onActivityConfigurationChanged(this); + } + } + } + private Object[] collectActivityLifecycleCallbacks() { Object[] callbacks = null; synchronized (mActivityLifecycleCallbacks) { @@ -1629,16 +1638,6 @@ public class Activity extends ContextThemeWrapper } } - /** @hide */ - public void setSplashScreenView(SplashScreenView v) { - mSplashScreenView = v; - } - - /** @hide */ - SplashScreenView getSplashScreenView() { - return mSplashScreenView; - } - /** * Same as {@link #onCreate(android.os.Bundle)} but called for those activities created with * the attribute {@link android.R.attr#persistableMode} set to @@ -1922,10 +1921,14 @@ public class Activity extends ContextThemeWrapper } /** - * Called after {@link #onRestoreInstanceState}, {@link #onRestart}, or - * {@link #onPause}, for your activity to start interacting with the user. This is an indicator - * that the activity became active and ready to receive input. It is on top of an activity stack - * and visible to user. + * Called after {@link #onRestoreInstanceState}, {@link #onRestart}, or {@link #onPause}. This + * is usually a hint for your activity to start interacting with the user, which is a good + * indicator that the activity became active and ready to receive input. This sometimes could + * also be a transit state toward another resting state. For instance, an activity may be + * relaunched to {@link #onPause} due to configuration changes and the activity was visible, + * but wasn’t the top-most activity of an activity task. {@link #onResume} is guaranteed to be + * called before {@link #onPause} in this case which honors the activity lifecycle policy and + * the activity eventually rests in {@link #onPause}. * *

On platform versions prior to {@link android.os.Build.VERSION_CODES#Q} this is also a good * place to try to open exclusive-access devices or to get access to singleton resources. @@ -2491,12 +2494,11 @@ public class Activity extends ContextThemeWrapper * *

To get the voice interactor you need to call {@link #getVoiceInteractor()} * which would return non null only if there is an ongoing voice - * interaction session. You an also detect when the voice interactor is no + * interaction session. You can also detect when the voice interactor is no * longer valid because the voice interaction session that is backing is finished * by calling {@link VoiceInteractor#registerOnDestroyedCallback(Executor, Runnable)}. * - *

This method will be called only after {@link #onStart()} is being called and - * before {@link #onStop()} is being called. + *

This method will be called only after {@link #onStart()} and before {@link #onStop()}. * *

You should pass to the callback the currently supported direct actions which * cannot be null or contain null elements. @@ -3027,6 +3029,8 @@ public class Activity extends ContextThemeWrapper // view changes from above. mActionBar.onConfigurationChanged(newConfig); } + + dispatchActivityConfigurationChanged(); } /** diff --git a/core/java/android/app/ActivityClient.java b/core/java/android/app/ActivityClient.java index bd4386885dd6..db7ab1a6f379 100644 --- a/core/java/android/app/ActivityClient.java +++ b/core/java/android/app/ActivityClient.java @@ -16,6 +16,7 @@ package android.app; +import android.annotation.Nullable; import android.content.ComponentName; import android.content.Intent; import android.content.res.Configuration; @@ -205,6 +206,19 @@ public class ActivityClient { } } + /** + * Returns the non-finishing activity token below in the same task if it belongs to the same + * process. + */ + @Nullable + public IBinder getActivityTokenBelow(IBinder activityToken) { + try { + return getActivityClientController().getActivityTokenBelow(activityToken); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + ComponentName getCallingActivity(IBinder token) { try { return getActivityClientController().getCallingActivity(token); diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index f53c5b6c9748..db45466d98d2 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -4075,6 +4075,85 @@ public class ActivityManager { return switchUser(user.getIdentifier()); } + /** + * Gets the message that is shown when a user is switched from. + * + * @hide + */ + @RequiresPermission(Manifest.permission.MANAGE_USERS) + public @Nullable String getSwitchingFromUserMessage() { + try { + return getService().getSwitchingFromUserMessage(); + } catch (RemoteException re) { + throw re.rethrowFromSystemServer(); + } + } + + /** + * Gets the message that is shown when a user is switched to. + * + * @hide + */ + @RequiresPermission(Manifest.permission.MANAGE_USERS) + public @Nullable String getSwitchingToUserMessage() { + try { + return getService().getSwitchingToUserMessage(); + } catch (RemoteException re) { + throw re.rethrowFromSystemServer(); + } + } + + /** + * Uses the value defined by the platform. + * + * @hide + */ + @TestApi + public static final int STOP_USER_ON_SWITCH_DEFAULT = -1; + + /** + * Overrides value defined by the platform and stop user on switch. + * + * @hide + */ + @TestApi + public static final int STOP_USER_ON_SWITCH_TRUE = 1; + + /** + * Overrides value defined by the platform and don't stop user on switch. + * + * @hide + */ + @TestApi + public static final int STOP_USER_ON_SWITCH_FALSE = 0; + + /** @hide */ + @IntDef(prefix = { "STOP_USER_ON_SWITCH_" }, value = { + STOP_USER_ON_SWITCH_DEFAULT, + STOP_USER_ON_SWITCH_TRUE, + STOP_USER_ON_SWITCH_FALSE + }) + public @interface StopUserOnSwitch {} + + /** + * Sets whether the current foreground user (and its profiles) should be stopped after switched + * out. + * + *

Should only be used on tests. Doesn't apply to {@link UserHandle#SYSTEM system user}. + * + * @hide + */ + @TestApi + @RequiresPermission(anyOf = {android.Manifest.permission.MANAGE_USERS, + android.Manifest.permission.INTERACT_ACROSS_USERS}) + public void setStopUserOnSwitch(@StopUserOnSwitch int value) { + try { + getService().setStopUserOnSwitch(value); + } catch (RemoteException re) { + throw re.rethrowFromSystemServer(); + } + } + /** * Starts a profile. * To be used with non-managed profiles, managed profiles should use diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java index 98ffb197f311..4aa219f5c472 100644 --- a/core/java/android/app/ActivityManagerInternal.java +++ b/core/java/android/app/ActivityManagerInternal.java @@ -16,6 +16,8 @@ package android.app; +import static android.app.ActivityManager.StopUserOnSwitch; + import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UserIdInt; @@ -650,4 +652,34 @@ public abstract class ActivityManagerInternal { */ @Nullable public abstract List getIsolatedProcesses(int uid); + + /** @see ActivityManagerService#sendIntentSender */ + public abstract int sendIntentSender(IIntentSender target, IBinder allowlistToken, int code, + Intent intent, String resolvedType, + IIntentReceiver finishedReceiver, String requiredPermission, Bundle options); + + /** + * Sets the provider to communicate between voice interaction manager service and + * ActivityManagerService. + */ + public abstract void setVoiceInteractionManagerProvider( + @Nullable VoiceInteractionManagerProvider provider); + + /** + * Sets whether the current foreground user (and its profiles) should be stopped after switched + * out. + */ + public abstract void setStopUserOnSwitch(@StopUserOnSwitch int value); + + /** + * Provides the interface to communicate between voice interaction manager service and + * ActivityManagerService. + */ + public interface VoiceInteractionManagerProvider { + /** + * Notifies the service when a high-level activity event has been changed, for example, + * an activity was resumed or stopped. + */ + void notifyActivityEventChanged(); + } } diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java index 8e1f263ebf03..0ff9f6655b8a 100644 --- a/core/java/android/app/ActivityOptions.java +++ b/core/java/android/app/ActivityOptions.java @@ -26,6 +26,7 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; +import android.annotation.SystemApi; import android.annotation.TestApi; import android.app.ExitTransitionCoordinator.ActivityExitTransitionCallbacks; import android.app.ExitTransitionCoordinator.ExitTransitionCallbacks; @@ -55,7 +56,7 @@ import android.view.RemoteAnimationAdapter; import android.view.View; import android.view.ViewGroup; import android.view.Window; -import android.window.IRemoteTransition; +import android.window.RemoteTransition; import android.window.SplashScreen; import android.window.WindowContainerToken; @@ -214,6 +215,14 @@ public class ActivityOptions { public static final String KEY_LAUNCH_ROOT_TASK_TOKEN = "android.activity.launchRootTaskToken"; + /** + * The {@link com.android.server.wm.TaskFragment} token the activity should be launched into. + * @see #setLaunchTaskFragmentToken(IBinder) + * @hide + */ + public static final String KEY_LAUNCH_TASK_FRAGMENT_TOKEN = + "android.activity.launchTaskFragmentToken"; + /** * The windowing mode the activity should be launched into. * @hide @@ -396,6 +405,7 @@ public class ActivityOptions { private int mCallerDisplayId = INVALID_DISPLAY; private WindowContainerToken mLaunchTaskDisplayArea; private WindowContainerToken mLaunchRootTask; + private IBinder mLaunchTaskFragmentToken; @WindowConfiguration.WindowingMode private int mLaunchWindowingMode = WINDOWING_MODE_UNDEFINED; @WindowConfiguration.ActivityType @@ -417,11 +427,11 @@ public class ActivityOptions { private IAppTransitionAnimationSpecsFuture mSpecsFuture; private RemoteAnimationAdapter mRemoteAnimationAdapter; private IBinder mLaunchCookie; - private IRemoteTransition mRemoteTransition; + private RemoteTransition mRemoteTransition; private boolean mOverrideTaskTransition; private String mSplashScreenThemeResName; @SplashScreen.SplashScreenStyle - private int mSplashScreenStyle; + private int mSplashScreenStyle = SplashScreen.SPLASH_SCREEN_STYLE_UNDEFINED; private boolean mRemoveWithTaskOrganizer; private boolean mLaunchedFromBubble; private boolean mTransientLaunch; @@ -1045,7 +1055,7 @@ public class ActivityOptions { */ @RequiresPermission(CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS) public static ActivityOptions makeRemoteAnimation(RemoteAnimationAdapter remoteAnimationAdapter, - IRemoteTransition remoteTransition) { + RemoteTransition remoteTransition) { final ActivityOptions opts = new ActivityOptions(); opts.mRemoteAnimationAdapter = remoteAnimationAdapter; opts.mAnimationType = ANIM_REMOTE_ANIMATION; @@ -1055,11 +1065,11 @@ public class ActivityOptions { /** * Create an {@link ActivityOptions} instance that lets the application control the entire - * transition using a {@link IRemoteTransition}. + * transition using a {@link RemoteTransition}. * @hide */ @RequiresPermission(CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS) - public static ActivityOptions makeRemoteTransition(IRemoteTransition remoteTransition) { + public static ActivityOptions makeRemoteTransition(RemoteTransition remoteTransition) { final ActivityOptions opts = new ActivityOptions(); opts.mRemoteTransition = remoteTransition; return opts; @@ -1138,6 +1148,7 @@ public class ActivityOptions { mCallerDisplayId = opts.getInt(KEY_CALLER_DISPLAY_ID, INVALID_DISPLAY); mLaunchTaskDisplayArea = opts.getParcelable(KEY_LAUNCH_TASK_DISPLAY_AREA_TOKEN); mLaunchRootTask = opts.getParcelable(KEY_LAUNCH_ROOT_TASK_TOKEN); + mLaunchTaskFragmentToken = opts.getBinder(KEY_LAUNCH_TASK_FRAGMENT_TOKEN); mLaunchWindowingMode = opts.getInt(KEY_LAUNCH_WINDOWING_MODE, WINDOWING_MODE_UNDEFINED); mLaunchActivityType = opts.getInt(KEY_LAUNCH_ACTIVITY_TYPE, ACTIVITY_TYPE_UNDEFINED); mLaunchTaskId = opts.getInt(KEY_LAUNCH_TASK_ID, -1); @@ -1171,8 +1182,7 @@ public class ActivityOptions { } mRemoteAnimationAdapter = opts.getParcelable(KEY_REMOTE_ANIMATION_ADAPTER); mLaunchCookie = opts.getBinder(KEY_LAUNCH_COOKIE); - mRemoteTransition = IRemoteTransition.Stub.asInterface(opts.getBinder( - KEY_REMOTE_TRANSITION)); + mRemoteTransition = opts.getParcelable(KEY_REMOTE_TRANSITION); mOverrideTaskTransition = opts.getBoolean(KEY_OVERRIDE_TASK_TRANSITION); mSplashScreenThemeResName = opts.getString(KEY_SPLASH_SCREEN_THEME); mRemoveWithTaskOrganizer = opts.getBoolean(KEY_REMOVE_WITH_TASK_ORGANIZER); @@ -1338,7 +1348,7 @@ public class ActivityOptions { } /** @hide */ - public IRemoteTransition getRemoteTransition() { + public RemoteTransition getRemoteTransition() { return mRemoteTransition; } @@ -1472,6 +1482,17 @@ public class ActivityOptions { return this; } + /** @hide */ + public IBinder getLaunchTaskFragmentToken() { + return mLaunchTaskFragmentToken; + } + + /** @hide */ + public ActivityOptions setLaunchTaskFragmentToken(IBinder taskFragmentToken) { + mLaunchTaskFragmentToken = taskFragmentToken; + return this; + } + /** @hide */ public int getLaunchWindowingMode() { return mLaunchWindowingMode; @@ -1501,7 +1522,8 @@ public class ActivityOptions { * Sets the task the activity will be launched in. * @hide */ - @TestApi + @RequiresPermission(START_TASKS_FROM_RECENTS) + @SystemApi public void setLaunchTaskId(int taskId) { mLaunchTaskId = taskId; } @@ -1509,6 +1531,7 @@ public class ActivityOptions { /** * @hide */ + @SystemApi public int getLaunchTaskId() { return mLaunchTaskId; } @@ -1882,6 +1905,9 @@ public class ActivityOptions { if (mLaunchRootTask != null) { b.putParcelable(KEY_LAUNCH_ROOT_TASK_TOKEN, mLaunchRootTask); } + if (mLaunchTaskFragmentToken != null) { + b.putBinder(KEY_LAUNCH_TASK_FRAGMENT_TOKEN, mLaunchTaskFragmentToken); + } if (mLaunchWindowingMode != WINDOWING_MODE_UNDEFINED) { b.putInt(KEY_LAUNCH_WINDOWING_MODE, mLaunchWindowingMode); } @@ -1941,7 +1967,7 @@ public class ActivityOptions { b.putBinder(KEY_LAUNCH_COOKIE, mLaunchCookie); } if (mRemoteTransition != null) { - b.putBinder(KEY_REMOTE_TRANSITION, mRemoteTransition.asBinder()); + b.putParcelable(KEY_REMOTE_TRANSITION, mRemoteTransition); } if (mOverrideTaskTransition) { b.putBoolean(KEY_OVERRIDE_TASK_TRANSITION, mOverrideTaskTransition); diff --git a/core/java/android/app/ActivityTaskManager.java b/core/java/android/app/ActivityTaskManager.java index 4a7fcd232ce9..a83662592513 100644 --- a/core/java/android/app/ActivityTaskManager.java +++ b/core/java/android/app/ActivityTaskManager.java @@ -475,6 +475,19 @@ public class ActivityTaskManager { } } + /** + * Detaches the navigation bar from the app it was attached to during a transition. + * @hide + */ + @RequiresPermission(android.Manifest.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS) + public void detachNavigationBarFromApp(@NonNull IBinder transition) { + try { + getService().detachNavigationBarFromApp(transition); + } 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 5c942d217fc4..d255870ecc5c 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -18,7 +18,6 @@ package android.app; import static android.app.ActivityManager.PROCESS_STATE_UNKNOWN; import static android.app.ConfigurationController.createNewConfigAndUpdateIfNotNull; -import static android.app.ConfigurationController.freeTextLayoutCachesIfNeeded; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static android.app.servertransaction.ActivityLifecycleItem.ON_CREATE; @@ -32,11 +31,21 @@ import static android.content.ContentResolver.DEPRECATE_DATA_COLUMNS; import static android.content.ContentResolver.DEPRECATE_DATA_PREFIX; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.Display.INVALID_DISPLAY; +import static android.window.ConfigurationHelper.diffPublicWithSizeBuckets; +import static android.window.ConfigurationHelper.freeTextLayoutCachesIfNeeded; +import static android.window.ConfigurationHelper.isDifferentDisplay; +import static android.window.ConfigurationHelper.shouldUpdateResources; import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE; import android.annotation.NonNull; import android.annotation.Nullable; +import android.app.RemoteServiceException.BadForegroundServiceNotificationException; +import android.app.RemoteServiceException.CannotDeliverBroadcastException; +import android.app.RemoteServiceException.CannotPostForegroundServiceNotificationException; +import android.app.RemoteServiceException.CrashedByAdbException; +import android.app.RemoteServiceException.ForegroundServiceDidNotStartInTimeException; +import android.app.RemoteServiceException.MissingRequestPasswordComplexityPermissionException; import android.app.assist.AssistContent; import android.app.assist.AssistStructure; import android.app.backup.BackupAgent; @@ -89,10 +98,8 @@ import android.database.sqlite.SQLiteDebug.DbStats; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.HardwareRenderer; -import android.graphics.Rect; import android.graphics.Typeface; import android.hardware.display.DisplayManagerGlobal; -import android.inputmethodservice.InputMethodService; import android.media.MediaFrameworkInitializer; import android.media.MediaFrameworkPlatformInitializer; import android.media.MediaServiceManager; @@ -167,6 +174,7 @@ import android.view.Choreographer; import android.view.Display; import android.view.DisplayAdjustments; import android.view.DisplayAdjustments.FixedRotationAdjustments; +import android.view.SurfaceControl; import android.view.ThreadedRenderer; import android.view.View; import android.view.ViewDebug; @@ -185,6 +193,7 @@ import android.webkit.WebView; import android.window.SizeConfigurationBuckets; import android.window.SplashScreen; import android.window.SplashScreenView; +import android.window.WindowProviderService; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; @@ -235,7 +244,6 @@ import java.util.Map; import java.util.Objects; import java.util.TimeZone; import java.util.concurrent.Executor; -import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Consumer; /** @@ -314,7 +322,8 @@ public final class ActivityThread extends ClientTransactionHandler @UnsupportedAppUsage private ContextImpl mSystemContext; - private final SparseArray mDisplaySystemUiContexts = new SparseArray<>(); + @GuardedBy("this") + private SparseArray mDisplaySystemUiContexts; @UnsupportedAppUsage static volatile IPackageManager sPackageManager; @@ -1287,8 +1296,11 @@ public final class ActivityThread extends ClientTransactionHandler } @Override - public void scheduleCrash(String msg, int typeId) { - sendMessage(H.SCHEDULE_CRASH, msg, typeId); + public void scheduleCrash(String msg, int typeId, @Nullable Bundle extras) { + SomeArgs args = SomeArgs.obtain(); + args.arg1 = msg; + args.arg2 = extras; + sendMessage(H.SCHEDULE_CRASH, args, typeId); } public void dumpActivity(ParcelFileDescriptor pfd, IBinder activitytoken, @@ -1918,17 +1930,42 @@ public final class ActivityThread extends ClientTransactionHandler } } - private void throwRemoteServiceException(String message, int typeId) { + private void throwRemoteServiceException(String message, int typeId, @Nullable Bundle extras) { // Use a switch to ensure all the type IDs are unique. switch (typeId) { - case ForegroundServiceDidNotStartInTimeException.TYPE_ID: // 1 - throw new ForegroundServiceDidNotStartInTimeException(message); - case RemoteServiceException.TYPE_ID: // 0 + case ForegroundServiceDidNotStartInTimeException.TYPE_ID: + throw generateForegroundServiceDidNotStartInTimeException(message, extras); + + case CannotDeliverBroadcastException.TYPE_ID: + throw new CannotDeliverBroadcastException(message); + + case CannotPostForegroundServiceNotificationException.TYPE_ID: + throw new CannotPostForegroundServiceNotificationException(message); + + case BadForegroundServiceNotificationException.TYPE_ID: + throw new BadForegroundServiceNotificationException(message); + + case MissingRequestPasswordComplexityPermissionException.TYPE_ID: + throw new MissingRequestPasswordComplexityPermissionException(message); + + case CrashedByAdbException.TYPE_ID: + throw new CrashedByAdbException(message); + default: - throw new RemoteServiceException(message); + throw new RemoteServiceException(message + + " (with unwknown typeId:" + typeId + ")"); } } + private ForegroundServiceDidNotStartInTimeException + generateForegroundServiceDidNotStartInTimeException(String message, Bundle extras) { + final String serviceClassName = + ForegroundServiceDidNotStartInTimeException.getServiceClassNameFromExtras(extras); + final Exception inner = (serviceClassName == null) ? null + : Service.getStartForegroundServiceStackTrace(serviceClassName); + throw new ForegroundServiceDidNotStartInTimeException(message, inner); + } + class H extends Handler { public static final int BIND_APPLICATION = 110; @UnsupportedAppUsage @@ -2146,9 +2183,14 @@ public final class ActivityThread extends ClientTransactionHandler handleDispatchPackageBroadcast(msg.arg1, (String[])msg.obj); Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); break; - case SCHEDULE_CRASH: - throwRemoteServiceException((String) msg.obj, msg.arg1); + case SCHEDULE_CRASH: { + SomeArgs args = (SomeArgs) msg.obj; + String message = (String) args.arg1; + Bundle extras = (Bundle) args.arg2; + args.recycle(); + throwRemoteServiceException(message, msg.arg1, extras); break; + } case DUMP_HEAP: handleDumpHeap((DumpHeapData) msg.obj); break; @@ -2610,7 +2652,6 @@ public final class ActivityThread extends ClientTransactionHandler } } - @Override @NonNull public ContextImpl getSystemUiContext() { return getSystemUiContext(DEFAULT_DISPLAY); @@ -2624,6 +2665,9 @@ public final class ActivityThread extends ClientTransactionHandler @NonNull public ContextImpl getSystemUiContext(int displayId) { synchronized (this) { + if (mDisplaySystemUiContexts == null) { + mDisplaySystemUiContexts = new SparseArray<>(); + } ContextImpl systemUiContext = mDisplaySystemUiContexts.get(displayId); if (systemUiContext == null) { systemUiContext = ContextImpl.createSystemUiContext(getSystemContext(), displayId); @@ -2633,6 +2677,25 @@ public final class ActivityThread extends ClientTransactionHandler } } + @Nullable + @Override + public ContextImpl getSystemUiContextNoCreate() { + synchronized (this) { + if (mDisplaySystemUiContexts == null) return null; + return mDisplaySystemUiContexts.get(DEFAULT_DISPLAY); + } + } + + void onSystemUiContextCleanup(ContextImpl context) { + synchronized (this) { + if (mDisplaySystemUiContexts == null) return; + final int index = mDisplaySystemUiContexts.indexOfValue(context); + if (index >= 0) { + mDisplaySystemUiContexts.removeAt(index); + } + } + } + public void installSystemApplicationInfo(ApplicationInfo info, ClassLoader classLoader) { synchronized (this) { getSystemContext().installSystemApplicationInfo(info, classLoader); @@ -3563,6 +3626,13 @@ public final class ActivityThread extends ClientTransactionHandler + ", comp=" + r.intent.getComponent().toShortString() + ", dir=" + r.packageInfo.getAppDir()); + // updatePendingActivityConfiguration() reads from mActivities to update + // ActivityClientRecord which runs in a different thread. Protect modifications to + // mActivities to avoid race. + synchronized (mResourcesManager) { + mActivities.put(r.token, r); + } + if (activity != null) { CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager()); Configuration config = @@ -3608,6 +3678,11 @@ public final class ActivityThread extends ClientTransactionHandler } activity.mLaunchedFromBubble = r.mLaunchedFromBubble; activity.mCalled = false; + // Assigning the activity to the record before calling onCreate() allows + // ActivityThread#getActivity() lookup for the callbacks triggered from + // ActivityLifecycleCallbacks#onActivityCreated() or + // ActivityLifecycleCallback#onActivityPostCreated(). + r.activity = activity; if (r.isPersistable()) { mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState); } else { @@ -3618,19 +3693,11 @@ public final class ActivityThread extends ClientTransactionHandler "Activity " + r.intent.getComponent().toShortString() + " did not call through to super.onCreate()"); } - r.activity = activity; mLastReportedWindowingMode.put(activity.getActivityToken(), config.windowConfiguration.getWindowingMode()); } r.setState(ON_CREATE); - // updatePendingActivityConfiguration() reads from mActivities to update - // ActivityClientRecord which runs in a different thread. Protect modifications to - // mActivities to avoid race. - synchronized (mResourcesManager) { - mActivities.put(r.token, r); - } - } catch (SuperNotCalledException e) { throw e; @@ -4074,10 +4141,11 @@ public final class ActivityThread extends ClientTransactionHandler @Override public void handleAttachSplashScreenView(@NonNull ActivityClientRecord r, - @Nullable SplashScreenView.SplashScreenViewParcelable parcelable) { + @Nullable SplashScreenView.SplashScreenViewParcelable parcelable, + @NonNull SurfaceControl startingWindowLeash) { final DecorView decorView = (DecorView) r.window.peekDecorView(); if (parcelable != null && decorView != null) { - createSplashScreen(r, decorView, parcelable); + createSplashScreen(r, decorView, parcelable, startingWindowLeash); } else { // shouldn't happen! Slog.e(TAG, "handleAttachSplashScreenView failed, unable to attach"); @@ -4085,63 +4153,57 @@ public final class ActivityThread extends ClientTransactionHandler } private void createSplashScreen(ActivityClientRecord r, DecorView decorView, - SplashScreenView.SplashScreenViewParcelable parcelable) { + SplashScreenView.SplashScreenViewParcelable parcelable, + @NonNull SurfaceControl startingWindowLeash) { final SplashScreenView.Builder builder = new SplashScreenView.Builder(r.activity); final SplashScreenView view = builder.createFromParcel(parcelable).build(); decorView.addView(view); view.attachHostActivityAndSetSystemUIColors(r.activity, r.window); view.requestLayout(); - // Ensure splash screen view is shown before remove the splash screen window. - final ViewRootImpl impl = decorView.getViewRootImpl(); - final boolean hardwareEnabled = impl != null && impl.isHardwareEnabled(); - final AtomicBoolean notified = new AtomicBoolean(); - if (hardwareEnabled) { - final Runnable frameCommit = new Runnable() { - @Override - public void run() { - view.post(() -> { - if (!notified.get()) { - view.getViewTreeObserver().unregisterFrameCommitCallback(this); - ActivityClient.getInstance().reportSplashScreenAttached( - r.token); - notified.set(true); - } - }); - } - }; - view.getViewTreeObserver().registerFrameCommitCallback(frameCommit); - } else { - final ViewTreeObserver.OnDrawListener onDrawListener = - new ViewTreeObserver.OnDrawListener() { - @Override - public void onDraw() { - view.post(() -> { - if (!notified.get()) { - view.getViewTreeObserver().removeOnDrawListener(this); - ActivityClient.getInstance().reportSplashScreenAttached( - r.token); - notified.set(true); - } - }); - } - }; - view.getViewTreeObserver().addOnDrawListener(onDrawListener); - } + + view.getViewTreeObserver().addOnDrawListener(new ViewTreeObserver.OnDrawListener() { + private boolean mHandled = false; + @Override + public void onDraw() { + if (mHandled) { + return; + } + mHandled = true; + // Transfer the splash screen view from shell to client. + // Call syncTransferSplashscreenViewTransaction at the first onDraw so we can ensure + // the client view is ready to show and we can use applyTransactionOnDraw to make + // all transitions happen at the same frame. + syncTransferSplashscreenViewTransaction( + view, r.token, decorView, startingWindowLeash); + view.post(() -> view.getViewTreeObserver().removeOnDrawListener(this)); + } + }); } - @Override - public void handOverSplashScreenView(@NonNull ActivityClientRecord r) { - final SplashScreenView v = r.activity.getSplashScreenView(); - if (v == null) { - return; - } + private void reportSplashscreenViewShown(IBinder token, SplashScreenView view) { + ActivityClient.getInstance().reportSplashScreenAttached(token); synchronized (this) { if (mSplashScreenGlobal != null) { - mSplashScreenGlobal.handOverSplashScreenView(r.token, v); + mSplashScreenGlobal.handOverSplashScreenView(token, view); } } } + private void syncTransferSplashscreenViewTransaction(SplashScreenView view, IBinder token, + View decorView, @NonNull SurfaceControl startingWindowLeash) { + // Ensure splash screen view is shown before remove the splash screen window. + // Once the copied splash screen view is onDrawn on decor view, use applyTransactionOnDraw + // to ensure the transfer of surface view and hide starting window are happen at the same + // frame. + final SurfaceControl.Transaction transaction = new SurfaceControl.Transaction(); + transaction.hide(startingWindowLeash); + + decorView.getViewRootImpl().applyTransactionOnDraw(transaction); + view.syncTransferSurfaceOnDraw(); + // Tell server we can remove the starting window + decorView.postOnAnimation(() -> reportSplashscreenViewShown(token, view)); + } + /** * Cycle activity through onPause and onUserLeaveHint so that PIP is entered if supported, then * return to its previous state. This allows activities that rely on onUserLeaveHint instead of @@ -4913,7 +4975,7 @@ public final class ActivityThread extends ClientTransactionHandler Slog.w(TAG, "Activity top position already set to onTop=" + onTop); return; } - // TODO(b/197484331): Remove this short-term workaround while fixing the binder failure. + // TODO(b/209744518): Remove this short-term workaround while fixing the binder failure. Slog.e(TAG, "Activity top position already set to onTop=" + onTop); } @@ -5442,6 +5504,12 @@ public final class ActivityThread extends ClientTransactionHandler // behave properly when activity is relaunching. r.window.clearContentView(); } else { + final ViewRootImpl viewRoot = v.getViewRootImpl(); + if (viewRoot != null) { + // Clear the callback to avoid the destroyed activity from receiving + // configuration changes that are no longer effective. + viewRoot.setActivityConfigCallback(null); + } wm.removeViewImmediate(v); } } @@ -5765,7 +5833,7 @@ public final class ActivityThread extends ClientTransactionHandler } @Override - public ArrayList collectComponentCallbacks(boolean includeActivities) { + public ArrayList collectComponentCallbacks(boolean includeUiContexts) { ArrayList callbacks = new ArrayList(); @@ -5774,7 +5842,7 @@ public final class ActivityThread extends ClientTransactionHandler for (int i=0; i= 0; i--) { final Activity a = mActivities.valueAt(i).activity; if (a != null && !a.mFinished) { @@ -5784,11 +5852,12 @@ public final class ActivityThread extends ClientTransactionHandler } final int NSVC = mServices.size(); for (int i=0; i callbacks = - collectComponentCallbacks(true /* includeActivities */); + collectComponentCallbacks(true /* includeUiContexts */); final int N = callbacks.size(); for (int i=0; i callbacks = - collectComponentCallbacks(true /* includeActivities */); + collectComponentCallbacks(true /* includeUiContexts */); final int N = callbacks.size(); for (int i = 0; i < N; i++) { @@ -7609,12 +7641,6 @@ public final class ActivityThread extends ClientTransactionHandler ViewRootImpl.ConfigChangedCallback configChangedCallback = (Configuration globalConfig) -> { synchronized (mResourcesManager) { - // TODO (b/135719017): Temporary log for debugging IME service. - if (Build.IS_DEBUGGABLE && mHasImeComponent) { - Log.d(TAG, "ViewRootImpl.ConfigChangedCallback for IME, " - + "config=" + globalConfig); - } - // We need to apply this change to the resources immediately, because upon returning // the view hierarchy will be informed about it. if (mResourcesManager.applyConfigurationToResources(globalConfig, @@ -7969,11 +7995,6 @@ public final class ActivityThread extends ClientTransactionHandler return mDensityCompatMode; } - @Override - public boolean hasImeComponent() { - return mHasImeComponent; - } - // ------------------ Regular JNI ------------------------ private native void nPurgePendingResources(); private native void nDumpGraphicsInfo(FileDescriptor fd); diff --git a/core/java/android/app/ActivityThreadInternal.java b/core/java/android/app/ActivityThreadInternal.java index d91933c0f817..b9ad5c337813 100644 --- a/core/java/android/app/ActivityThreadInternal.java +++ b/core/java/android/app/ActivityThreadInternal.java @@ -28,15 +28,13 @@ import java.util.ArrayList; interface ActivityThreadInternal { ContextImpl getSystemContext(); - ContextImpl getSystemUiContext(); + ContextImpl getSystemUiContextNoCreate(); boolean isInDensityCompatMode(); - boolean hasImeComponent(); - boolean isCachedProcessState(); Application getApplication(); - ArrayList collectComponentCallbacks(boolean includeActivities); + ArrayList collectComponentCallbacks(boolean includeUiContexts); } diff --git a/core/java/android/app/ActivityTransitionCoordinator.java b/core/java/android/app/ActivityTransitionCoordinator.java index 4b87a647a80b..f5b3b40d88d6 100644 --- a/core/java/android/app/ActivityTransitionCoordinator.java +++ b/core/java/android/app/ActivityTransitionCoordinator.java @@ -871,6 +871,7 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver { if (view.isAttachedToWindow()) { tempMatrix.reset(); mSharedElementParentMatrices.get(i).invert(tempMatrix); + decor.transformMatrixToLocal(tempMatrix); GhostView.addGhost(view, decor, tempMatrix); ViewGroup parent = (ViewGroup) view.getParent(); if (moveWithParent && !isInTransitionGroup(parent, decor)) { diff --git a/core/java/android/app/Application.java b/core/java/android/app/Application.java index 618eda8c84e8..a1eab6553cff 100644 --- a/core/java/android/app/Application.java +++ b/core/java/android/app/Application.java @@ -205,6 +205,13 @@ public class Application extends ContextWrapper implements ComponentCallbacks2 { */ default void onActivityPostDestroyed(@NonNull Activity activity) { } + + /** + * Called when the Activity configuration was changed. + * @hide + */ + default void onActivityConfigurationChanged(@NonNull Activity activity) { + } } /** @@ -554,6 +561,16 @@ public class Application extends ContextWrapper implements ComponentCallbacks2 { } } + /* package */ void dispatchActivityConfigurationChanged(@NonNull Activity activity) { + Object[] callbacks = collectActivityLifecycleCallbacks(); + if (callbacks != null) { + for (int i = 0; i < callbacks.length; i++) { + ((ActivityLifecycleCallbacks) callbacks[i]).onActivityConfigurationChanged( + activity); + } + } + } + @UnsupportedAppUsage private Object[] collectActivityLifecycleCallbacks() { Object[] callbacks = null; diff --git a/core/java/android/app/ClientTransactionHandler.java b/core/java/android/app/ClientTransactionHandler.java index 115101c0bff6..c743f6572d5e 100644 --- a/core/java/android/app/ClientTransactionHandler.java +++ b/core/java/android/app/ClientTransactionHandler.java @@ -28,6 +28,7 @@ import android.content.res.Configuration; import android.os.IBinder; import android.util.MergedConfiguration; import android.view.DisplayAdjustments.FixedRotationAdjustments; +import android.view.SurfaceControl; import android.window.SplashScreenView.SplashScreenViewParcelable; import com.android.internal.annotations.VisibleForTesting; @@ -165,10 +166,8 @@ public abstract class ClientTransactionHandler { /** Attach a splash screen window view to the top of the activity */ public abstract void handleAttachSplashScreenView(@NonNull ActivityClientRecord r, - @NonNull SplashScreenViewParcelable parcelable); - - /** Hand over the splash screen window view to the activity */ - public abstract void handOverSplashScreenView(@NonNull ActivityClientRecord r); + @NonNull SplashScreenViewParcelable parcelable, + @NonNull SurfaceControl startingWindowLeash); /** Perform activity launch. */ public abstract Activity handleLaunchActivity(@NonNull ActivityClientRecord r, diff --git a/core/java/android/app/ConfigurationController.java b/core/java/android/app/ConfigurationController.java index f79e0780ecae..58f60a6a59a7 100644 --- a/core/java/android/app/ConfigurationController.java +++ b/core/java/android/app/ConfigurationController.java @@ -17,24 +17,20 @@ package android.app; import static android.app.ActivityThread.DEBUG_CONFIGURATION; +import static android.window.ConfigurationHelper.freeTextLayoutCachesIfNeeded; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.ComponentCallbacks2; import android.content.Context; -import android.content.pm.ActivityInfo; import android.content.res.CompatibilityInfo; import android.content.res.Configuration; import android.content.res.Resources; import android.graphics.Bitmap; -import android.graphics.Canvas; import android.graphics.HardwareRenderer; -import android.inputmethodservice.InputMethodService; -import android.os.Build; import android.os.LocaleList; import android.os.Trace; import android.util.DisplayMetrics; -import android.util.Log; import android.util.Slog; import android.view.ContextThemeWrapper; import android.view.WindowManagerGlobal; @@ -158,9 +154,12 @@ class ConfigurationController { int configDiff; boolean equivalent; + // Get theme outside of synchronization to avoid nested lock. + final Resources.Theme systemTheme = mActivityThread.getSystemContext().getTheme(); + final ContextImpl systemUiContext = mActivityThread.getSystemUiContextNoCreate(); + final Resources.Theme systemUiTheme = + systemUiContext != null ? systemUiContext.getTheme() : null; synchronized (mResourcesManager) { - final Resources.Theme systemTheme = mActivityThread.getSystemContext().getTheme(); - final Resources.Theme systemUiTheme = mActivityThread.getSystemUiContext().getTheme(); if (mPendingConfiguration != null) { if (!mPendingConfiguration.isOtherSeqNewer(config)) { config = mPendingConfiguration; @@ -169,12 +168,7 @@ class ConfigurationController { mPendingConfiguration = null; } - final boolean hasIme = mActivityThread.hasImeComponent(); if (config == null) { - // TODO (b/135719017): Temporary log for debugging IME service. - if (Build.IS_DEBUGGABLE && hasIme) { - Log.w(TAG, "handleConfigurationChanged for IME app but config is null"); - } return; } @@ -205,12 +199,6 @@ class ConfigurationController { mConfiguration = new Configuration(); } if (!mConfiguration.isOtherSeqNewer(config) && compat == null) { - // TODO (b/135719017): Temporary log for debugging IME service. - if (Build.IS_DEBUGGABLE && hasIme) { - Log.w(TAG, "handleConfigurationChanged for IME app but config seq is obsolete " - + ", config=" + config - + ", mConfiguration=" + mConfiguration); - } return; } @@ -222,13 +210,14 @@ class ConfigurationController { systemTheme.rebase(); } - if ((systemUiTheme.getChangingConfigurations() & configDiff) != 0) { + if (systemUiTheme != null + && (systemUiTheme.getChangingConfigurations() & configDiff) != 0) { systemUiTheme.rebase(); } } final ArrayList callbacks = - mActivityThread.collectComponentCallbacks(false /* includeActivities */); + mActivityThread.collectComponentCallbacks(false /* includeUiContexts */); freeTextLayoutCachesIfNeeded(configDiff); @@ -238,13 +227,6 @@ class ConfigurationController { ComponentCallbacks2 cb = callbacks.get(i); if (!equivalent) { performConfigurationChanged(cb, config); - } else { - // TODO (b/135719017): Temporary log for debugging IME service. - if (Build.IS_DEBUGGABLE && cb instanceof InputMethodService) { - Log.w(TAG, "performConfigurationChanged didn't callback to IME " - + ", configDiff=" + configDiff - + ", mConfiguration=" + mConfiguration); - } } } } @@ -326,16 +308,4 @@ class ConfigurationController { return newConfig; } - /** Ask test layout engine to free its caches if there is a locale change. */ - static void freeTextLayoutCachesIfNeeded(int configDiff) { - if (configDiff != 0) { - boolean hasLocaleConfigChange = ((configDiff & ActivityInfo.CONFIG_LOCALE) != 0); - if (hasLocaleConfigChange) { - Canvas.freeTextLayoutCaches(); - if (DEBUG_CONFIGURATION) { - Slog.v(TAG, "Cleared TextLayout Caches"); - } - } - } - } } diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index 1093baade42c..fc34faccf3be 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -311,6 +311,14 @@ class ContextImpl extends Context { @ContextType private int mContextType; + /** + * {@code true} to indicate that the {@link Context} owns the {@link #getWindowContextToken()} + * and is responsible for detaching the token when the Context is released. + * + * @see #finalize() + */ + private boolean mOwnsToken = false; + @GuardedBy("mSync") private File mDatabasesDir; @GuardedBy("mSync") @@ -1862,6 +1870,14 @@ class ContextImpl extends Context { "Not allowed to start service " + service + ": " + cn.getClassName()); } } + // If we started a foreground service in the same package, remember the stack trace. + if (cn != null && requireForeground) { + if (cn.getPackageName().equals(getOpPackageName())) { + Service.setStartForegroundServiceStackTrace(cn.getClassName(), + new StackTrace("Last startServiceCommon() call for this service was " + + "made here")); + } + } return cn; } catch (RemoteException e) { throw e.rethrowFromSystemServer(); @@ -2745,7 +2761,7 @@ class ContextImpl extends Context { */ private static Resources createWindowContextResources(@NonNull ContextImpl windowContextBase) { final LoadedApk packageInfo = windowContextBase.mPackageInfo; - final ClassLoader classLoader = windowContextBase.mClassLoader; + final ClassLoader classLoader = windowContextBase.getClassLoader(); final IBinder token = windowContextBase.getWindowContextToken(); final String resDir = packageInfo.getResDir(); @@ -3002,6 +3018,7 @@ class ContextImpl extends Context { token.attachContext(context); token.attachToDisplayContent(displayId); context.mContextType = CONTEXT_TYPE_SYSTEM_OR_SYSTEM_UI; + context.mOwnsToken = true; return context; } @@ -3183,6 +3200,10 @@ class ContextImpl extends Context { final void performFinalCleanup(String who, String what) { //Log.i(TAG, "Cleanup up context: " + this); mPackageInfo.removeContextRegistrations(getOuterContext(), who, what); + if (mContextType == CONTEXT_TYPE_SYSTEM_OR_SYSTEM_UI + && mToken instanceof WindowTokenClient) { + mMainThread.onSystemUiContextCleanup(this); + } } @UnsupportedAppUsage @@ -3196,12 +3217,6 @@ class ContextImpl extends Context { @UnsupportedAppUsage final void setOuterContext(@NonNull Context context) { mOuterContext = context; - // TODO(b/149463653): check if we still need this method after migrating IMS to - // WindowContext. - if (mOuterContext.isUiContext() && mContextType <= CONTEXT_TYPE_DISPLAY_CONTEXT) { - mContextType = CONTEXT_TYPE_WINDOW_CONTEXT; - mIsConfigurationBasedContext = true; - } } @UnsupportedAppUsage diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java index 9833ed60fe46..306035341ea3 100644 --- a/core/java/android/app/Dialog.java +++ b/core/java/android/app/Dialog.java @@ -151,6 +151,9 @@ public class Dialog implements DialogInterface, Window.Callback, private final Runnable mDismissAction = this::dismissDialog; + /** A {@link Runnable} to run instead of dismissing when {@link #dismiss()} is called. */ + private Runnable mDismissOverride; + /** * Creates a dialog window that uses the default dialog theme. *

@@ -370,6 +373,11 @@ public class Dialog implements DialogInterface, Window.Callback, */ @Override public void dismiss() { + if (mDismissOverride != null) { + mDismissOverride.run(); + return; + } + if (Looper.myLooper() == mHandler.getLooper()) { dismissDialog(); } else { @@ -1354,6 +1362,21 @@ public class Dialog implements DialogInterface, Window.Callback, mDismissMessage = msg; } + /** + * Set a {@link Runnable} to run when this dialog is dismissed instead of directly dismissing + * it. This allows to animate the dialog in its window before dismissing it. + * + * Note that {@code override} should always end up calling this method with {@code null} + * followed by a call to {@link #dismiss() dismiss} to actually dismiss the dialog. + * + * @see #dismiss() + * + * @hide + */ + public void setDismissOverride(@Nullable Runnable override) { + mDismissOverride = override; + } + /** @hide */ public boolean takeCancelAndDismissListeners(@Nullable String msg, @Nullable OnCancelListener cancel, @Nullable OnDismissListener dismiss) { diff --git a/core/java/android/app/DirectAction.java b/core/java/android/app/DirectAction.java index b0ed490369ad..ac3868b2ece9 100644 --- a/core/java/android/app/DirectAction.java +++ b/core/java/android/app/DirectAction.java @@ -22,14 +22,13 @@ import android.os.Bundle; import android.os.IBinder; import android.os.Parcel; import android.os.Parcelable; -import android.view.accessibility.AccessibilityNodeInfo; import com.android.internal.util.Preconditions; import java.util.Objects; /** - * Represents a abstract action that can be perform on this app. This are requested from + * Represents an abstract action that can be perform on this app. This are requested from * outside the app's UI (eg by SystemUI or assistant). The semantics of these actions are * not specified by the OS. This allows open-ended and scalable approach for defining how * an app interacts with components that expose alternative interaction models to the user diff --git a/core/java/android/app/DisabledWallpaperManager.java b/core/java/android/app/DisabledWallpaperManager.java index 1f323c378093..ae3a9e6668ab 100644 --- a/core/java/android/app/DisabledWallpaperManager.java +++ b/core/java/android/app/DisabledWallpaperManager.java @@ -74,6 +74,11 @@ final class DisabledWallpaperManager extends WallpaperManager { return false; } + private static int unsupportedInt() { + if (DEBUG) Log.w(TAG, "unsupported method called; returning -1", new Exception()); + return -1; + } + @Override public Drawable getDrawable() { return unsupported(); @@ -189,12 +194,12 @@ final class DisabledWallpaperManager extends WallpaperManager { @Override public int getWallpaperId(int which) { - return unsupported(); + return unsupportedInt(); } @Override public int getWallpaperIdForUser(int which, int userId) { - return unsupported(); + return unsupportedInt(); } @Override @@ -209,7 +214,8 @@ final class DisabledWallpaperManager extends WallpaperManager { @Override public int setResource(int resid, int which) throws IOException { - return unsupported(); + unsupported(); + return 0; } @Override @@ -220,19 +226,22 @@ final class DisabledWallpaperManager extends WallpaperManager { @Override public int setBitmap(Bitmap fullImage, Rect visibleCropHint, boolean allowBackup) throws IOException { - return unsupported(); + unsupported(); + return 0; } @Override public int setBitmap(Bitmap fullImage, Rect visibleCropHint, boolean allowBackup, int which) throws IOException { - return unsupported(); + unsupported(); + return 0; } @Override public int setBitmap(Bitmap fullImage, Rect visibleCropHint, boolean allowBackup, int which, int userId) throws IOException { - return unsupported(); + unsupported(); + return 0; } @Override @@ -243,13 +252,15 @@ final class DisabledWallpaperManager extends WallpaperManager { @Override public int setStream(InputStream bitmapData, Rect visibleCropHint, boolean allowBackup) throws IOException { - return unsupported(); + unsupported(); + return 0; } @Override public int setStream(InputStream bitmapData, Rect visibleCropHint, boolean allowBackup, int which) throws IOException { - return unsupported(); + unsupported(); + return 0; } @Override @@ -259,12 +270,12 @@ final class DisabledWallpaperManager extends WallpaperManager { @Override public int getDesiredMinimumWidth() { - return unsupported(); + return unsupportedInt(); } @Override public int getDesiredMinimumHeight() { - return unsupported(); + return unsupportedInt(); } @Override diff --git a/core/java/android/app/ForegroundServiceDidNotStartInTimeException.java b/core/java/android/app/ForegroundServiceDidNotStartInTimeException.java deleted file mode 100644 index 364291e69ad6..000000000000 --- a/core/java/android/app/ForegroundServiceDidNotStartInTimeException.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (C) 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT 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; - -/** - * Exception used to crash an app process when it didn't call {@link Service#startForeground} - * in time after the service was started with - * {@link android.content.Context#startForegroundService}. - * - * @hide - */ -public class ForegroundServiceDidNotStartInTimeException extends RemoteServiceException { - /** The type ID passed to {@link IApplicationThread#scheduleCrash}. */ - public static final int TYPE_ID = 1; - - public ForegroundServiceDidNotStartInTimeException(String msg) { - super(msg); - } -} diff --git a/core/java/android/app/IActivityClientController.aidl b/core/java/android/app/IActivityClientController.aidl index c6649692d848..aba6eb9229f2 100644 --- a/core/java/android/app/IActivityClientController.aidl +++ b/core/java/android/app/IActivityClientController.aidl @@ -70,6 +70,7 @@ interface IActivityClientController { boolean willActivityBeVisible(in IBinder token); int getDisplayId(in IBinder activityToken); int getTaskForActivity(in IBinder token, in boolean onlyRoot); + IBinder getActivityTokenBelow(IBinder token); ComponentName getCallingActivity(in IBinder token); String getCallingPackage(in IBinder token); int getLaunchedFromUid(in IBinder token); diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl index b90b9a11611e..64a9c441c57f 100644 --- a/core/java/android/app/IActivityManager.aidl +++ b/core/java/android/app/IActivityManager.aidl @@ -319,10 +319,10 @@ interface IActivityManager { void handleApplicationStrictModeViolation(in IBinder app, int penaltyMask, in StrictMode.ViolationInfo crashInfo); boolean isTopActivityImmersive(); - void crashApplication(int uid, int initialPid, in String packageName, int userId, - in String message, boolean force); void crashApplicationWithType(int uid, int initialPid, in String packageName, int userId, in String message, boolean force, int exceptionTypeId); + void crashApplicationWithTypeWithExtras(int uid, int initialPid, in String packageName, + int userId, in String message, boolean force, int exceptionTypeId, in Bundle extras); /** @deprecated -- use getProviderMimeTypeAsync */ @UnsupportedAppUsage(maxTargetSdk = 29, publicAlternatives = "Use {@link android.content.ContentResolver#getType} public API instead.") @@ -340,7 +340,10 @@ interface IActivityManager { void setPackageScreenCompatMode(in String packageName, int mode); @UnsupportedAppUsage boolean switchUser(int userid); + String getSwitchingFromUserMessage(); + String getSwitchingToUserMessage(); @UnsupportedAppUsage + void setStopUserOnSwitch(int value); boolean removeTask(int taskId); @UnsupportedAppUsage void registerProcessObserver(in IProcessObserver observer); diff --git a/core/java/android/app/IActivityTaskManager.aidl b/core/java/android/app/IActivityTaskManager.aidl index 74d51a0bcf63..2be78033ddf7 100644 --- a/core/java/android/app/IActivityTaskManager.aidl +++ b/core/java/android/app/IActivityTaskManager.aidl @@ -330,4 +330,18 @@ interface IActivityTaskManager { * When the Picture-in-picture state has changed. */ void onPictureInPictureStateChanged(in PictureInPictureUiState pipState); + + /** + * Re-attach navbar to the display during a recents transition. + * TODO(188595497): Remove this once navbar attachment is in shell. + */ + void detachNavigationBarFromApp(in IBinder transition); + + /** + * Marks a process as a delegate for the currently playing remote transition animation. This + * must be called from a process that is already a remote transition player or delegate. Any + * marked delegates are cleaned-up automatically at the end of the transition. + * @param caller is the IApplicationThread representing the calling process. + */ + void setRunningRemoteTransitionDelegate(in IApplicationThread caller); } diff --git a/core/java/android/app/IApplicationThread.aidl b/core/java/android/app/IApplicationThread.aidl index d6ff6d3dfc3a..448c3cf48e10 100644 --- a/core/java/android/app/IApplicationThread.aidl +++ b/core/java/android/app/IApplicationThread.aidl @@ -107,7 +107,7 @@ oneway interface IApplicationThread { void scheduleOnNewActivityOptions(IBinder token, in Bundle options); void scheduleSuicide(); void dispatchPackageBroadcast(int cmd, in String[] packages); - void scheduleCrash(in String msg, int typeId); + void scheduleCrash(in String msg, int typeId, in Bundle extras); void dumpHeap(boolean managed, boolean mallocInfo, boolean runGc, in String path, in ParcelFileDescriptor fd, in RemoteCallback finishCallback); void dumpActivity(in ParcelFileDescriptor fd, IBinder servicetoken, in String prefix, diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java index 1ca4d1c27e04..a445267b36a9 100644 --- a/core/java/android/app/Instrumentation.java +++ b/core/java/android/app/Instrumentation.java @@ -743,6 +743,18 @@ public class Instrumentation { } } + /** + * This overload is used for notifying the {@link android.window.TaskFragmentOrganizer} + * implementation internally about started activities. + * + * @see #onStartActivity(Intent) + * @hide + */ + public ActivityResult onStartActivity(@NonNull Context who, @NonNull Intent intent, + @NonNull Bundle options) { + return onStartActivity(intent); + } + /** * Used for intercepting any started activity. * @@ -1724,7 +1736,10 @@ public class Instrumentation { final ActivityMonitor am = mActivityMonitors.get(i); ActivityResult result = null; if (am.ignoreMatchingSpecificIntents()) { - result = am.onStartActivity(intent); + if (options == null) { + options = ActivityOptions.makeBasic().toBundle(); + } + result = am.onStartActivity(who, intent, options); } if (result != null) { am.mHits++; @@ -1793,7 +1808,10 @@ public class Instrumentation { final ActivityMonitor am = mActivityMonitors.get(i); ActivityResult result = null; if (am.ignoreMatchingSpecificIntents()) { - result = am.onStartActivity(intents[0]); + if (options == null) { + options = ActivityOptions.makeBasic().toBundle(); + } + result = am.onStartActivity(who, intents[0], options); } if (result != null) { am.mHits++; @@ -1865,7 +1883,10 @@ public class Instrumentation { final ActivityMonitor am = mActivityMonitors.get(i); ActivityResult result = null; if (am.ignoreMatchingSpecificIntents()) { - result = am.onStartActivity(intent); + if (options == null) { + options = ActivityOptions.makeBasic().toBundle(); + } + result = am.onStartActivity(who, intent, options); } if (result != null) { am.mHits++; @@ -1933,7 +1954,10 @@ public class Instrumentation { final ActivityMonitor am = mActivityMonitors.get(i); ActivityResult result = null; if (am.ignoreMatchingSpecificIntents()) { - result = am.onStartActivity(intent); + if (options == null) { + options = ActivityOptions.makeBasic().toBundle(); + } + result = am.onStartActivity(who, intent, options); } if (result != null) { am.mHits++; @@ -1979,7 +2003,10 @@ public class Instrumentation { final ActivityMonitor am = mActivityMonitors.get(i); ActivityResult result = null; if (am.ignoreMatchingSpecificIntents()) { - result = am.onStartActivity(intent); + if (options == null) { + options = ActivityOptions.makeBasic().toBundle(); + } + result = am.onStartActivity(who, intent, options); } if (result != null) { am.mHits++; @@ -2027,7 +2054,10 @@ public class Instrumentation { final ActivityMonitor am = mActivityMonitors.get(i); ActivityResult result = null; if (am.ignoreMatchingSpecificIntents()) { - result = am.onStartActivity(intent); + if (options == null) { + options = ActivityOptions.makeBasic().toBundle(); + } + result = am.onStartActivity(who, intent, options); } if (result != null) { am.mHits++; diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java index a2c9795204ad..74208c3a4aff 100644 --- a/core/java/android/app/LoadedApk.java +++ b/core/java/android/app/LoadedApk.java @@ -2134,4 +2134,38 @@ public final class LoadedApk { final IBinder mService; } } + + /** + * Check if the Apk paths in the cache are correct, and update them if they are not. + * @hide + */ + public static void checkAndUpdateApkPaths(ApplicationInfo expectedAppInfo) { + // Get the LoadedApk from the cache + ActivityThread activityThread = ActivityThread.currentActivityThread(); + if (activityThread == null) { + Log.e(TAG, "Cannot find activity thread"); + return; + } + checkAndUpdateApkPaths(activityThread, expectedAppInfo, /* cacheWithCode */ true); + checkAndUpdateApkPaths(activityThread, expectedAppInfo, /* cacheWithCode */ false); + } + + private static void checkAndUpdateApkPaths(ActivityThread activityThread, + ApplicationInfo expectedAppInfo, boolean cacheWithCode) { + String expectedCodePath = expectedAppInfo.getCodePath(); + LoadedApk loadedApk = activityThread.peekPackageInfo( + expectedAppInfo.packageName, /* includeCode= */ cacheWithCode); + // If there is load apk cached, or if the cache is valid, don't do anything. + if (loadedApk == null || loadedApk.getApplicationInfo() == null + || loadedApk.getApplicationInfo().getCodePath().equals(expectedCodePath)) { + return; + } + // Duplicate framework logic + List oldPaths = new ArrayList<>(); + LoadedApk.makePaths(activityThread, expectedAppInfo, oldPaths); + + // Force update the LoadedApk instance, which should update the reference in the cache + loadedApk.updateApplicationInfo(expectedAppInfo, oldPaths); + } + } diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index 61b1abe25ca2..2c02be7dc6b9 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -5810,6 +5810,7 @@ public class Notification implements Parcelable p, result); buildCustomContentIntoTemplate(mContext, standard, customContent, p, result); + makeHeaderExpanded(standard); return standard; } @@ -6793,7 +6794,7 @@ public class Notification implements Parcelable // We show these sorts of notifications immediately in the absence of // any explicit app declaration - if (isMediaNotification() || hasMediaSession() + if (isMediaNotification() || CATEGORY_CALL.equals(category) || CATEGORY_NAVIGATION.equals(category) || (actions != null && actions.length > 0)) { @@ -6812,14 +6813,6 @@ public class Notification implements Parcelable return FOREGROUND_SERVICE_DEFERRED == mFgsDeferBehavior; } - /** - * @return whether this notification has a media session attached - * @hide - */ - public boolean hasMediaSession() { - return extras.getParcelable(Notification.EXTRA_MEDIA_SESSION) != null; - } - /** * @return the style class of this notification * @hide @@ -6863,18 +6856,20 @@ public class Notification implements Parcelable } /** - * @return true if this is a media notification + * @return true if this is a media style notification with a media session * * @hide */ public boolean isMediaNotification() { Class style = getNotificationStyle(); - if (MediaStyle.class.equals(style)) { - return true; - } else if (DecoratedMediaCustomViewStyle.class.equals(style)) { - return true; - } - return false; + boolean isMediaStyle = (MediaStyle.class.equals(style) + || DecoratedMediaCustomViewStyle.class.equals(style)); + + boolean hasMediaSession = (extras.getParcelable(Notification.EXTRA_MEDIA_SESSION) != null + && extras.getParcelable(Notification.EXTRA_MEDIA_SESSION) + instanceof MediaSession.Token); + + return isMediaStyle && hasMediaSession; } /** diff --git a/core/java/android/app/RemoteServiceException.java b/core/java/android/app/RemoteServiceException.java index 4b32463e2996..e220627706f9 100644 --- a/core/java/android/app/RemoteServiceException.java +++ b/core/java/android/app/RemoteServiceException.java @@ -16,23 +16,133 @@ package android.app; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.ComponentName; +import android.os.Bundle; import android.util.AndroidRuntimeException; /** - * Exception used by {@link ActivityThread} to crash an app process. + * Exception used by {@link ActivityThread} to crash an app process for an unknown cause. + * An exception of this class is no longer supposed to be thrown. Instead, we use fine-grained + * sub-exceptions. + * + * Subclasses must be registered in + * {@link android.app.ActivityThread#throwRemoteServiceException(java.lang.String, int)}. * * @hide */ public class RemoteServiceException extends AndroidRuntimeException { + public RemoteServiceException(String msg) { + super(msg); + } + + public RemoteServiceException(String msg, Throwable cause) { + super(msg, cause); + } + /** - * The type ID passed to {@link IApplicationThread#scheduleCrash}. + * Exception used to crash an app process when it didn't call {@link Service#startForeground} + * in time after the service was started with + * {@link android.content.Context#startForegroundService}. * - * Assign a unique ID to each subclass. See the above method for the numbers that are already - * taken. + * @hide */ - public static final int TYPE_ID = 0; + public static class ForegroundServiceDidNotStartInTimeException extends RemoteServiceException { + /** The type ID passed to {@link IApplicationThread#scheduleCrash}. */ + public static final int TYPE_ID = 1; - public RemoteServiceException(String msg) { - super(msg); + private static final String KEY_SERVICE_CLASS_NAME = "serviceclassname"; + + public ForegroundServiceDidNotStartInTimeException(String msg, Throwable cause) { + super(msg, cause); + } + + public static Bundle createExtrasForService(@NonNull ComponentName service) { + Bundle b = new Bundle(); + b.putString(KEY_SERVICE_CLASS_NAME, service.getClassName()); + return b; + } + + @Nullable + public static String getServiceClassNameFromExtras(@Nullable Bundle extras) { + return (extras == null) ? null : extras.getString(KEY_SERVICE_CLASS_NAME); + } + } + + /** + * Exception used to crash an app process when the system received a RemoteException + * while delivering a broadcast to an app process. + * + * @hide + */ + public static class CannotDeliverBroadcastException extends RemoteServiceException { + /** The type ID passed to {@link IApplicationThread#scheduleCrash}. */ + public static final int TYPE_ID = 2; + + public CannotDeliverBroadcastException(String msg) { + super(msg); + } + } + + /** + * Exception used to crash an app process when the system received a RemoteException + * while posting a notification of a foreground service. + * + * @hide + */ + public static class CannotPostForegroundServiceNotificationException + extends RemoteServiceException { + /** The type ID passed to {@link IApplicationThread#scheduleCrash}. */ + public static final int TYPE_ID = 3; + + public CannotPostForegroundServiceNotificationException(String msg) { + super(msg); + } + } + + /** + * Exception used to crash an app process when the system finds an error in a foreground service + * notification. + * + * @hide + */ + public static class BadForegroundServiceNotificationException extends RemoteServiceException { + /** The type ID passed to {@link IApplicationThread#scheduleCrash}. */ + public static final int TYPE_ID = 4; + + public BadForegroundServiceNotificationException(String msg) { + super(msg); + } + } + + /** + * Exception used to crash an app process when it calls a setting activity that requires + * the {@code REQUEST_PASSWORD_COMPLEXITY} permission. + * + * @hide + */ + public static class MissingRequestPasswordComplexityPermissionException + extends RemoteServiceException { + /** The type ID passed to {@link IApplicationThread#scheduleCrash}. */ + public static final int TYPE_ID = 5; + + public MissingRequestPasswordComplexityPermissionException(String msg) { + super(msg); + } + } + + /** + * Exception used to crash an app process by {@code adb shell am crash}. + * + * @hide + */ + public static class CrashedByAdbException extends RemoteServiceException { + /** The type ID passed to {@link IApplicationThread#scheduleCrash}. */ + public static final int TYPE_ID = 6; + + public CrashedByAdbException(String msg) { + super(msg); + } } } diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java index 198c33e83707..bf3778dfeecc 100644 --- a/core/java/android/app/ResourcesManager.java +++ b/core/java/android/app/ResourcesManager.java @@ -693,7 +693,7 @@ public class ResourcesManager { * @return true if activity resources override config matches the provided one or they are both * null, false otherwise. */ - boolean isSameResourcesOverrideConfig(@Nullable IBinder activityToken, + public boolean isSameResourcesOverrideConfig(@Nullable IBinder activityToken, @Nullable Configuration overrideConfig) { synchronized (mLock) { final ActivityResources activityResources diff --git a/core/java/android/app/Service.java b/core/java/android/app/Service.java index 336387204410..5a5ccb5d8987 100644 --- a/core/java/android/app/Service.java +++ b/core/java/android/app/Service.java @@ -33,9 +33,12 @@ import android.content.res.Configuration; import android.os.Build; import android.os.IBinder; import android.os.RemoteException; +import android.util.ArrayMap; import android.util.Log; import android.view.contentcapture.ContentCaptureManager; +import com.android.internal.annotations.GuardedBy; + import java.io.FileDescriptor; import java.io.PrintWriter; import java.lang.annotation.Retention; @@ -733,6 +736,7 @@ public abstract class Service extends ContextWrapper implements ComponentCallbac mActivityManager.setServiceForeground( new ComponentName(this, mClassName), mToken, id, notification, 0, FOREGROUND_SERVICE_TYPE_MANIFEST); + clearStartForegroundServiceStackTrace(); } catch (RemoteException ex) { } } @@ -786,6 +790,7 @@ public abstract class Service extends ContextWrapper implements ComponentCallbac mActivityManager.setServiceForeground( new ComponentName(this, mClassName), mToken, id, notification, 0, foregroundServiceType); + clearStartForegroundServiceStackTrace(); } catch (RemoteException ex) { } } @@ -941,4 +946,34 @@ public abstract class Service extends ContextWrapper implements ComponentCallbac private IActivityManager mActivityManager = null; @UnsupportedAppUsage private boolean mStartCompatibility = false; + + /** + * This keeps track of the stacktrace where Context.startForegroundService() was called + * for each service class. We use that when we crash the app for not calling + * {@link #startForeground} in time, in {@link ActivityThread#throwRemoteServiceException}. + */ + @GuardedBy("sStartForegroundServiceStackTraces") + private static final ArrayMap sStartForegroundServiceStackTraces = + new ArrayMap<>(); + + /** @hide */ + public static void setStartForegroundServiceStackTrace( + @NonNull String className, @NonNull StackTrace stacktrace) { + synchronized (sStartForegroundServiceStackTraces) { + sStartForegroundServiceStackTraces.put(className, stacktrace); + } + } + + private void clearStartForegroundServiceStackTrace() { + synchronized (sStartForegroundServiceStackTraces) { + sStartForegroundServiceStackTraces.remove(this.getClassName()); + } + } + + /** @hide */ + public static StackTrace getStartForegroundServiceStackTrace(@NonNull String className) { + synchronized (sStartForegroundServiceStackTraces) { + return sStartForegroundServiceStackTraces.get(className); + } + } } diff --git a/core/java/android/app/ServiceStartNotAllowedException.java b/core/java/android/app/ServiceStartNotAllowedException.java index 33285b2190eb..b1f47eee4bfd 100644 --- a/core/java/android/app/ServiceStartNotAllowedException.java +++ b/core/java/android/app/ServiceStartNotAllowedException.java @@ -40,4 +40,11 @@ public abstract class ServiceStartNotAllowedException extends IllegalStateExcept return new BackgroundServiceStartNotAllowedException(message); } } + + @Override + public synchronized Throwable getCause() { + // "Cause" is often used for clustering exceptions, and developers don't want to have it + // for this exception. b/210890426 + return null; + } } diff --git a/core/java/android/app/StackTrace.java b/core/java/android/app/StackTrace.java new file mode 100644 index 000000000000..ec058f88118b --- /dev/null +++ b/core/java/android/app/StackTrace.java @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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; + +/** + * An Exception subclass that's used only for logging stacktraces. + * @hide + */ +public class StackTrace extends Exception { + public StackTrace(String message) { + super(message); + } +} diff --git a/core/java/android/app/StatusBarManager.java b/core/java/android/app/StatusBarManager.java index 77bcef3ae009..be702c2a1756 100644 --- a/core/java/android/app/StatusBarManager.java +++ b/core/java/android/app/StatusBarManager.java @@ -46,7 +46,7 @@ import java.lang.annotation.RetentionPolicy; */ @SystemService(Context.STATUS_BAR_SERVICE) public class StatusBarManager { - + // LINT.IfChange /** @hide */ public static final int DISABLE_EXPAND = View.STATUS_BAR_DISABLE_EXPAND; /** @hide */ @@ -144,6 +144,7 @@ public class StatusBarManager { }) @Retention(RetentionPolicy.SOURCE) public @interface Disable2Flags {} + // LINT.ThenChange(frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/DisableFlagsLogger.kt) /** * Default disable flags for setup diff --git a/core/java/android/app/TaskInfo.java b/core/java/android/app/TaskInfo.java index 85758a92fa98..ddde27220b96 100644 --- a/core/java/android/app/TaskInfo.java +++ b/core/java/android/app/TaskInfo.java @@ -17,6 +17,7 @@ package android.app; import static android.app.ActivityTaskManager.INVALID_TASK_ID; +import static android.window.DisplayAreaOrganizer.FEATURE_UNDEFINED; import android.annotation.NonNull; import android.annotation.Nullable; @@ -118,6 +119,12 @@ public class TaskInfo { */ public int displayId; + /** + * The feature id of {@link com.android.server.wm.TaskDisplayArea} this task is associated with. + * @hide + */ + public int displayAreaFeatureId = FEATURE_UNDEFINED; + /** * The recent activity values for the highest activity in the stack to have set the values. * {@link Activity#setTaskDescription(android.app.ActivityManager.TaskDescription)}. @@ -243,6 +250,12 @@ public class TaskInfo { */ public boolean isVisible; + /** + * Whether this task is sleeping due to sleeping display. + * @hide + */ + public boolean isSleeping; + TaskInfo() { // Do nothing } @@ -251,6 +264,13 @@ public class TaskInfo { readFromParcel(source); } + /** + * Whether this task is visible. + */ + public boolean isVisible() { + return isVisible; + } + /** * @param isLowResolution * @return @@ -329,11 +349,10 @@ public class TaskInfo { } /** - * Returns {@code true} if parameters that are important for task organizers have changed - * and {@link com.android.server.wm.TaskOrginizerController} needs to notify listeners - * about that. - * @hide - */ + * Returns {@code true} if the parameters that are important for task organizers are equal + * between this {@link TaskInfo} and {@param that}. + * @hide + */ public boolean equalsForTaskOrganizer(@Nullable TaskInfo that) { if (that == null) { return false; @@ -341,13 +360,16 @@ public class TaskInfo { return topActivityType == that.topActivityType && isResizeable == that.isResizeable && supportsMultiWindow == that.supportsMultiWindow + && displayAreaFeatureId == that.displayAreaFeatureId && Objects.equals(positionInParent, that.positionInParent) && Objects.equals(pictureInPictureParams, that.pictureInPictureParams) && Objects.equals(displayCutoutInsets, that.displayCutoutInsets) && getWindowingMode() == that.getWindowingMode() && Objects.equals(taskDescription, that.taskDescription) && isFocused == that.isFocused - && isVisible == that.isVisible; + && isVisible == that.isVisible + && isSleeping == that.isSleeping + && Objects.equals(mTopActivityLocusId, that.mTopActivityLocusId); } /** @@ -402,8 +424,10 @@ public class TaskInfo { parentTaskId = source.readInt(); isFocused = source.readBoolean(); isVisible = source.readBoolean(); + isSleeping = source.readBoolean(); topActivityInSizeCompat = source.readBoolean(); mTopActivityLocusId = source.readTypedObject(LocusId.CREATOR); + displayAreaFeatureId = source.readInt(); } /** @@ -440,8 +464,10 @@ public class TaskInfo { dest.writeInt(parentTaskId); dest.writeBoolean(isFocused); dest.writeBoolean(isVisible); + dest.writeBoolean(isSleeping); dest.writeBoolean(topActivityInSizeCompat); dest.writeTypedObject(mTopActivityLocusId, flags); + dest.writeInt(displayAreaFeatureId); } @Override @@ -468,8 +494,10 @@ public class TaskInfo { + " parentTaskId=" + parentTaskId + " isFocused=" + isFocused + " isVisible=" + isVisible + + " isSleeping=" + isSleeping + " topActivityInSizeCompat=" + topActivityInSizeCompat - + " locusId= " + mTopActivityLocusId + + " locusId=" + mTopActivityLocusId + + " displayAreaFeatureId=" + displayAreaFeatureId + "}"; } } diff --git a/core/java/android/app/WallpaperInfo.java b/core/java/android/app/WallpaperInfo.java index e9b01750b3b1..99d406446dae 100644 --- a/core/java/android/app/WallpaperInfo.java +++ b/core/java/android/app/WallpaperInfo.java @@ -81,6 +81,7 @@ public final class WallpaperInfo implements Parcelable { final int mContextDescriptionResource; final boolean mShowMetadataInPreview; final boolean mSupportsAmbientMode; + final boolean mShouldUseDefaultUnfoldTransition; final String mSettingsSliceUri; final boolean mSupportMultipleDisplays; @@ -145,6 +146,9 @@ public final class WallpaperInfo implements Parcelable { mSupportsAmbientMode = sa.getBoolean( com.android.internal.R.styleable.Wallpaper_supportsAmbientMode, false); + mShouldUseDefaultUnfoldTransition = sa.getBoolean( + com.android.internal.R.styleable + .Wallpaper_shouldUseDefaultUnfoldTransition, true); mSettingsSliceUri = sa.getString( com.android.internal.R.styleable.Wallpaper_settingsSliceUri); mSupportMultipleDisplays = sa.getBoolean( @@ -171,6 +175,7 @@ public final class WallpaperInfo implements Parcelable { mSupportsAmbientMode = source.readInt() != 0; mSettingsSliceUri = source.readString(); mSupportMultipleDisplays = source.readInt() != 0; + mShouldUseDefaultUnfoldTransition = source.readInt() != 0; mService = ResolveInfo.CREATOR.createFromParcel(source); } @@ -393,6 +398,28 @@ public final class WallpaperInfo implements Parcelable { return mSupportMultipleDisplays; } + /** + * Returns whether this wallpaper should receive default zooming updates when the device + * changes its state (e.g. when folding or unfolding a foldable device). + * If set to false the wallpaper will not receive zoom events when changing the device state, + * so it can implement its own transition instead. + *

+ * This corresponds to the value {@link + * android.R.styleable#Wallpaper_shouldUseDefaultUnfoldTransition} in the + * XML description of the wallpaper. + *

+ * The default value is {@code true}. + * + * @see android.R.styleable#Wallpaper_shouldUseDefaultUnfoldTransition + * @return {@code true} if wallpaper should receive default device state change + * transition updates + * + * @attr ref android.R.styleable#Wallpaper_shouldUseDefaultUnfoldTransition + */ + public boolean shouldUseDefaultUnfoldTransition() { + return mShouldUseDefaultUnfoldTransition; + } + public void dump(Printer pw, String prefix) { pw.println(prefix + "Service:"); mService.dump(pw, prefix + " "); @@ -423,6 +450,7 @@ public final class WallpaperInfo implements Parcelable { dest.writeInt(mSupportsAmbientMode ? 1 : 0); dest.writeString(mSettingsSliceUri); dest.writeInt(mSupportMultipleDisplays ? 1 : 0); + dest.writeInt(mShouldUseDefaultUnfoldTransition ? 1 : 0); mService.writeToParcel(dest, flags); } diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java index 6ad36e19f7a2..b337396ebe5d 100644 --- a/core/java/android/app/WallpaperManager.java +++ b/core/java/android/app/WallpaperManager.java @@ -220,6 +220,20 @@ public class WallpaperManager { */ public static final String COMMAND_REAPPLY = "android.wallpaper.reapply"; + /** + * Command for {@link #sendWallpaperCommand}: reported when the live wallpaper needs to be + * frozen. + * @hide + */ + public static final String COMMAND_FREEZE = "android.wallpaper.freeze"; + + /** + * Command for {@link #sendWallpaperCommand}: reported when the live wallapper doesn't need + * to be frozen anymore. + * @hide + */ + public static final String COMMAND_UNFREEZE = "android.wallpaper.unfreeze"; + /** * Extra passed back from setWallpaper() giving the new wallpaper's assigned ID. * @hide @@ -351,17 +365,18 @@ public class WallpaperManager { private int mCachedWallpaperUserId; private Bitmap mDefaultWallpaper; private Handler mMainLooperHandler; - private ArrayMap> mLocalColorAreas = - new ArrayMap<>(); + private ArrayMap> mLocalColorCallbackAreas = + new ArrayMap<>(); private ILocalWallpaperColorConsumer mLocalColorCallback = new ILocalWallpaperColorConsumer.Stub() { @Override public void onColorsChanged(RectF area, WallpaperColors colors) { - ArraySet callbacks = - mLocalColorAreas.get(area); - if (callbacks == null) return; - for (LocalWallpaperColorConsumer callback: callbacks) { - callback.onColorsChanged(area, colors); + for (LocalWallpaperColorConsumer callback : + mLocalColorCallbackAreas.keySet()) { + ArraySet areas = mLocalColorCallbackAreas.get(callback); + if (areas != null && areas.contains(area)) { + callback.onColorsChanged(area, colors); + } } } }; @@ -406,46 +421,52 @@ public class WallpaperManager { } } - public void addOnColorsChangedListener(@NonNull LocalWallpaperColorConsumer callback, + public void addOnColorsChangedListener( + @NonNull LocalWallpaperColorConsumer callback, @NonNull List regions, int which, int userId, int displayId) { - for (RectF area: regions) { - ArraySet callbacks = mLocalColorAreas.get(area); - if (callbacks == null) { - callbacks = new ArraySet<>(); - mLocalColorAreas.put(area, callbacks); + synchronized (this) { + for (RectF area : regions) { + ArraySet areas = mLocalColorCallbackAreas.get(callback); + if (areas == null) { + areas = new ArraySet<>(); + mLocalColorCallbackAreas.put(callback, areas); + } + areas.add(area); + } + try { + // one way returns immediately + mService.addOnLocalColorsChangedListener(mLocalColorCallback, regions, which, + userId, displayId); + } catch (RemoteException e) { + // Can't get colors, connection lost. + Log.e(TAG, "Can't register for local color updates", e); } - callbacks.add(callback); - } - try { - mService.addOnLocalColorsChangedListener(mLocalColorCallback , regions, which, - userId, displayId); - } catch (RemoteException e) { - // Can't get colors, connection lost. - Log.e(TAG, "Can't register for local color updates", e); } } public void removeOnColorsChangedListener( @NonNull LocalWallpaperColorConsumer callback, int which, int userId, int displayId) { - final ArrayList removeAreas = new ArrayList<>(); - for (RectF area : mLocalColorAreas.keySet()) { - ArraySet callbacks = mLocalColorAreas.get(area); - if (callbacks == null) continue; - callbacks.remove(callback); - if (callbacks.size() == 0) { - mLocalColorAreas.remove(area); - removeAreas.add(area); + synchronized (this) { + final ArraySet removeAreas = mLocalColorCallbackAreas.remove(callback); + if (removeAreas == null || removeAreas.size() == 0) { + return; } - } - try { - if (removeAreas.size() > 0) { - mService.removeOnLocalColorsChangedListener( - mLocalColorCallback, removeAreas, which, userId, displayId); + for (LocalWallpaperColorConsumer cb : mLocalColorCallbackAreas.keySet()) { + ArraySet areas = mLocalColorCallbackAreas.get(cb); + if (areas != null && cb != callback) removeAreas.removeAll(areas); + } + try { + if (removeAreas.size() > 0) { + // one way returns immediately + mService.removeOnLocalColorsChangedListener( + mLocalColorCallback, new ArrayList(removeAreas), which, userId, + displayId); + } + } catch (RemoteException e) { + // Can't get colors, connection lost. + Log.e(TAG, "Can't unregister for local color updates", e); } - } catch (RemoteException e) { - // Can't get colors, connection lost. - Log.e(TAG, "Can't unregister for local color updates", e); } } @@ -556,7 +577,7 @@ public class WallpaperManager { } if (returnDefault) { Bitmap defaultWallpaper = mDefaultWallpaper; - if (defaultWallpaper == null) { + if (defaultWallpaper == null || defaultWallpaper.isRecycled()) { defaultWallpaper = getDefaultWallpaper(context, which); synchronized (this) { mDefaultWallpaper = defaultWallpaper; @@ -580,12 +601,12 @@ public class WallpaperManager { Rect dimensions = null; synchronized (this) { + ParcelFileDescriptor pfd = null; try { Bundle params = new Bundle(); + pfd = mService.getWallpaperWithFeature(context.getOpPackageName(), + context.getAttributionTag(), this, FLAG_SYSTEM, params, userId); // Let's peek user wallpaper first. - ParcelFileDescriptor pfd = mService.getWallpaperWithFeature( - context.getOpPackageName(), context.getAttributionTag(), this, - FLAG_SYSTEM, params, userId); if (pfd != null) { BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; @@ -594,6 +615,13 @@ public class WallpaperManager { } } catch (RemoteException ex) { Log.w(TAG, "peek wallpaper dimensions failed", ex); + } finally { + if (pfd != null) { + try { + pfd.close(); + } catch (IOException ignored) { + } + } } } // If user wallpaper is unavailable, may be the default one instead. diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index 0fe80c45ad2a..3553748e5004 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -679,8 +679,9 @@ public class DevicePolicyManager { * A String extra holding the time zone {@link android.app.AlarmManager} that the device * will be set to. * - *

Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC} that starts device owner - * provisioning via an NFC bump. + *

Use only for device owner provisioning. This extra can be returned by the admin app when + * performing the admin-integrated provisioning flow as a result of the {@link + * #ACTION_GET_PROVISIONING_MODE} activity. */ public static final String EXTRA_PROVISIONING_TIME_ZONE = "android.app.extra.PROVISIONING_TIME_ZONE"; @@ -689,8 +690,9 @@ public class DevicePolicyManager { * A Long extra holding the wall clock time (in milliseconds) to be set on the device's * {@link android.app.AlarmManager}. * - *

Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC} that starts device owner - * provisioning via an NFC bump. + *

Use only for device owner provisioning. This extra can be returned by the admin app when + * performing the admin-integrated provisioning flow as a result of the {@link + * #ACTION_GET_PROVISIONING_MODE} activity. */ public static final String EXTRA_PROVISIONING_LOCAL_TIME = "android.app.extra.PROVISIONING_LOCAL_TIME"; @@ -699,8 +701,9 @@ public class DevicePolicyManager { * A String extra holding the {@link java.util.Locale} that the device will be set to. * Format: xx_yy, where xx is the language code, and yy the country code. * - *

Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC} that starts device owner - * provisioning via an NFC bump. + *

Use only for device owner provisioning. This extra can be returned by the admin app when + * performing the admin-integrated provisioning flow as a result of the {@link + * #ACTION_GET_PROVISIONING_MODE} activity. */ public static final String EXTRA_PROVISIONING_LOCALE = "android.app.extra.PROVISIONING_LOCALE"; @@ -996,7 +999,10 @@ public class DevicePolicyManager { * The default for this extra is {@code false} - by default, the admin of a fully-managed * device has the ability to grant sensors-related permissions. * - *

Use only for device owner provisioning. + *

Use only for device owner provisioning. This extra can be returned by the + * admin app when performing the admin-integrated provisioning flow as a result of the + * {@link #ACTION_GET_PROVISIONING_MODE} activity. + * * @see #ACTION_GET_PROVISIONING_MODE */ public static final String EXTRA_PROVISIONING_SENSORS_PERMISSION_GRANT_OPT_OUT = @@ -1065,6 +1071,9 @@ public class DevicePolicyManager { * *

From {@link android.os.Build.VERSION_CODES#N} onwards, this is also supported for an * intent with action {@link #ACTION_PROVISION_MANAGED_PROFILE}. + * + *

This extra can also be returned by the admin app when performing the admin-integrated + * provisioning flow as a result of the {@link #ACTION_GET_PROVISIONING_MODE} activity. */ public static final String EXTRA_PROVISIONING_SKIP_ENCRYPTION = "android.app.extra.PROVISIONING_SKIP_ENCRYPTION"; @@ -1104,8 +1113,9 @@ public class DevicePolicyManager { * *

Maximum 3 key-value pairs can be specified. The rest will be ignored. * - *

Use in an intent with action {@link #ACTION_PROVISION_MANAGED_PROFILE} or - * {@link #ACTION_PROVISION_MANAGED_DEVICE} + *

Can be used in an intent with action {@link #ACTION_PROVISION_MANAGED_PROFILE}. This + * extra can also be returned by the admin app when performing the admin-integrated + * provisioning flow as a result of the {@link #ACTION_GET_PROVISIONING_MODE} activity. */ public static final String EXTRA_PROVISIONING_DISCLAIMERS = "android.app.extra.PROVISIONING_DISCLAIMERS"; @@ -3437,6 +3447,9 @@ public class DevicePolicyManager { * set on the primary {@link DevicePolicyManager} must be cleared first by calling * {@link #setRequiredPasswordComplexity} with {@link #PASSWORD_COMPLEXITY_NONE) first. * + *

Note: this method is ignored on + * {PackageManager#FEATURE_AUTOMOTIVE automotive builds}. + * * @deprecated Prefer using {@link #setRequiredPasswordComplexity(int)}, to require a password * that satisfies a complexity level defined by the platform, rather than specifying custom * password requirement. @@ -3527,12 +3540,14 @@ public class DevicePolicyManager { * {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD} to be able to call this method; if it has * not, a security exception will be thrown. *

- * * Apps targeting {@link android.os.Build.VERSION_CODES#R} and below can call this method on the * {@link DevicePolicyManager} instance returned by * {@link #getParentProfileInstance(ComponentName)} in order to set restrictions on the parent * profile. * + *

Note: this method is ignored on + * {PackageManager#FEATURE_AUTOMOTIVE automotive builds}. + * * @deprecated see {@link #setPasswordQuality(ComponentName, int)} for details. * * @param admin Which {@link DeviceAdminReceiver} this request is associated with. @@ -3610,12 +3625,14 @@ public class DevicePolicyManager { * {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD} to be able to call this method; if it has * not, a security exception will be thrown. *

- * * Apps targeting {@link android.os.Build.VERSION_CODES#R} and below can call this method on the * {@link DevicePolicyManager} instance returned by * {@link #getParentProfileInstance(ComponentName)} in order to set restrictions on the parent * profile. * + *

Note: this method is ignored on + * {PackageManager#FEATURE_AUTOMOTIVE automotive builds}. + * * @deprecated see {@link #setPasswordQuality(ComponentName, int)} for details. * * @param admin Which {@link DeviceAdminReceiver} this request is associated with. @@ -3700,12 +3717,14 @@ public class DevicePolicyManager { * {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD} to be able to call this method; if it has * not, a security exception will be thrown. *

- * * Apps targeting {@link android.os.Build.VERSION_CODES#R} and below can call this method on the * {@link DevicePolicyManager} instance returned by * {@link #getParentProfileInstance(ComponentName)} in order to set restrictions on the parent * profile. * + *

Note: this method is ignored on + * {PackageManager#FEATURE_AUTOMOTIVE automotive builds}. + * * @deprecated see {@link #setPasswordQuality(ComponentName, int)} for details. * * @param admin Which {@link DeviceAdminReceiver} this request is associated with. @@ -3790,12 +3809,14 @@ public class DevicePolicyManager { * {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD} to be able to call this method; if it has * not, a security exception will be thrown. *

- * * Apps targeting {@link android.os.Build.VERSION_CODES#R} and below can call this method on the * {@link DevicePolicyManager} instance returned by * {@link #getParentProfileInstance(ComponentName)} in order to set restrictions on the parent * profile. * + *

Note: this method is ignored on + * {PackageManager#FEATURE_AUTOMOTIVE automotive builds}. + * * @deprecated see {@link #setPasswordQuality(ComponentName, int)} for details. * * @param admin Which {@link DeviceAdminReceiver} this request is associated with. @@ -3879,12 +3900,14 @@ public class DevicePolicyManager { * {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD} to be able to call this method; if it has * not, a security exception will be thrown. *

- * * Apps targeting {@link android.os.Build.VERSION_CODES#R} and below can call this method on the * {@link DevicePolicyManager} instance returned by * {@link #getParentProfileInstance(ComponentName)} in order to set restrictions on the parent * profile. * + *

Note: this method is ignored on + * {PackageManager#FEATURE_AUTOMOTIVE automotive builds}. + * * @deprecated see {@link #setPasswordQuality(ComponentName, int)} for details. * * @param admin Which {@link DeviceAdminReceiver} this request is associated with. @@ -3968,12 +3991,14 @@ public class DevicePolicyManager { * {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD} to be able to call this method; if it has * not, a security exception will be thrown. *

- * * Apps targeting {@link android.os.Build.VERSION_CODES#R} and below can call this method on the * {@link DevicePolicyManager} instance returned by * {@link #getParentProfileInstance(ComponentName)} in order to set restrictions on the parent * profile. * + *

Note: this method is ignored on + * {PackageManager#FEATURE_AUTOMOTIVE automotive builds}. + * * @deprecated see {@link #setPasswordQuality(ComponentName, int)} for details. * * @param admin Which {@link DeviceAdminReceiver} this request is associated with. @@ -4056,12 +4081,14 @@ public class DevicePolicyManager { * {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD} to be able to call this method; if it has * not, a security exception will be thrown. *

- * * Apps targeting {@link android.os.Build.VERSION_CODES#R} and below can call this method on the * {@link DevicePolicyManager} instance returned by * {@link #getParentProfileInstance(ComponentName)} in order to set restrictions on the parent * profile. * + *

Note: this method is ignored on + * {PackageManager#FEATURE_AUTOMOTIVE automotive builds}. + * * @deprecated see {@link #setPasswordQuality(ComponentName, int)} for details. * * @param admin Which {@link DeviceAdminReceiver} this request is associated with. @@ -7726,27 +7753,64 @@ public class DevicePolicyManager { } /** - * @hide - * Sets the given package as the device owner. The package must already be installed. There - * must not already be a device owner. - * Only apps with the MANAGE_PROFILE_AND_DEVICE_OWNERS permission and the shell uid can call - * this method. - * Calling this after the setup phase of the primary user has completed is allowed only if - * the caller is the shell uid, and there are no additional users and no accounts. + * Sets the given package as the device owner. + * + *

Preconditions: + *

    + *
  • The package must already be installed. + *
  • There must not already be a device owner. + *
  • Only apps with the {@code MANAGE_PROFILE_AND_DEVICE_OWNERS} permission or the + * {@link Process#SHELL_UID Shell UID} can call this method. + *
+ * + *

Calling this after the setup phase of the device owner user has completed is allowed only + * if the caller is the {@link Process#SHELL_UID Shell UID}, and there are no additional users + * (except when the device runs on headless system user mode, in which case it could have exact + * one extra user, which is the current user - the device owner will be set in the + * {@link UserHandle#SYSTEM system} user and a profile owner will be set in the current user) + * and no accounts. + * * @param who the component name to be registered as device owner. * @param ownerName the human readable name of the institution that owns this device. * @param userId ID of the user on which the device owner runs. + * * @return whether the package was successfully registered as the device owner. - * @throws IllegalArgumentException if the package name is null or invalid + * + * @throws IllegalArgumentException if the package name is {@code null} or invalid. * @throws IllegalStateException If the preconditions mentioned are not met. + * + * @hide */ @TestApi @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) - public boolean setDeviceOwner( + public boolean setDeviceOwner(@NonNull ComponentName who, @Nullable String ownerName, + @UserIdInt int userId) { + if (mService != null) { + try { + return mService.setDeviceOwner(who, ownerName, userId, + /* setProfileOwnerOnCurrentUserIfNecessary= */ true); + } catch (RemoteException re) { + throw re.rethrowFromSystemServer(); + } + } + return false; + } + + /** + * Same as {@link #setDeviceOwner(ComponentName, String, int)}, but without setting the profile + * owner on current user when running on headless system user mode - should be used only by + * testing infra. + * + * @hide + */ + @TestApi + @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) + public boolean setDeviceOwnerOnly( @NonNull ComponentName who, @Nullable String ownerName, @UserIdInt int userId) { if (mService != null) { try { - return mService.setDeviceOwner(who, ownerName, userId); + return mService.setDeviceOwner(who, ownerName, userId, + /* setProfileOwnerOnCurrentUserIfNecessary= */ false); } catch (RemoteException re) { throw re.rethrowFromSystemServer(); } @@ -9528,7 +9592,14 @@ public class DevicePolicyManager { /** * Called by a profile owner of secondary user that is affiliated with the device to stop the - * calling user and switch back to primary. + * calling user and switch back to primary user. + * + *

Notice that on devices running with + * {@link UserManager#isHeadlessSystemUserMode() headless system user mode}, there is no primary + * user, so it switches back to the user that was in the foreground before the first call to + * {@link #switchUser(ComponentName, UserHandle)} (or fails with + * {@link UserManager#USER_OPERATION_ERROR_UNKNOWN} if that method was not called prior to this + * call). * * @param admin Which {@link DeviceAdminReceiver} this request is associated with. * @return one of the following result codes: @@ -9548,6 +9619,37 @@ public class DevicePolicyManager { } } + /** + * Gets the user a {@link #logoutUser(ComponentName)} call would switch to, + * or {@link UserHandle#USER_NULL} if the current user is not in a session. + * + * @hide + */ + @RequiresPermission(android.Manifest.permission.MANAGE_USERS) + public @UserIdInt int getLogoutUserId() { + try { + return mService.getLogoutUserId(); + } catch (RemoteException re) { + throw re.rethrowFromSystemServer(); + } + } + + /** + * Clears the user that {@link #logoutUser(ComponentName)} would switch to. + * + *

Typically used by system UI after it logout a session. + * + * @hide + */ + @RequiresPermission(android.Manifest.permission.MANAGE_USERS) + public void clearLogoutUser() { + try { + mService.clearLogoutUser(); + } catch (RemoteException re) { + throw re.rethrowFromSystemServer(); + } + } + /** * Called by a device owner to list all secondary users on the device. Managed profiles are not * considered as secondary users. @@ -13760,6 +13862,23 @@ public class DevicePolicyManager { } } + /** + * Clears organization ID set by the DPC and resets the precomputed enrollment specific ID. + * @hide + */ + @TestApi + @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) + public void clearOrganizationId() { + if (mService == null) { + return; + } + try { + mService.clearOrganizationIdForUser(myUserId()); + } catch (RemoteException re) { + throw re.rethrowFromSystemServer(); + } + } + /** * Creates and provisions a managed profile and sets the * {@link ManagedProfileProvisioningParams#getProfileAdminComponentName()} as the profile diff --git a/core/java/android/app/admin/EnterprisePlatformSecurity_OWNERS b/core/java/android/app/admin/EnterprisePlatformSecurity_OWNERS new file mode 100644 index 000000000000..f5604347065e --- /dev/null +++ b/core/java/android/app/admin/EnterprisePlatformSecurity_OWNERS @@ -0,0 +1,4 @@ +rubinxu@google.com +acjohnston@google.com +pgrafov@google.com +alexkershaw@google.com #{LAST_RESORT_SUGGESTION} \ No newline at end of file diff --git a/core/java/android/app/admin/EnterprisePlatform_OWNERS b/core/java/android/app/admin/EnterprisePlatform_OWNERS new file mode 100644 index 000000000000..fb00fe506ed1 --- /dev/null +++ b/core/java/android/app/admin/EnterprisePlatform_OWNERS @@ -0,0 +1,2 @@ +file:WorkDeviceExperience_OWNERS +file:EnterprisePlatformSecurity_OWNERS \ No newline at end of file diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl index b5b3934035e0..7c7478bdb41f 100644 --- a/core/java/android/app/admin/IDevicePolicyManager.aidl +++ b/core/java/android/app/admin/IDevicePolicyManager.aidl @@ -159,7 +159,7 @@ interface IDevicePolicyManager { void reportKeyguardDismissed(int userHandle); void reportKeyguardSecured(int userHandle); - boolean setDeviceOwner(in ComponentName who, String ownerName, int userId); + boolean setDeviceOwner(in ComponentName who, String ownerName, int userId, boolean setProfileOwnerOnCurrentUserIfNecessary); ComponentName getDeviceOwnerComponent(boolean callingUserOnly); boolean hasDeviceOwner(); String getDeviceOwnerName(); @@ -261,6 +261,8 @@ interface IDevicePolicyManager { int startUserInBackground(in ComponentName who, in UserHandle userHandle); int stopUser(in ComponentName who, in UserHandle userHandle); int logoutUser(in ComponentName who); + int getLogoutUserId(); + void clearLogoutUser(); List getSecondaryUsers(in ComponentName who); void resetNewUserDisclaimer(); @@ -378,6 +380,7 @@ interface IDevicePolicyManager { void setOrganizationColor(in ComponentName admin, in int color); void setOrganizationColorForUser(in int color, in int userId); + void clearOrganizationIdForUser(int userHandle); int getOrganizationColor(in ComponentName admin); int getOrganizationColorForUser(int userHandle); diff --git a/core/java/android/app/admin/OWNERS b/core/java/android/app/admin/OWNERS index 6acbef29bec3..10a5f14dca9e 100644 --- a/core/java/android/app/admin/OWNERS +++ b/core/java/android/app/admin/OWNERS @@ -1,11 +1,5 @@ # Bug component: 142675 -# Android Enterprise team -rubinxu@google.com -sandness@google.com -alexkershaw@google.com -pgrafov@google.com +file:EnterprisePlatform_OWNERS -# Emeritus -yamasani@google.com -eranm@google.com +yamasani@google.com #{LAST_RESORT_SUGGESTION} \ No newline at end of file diff --git a/core/java/android/app/admin/WorkDeviceExperience_OWNERS b/core/java/android/app/admin/WorkDeviceExperience_OWNERS new file mode 100644 index 000000000000..dcacaa25a236 --- /dev/null +++ b/core/java/android/app/admin/WorkDeviceExperience_OWNERS @@ -0,0 +1,5 @@ +work-device-experience+reviews@google.com +scottjonathan@google.com +arangelov@google.com +kholoudm@google.com +alexkershaw@google.com #{LAST_RESORT_SUGGESTION} \ No newline at end of file diff --git a/core/java/android/app/compat/PackageOverride.java b/core/java/android/app/compat/PackageOverride.java index fad6cd311021..ebc2945fb1a0 100644 --- a/core/java/android/app/compat/PackageOverride.java +++ b/core/java/android/app/compat/PackageOverride.java @@ -24,6 +24,7 @@ import android.os.Parcel; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.util.Objects; /** * An app compat override applied to a given package and change id pairing. @@ -137,6 +138,22 @@ public final class PackageOverride { return new PackageOverride(in.readLong(), in.readLong(), in.readBoolean()); } + /** @hide */ + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + PackageOverride that = (PackageOverride) o; + return mMinVersionCode == that.mMinVersionCode && mMaxVersionCode == that.mMaxVersionCode + && mEnabled == that.mEnabled; + } + + /** @hide */ + @Override + public int hashCode() { + return Objects.hash(mMinVersionCode, mMaxVersionCode, mEnabled); + } + /** @hide */ @Override public String toString() { diff --git a/core/java/android/app/servertransaction/ActivityResultItem.java b/core/java/android/app/servertransaction/ActivityResultItem.java index e059f177e344..27d104b59284 100644 --- a/core/java/android/app/servertransaction/ActivityResultItem.java +++ b/core/java/android/app/servertransaction/ActivityResultItem.java @@ -16,6 +16,8 @@ package android.app.servertransaction; +import static android.app.servertransaction.ActivityLifecycleItem.ON_RESUME; +import static android.app.servertransaction.ActivityLifecycleItem.UNDEFINED; import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER; import android.annotation.NonNull; @@ -23,6 +25,9 @@ import android.annotation.Nullable; import android.app.ActivityThread.ActivityClientRecord; import android.app.ClientTransactionHandler; import android.app.ResultInfo; +import android.app.compat.CompatChanges; +import android.compat.annotation.ChangeId; +import android.compat.annotation.EnabledAfter; import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; import android.os.Parcel; @@ -41,11 +46,19 @@ public class ActivityResultItem extends ActivityTransactionItem { @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) private List mResultInfoList; - /* TODO(b/78294732) + /** + * Correct the lifecycle of activity result after {@link android.os.Build.VERSION_CODES#S} to + * guarantee that an activity gets activity result just before resume. + */ + @ChangeId + @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.S) + public static final long CALL_ACTIVITY_RESULT_BEFORE_RESUME = 78294732L; + @Override public int getPostExecutionState() { - return ON_RESUME; - }*/ + return CompatChanges.isChangeEnabled(CALL_ACTIVITY_RESULT_BEFORE_RESUME) + ? ON_RESUME : UNDEFINED; + } @Override public void execute(ClientTransactionHandler client, ActivityClientRecord r, diff --git a/core/java/android/app/servertransaction/ActivityTransactionItem.java b/core/java/android/app/servertransaction/ActivityTransactionItem.java index a539812fa8c6..186f25deab67 100644 --- a/core/java/android/app/servertransaction/ActivityTransactionItem.java +++ b/core/java/android/app/servertransaction/ActivityTransactionItem.java @@ -59,36 +59,37 @@ public abstract class ActivityTransactionItem extends ClientTransactionItem { } /** - * Get the {@link ActivityClientRecord} instance that corresponds to the provided token. + * Gets the {@link ActivityClientRecord} instance that corresponds to the provided token. * @param client Target client handler. * @param token Target activity token. - * @param includeLaunching Indicate to also find the {@link ActivityClientRecord} in launching - * activity list. It should be noted that there is no activity in + * @param includeLaunching Indicate to find the {@link ActivityClientRecord} in launching + * activity list. + *

Note that there is no {@link android.app.Activity} instance in * {@link ActivityClientRecord} from the launching activity list. * @return The {@link ActivityClientRecord} instance that corresponds to the provided token. */ @NonNull ActivityClientRecord getActivityClientRecord( @NonNull ClientTransactionHandler client, IBinder token, boolean includeLaunching) { - ActivityClientRecord r = client.getActivityClient(token); - if (r != null) { - if (client.getActivity(token) == null) { + ActivityClientRecord r = null; + // Check launching Activity first to prevent race condition that activity instance has not + // yet set to ActivityClientRecord. + if (includeLaunching) { + r = client.getLaunchingActivity(token); + } + // Then if we don't want to find launching Activity or the ActivityClientRecord doesn't + // exist in launching Activity list. The ActivityClientRecord should have been initialized + // and put in the Activity list. + if (r == null) { + r = client.getActivityClient(token); + if (r != null && client.getActivity(token) == null) { throw new IllegalArgumentException("Activity must not be null to execute " + "transaction item"); } - return r; - } - // The activity may not be launched yet. Fallback to check launching activity. - if (includeLaunching) { - r = client.getLaunchingActivity(token); } if (r == null) { throw new IllegalArgumentException("Activity client record must not be null to execute " + "transaction item"); } - - // We don't need to check the activity of launching activity client records because they - // have not been launched yet. - return r; } } diff --git a/core/java/android/app/servertransaction/TransferSplashScreenViewStateItem.java b/core/java/android/app/servertransaction/TransferSplashScreenViewStateItem.java index 5374984d31d0..767fd28b8a2a 100644 --- a/core/java/android/app/servertransaction/TransferSplashScreenViewStateItem.java +++ b/core/java/android/app/servertransaction/TransferSplashScreenViewStateItem.java @@ -16,17 +16,14 @@ package android.app.servertransaction; -import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityThread; import android.app.ClientTransactionHandler; import android.os.Parcel; +import android.view.SurfaceControl; import android.window.SplashScreenView.SplashScreenViewParcelable; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - /** * Transfer a splash screen view to an Activity. * @hide @@ -34,31 +31,13 @@ import java.lang.annotation.RetentionPolicy; public class TransferSplashScreenViewStateItem extends ActivityTransactionItem { private SplashScreenViewParcelable mSplashScreenViewParcelable; - private @TransferRequest int mRequest; - - @IntDef(value = { - ATTACH_TO, - HANDOVER_TO - }) - @Retention(RetentionPolicy.SOURCE) - public @interface TransferRequest {} - // request client to attach the view on it. - public static final int ATTACH_TO = 0; - // tell client that you can handle the splash screen view. - public static final int HANDOVER_TO = 1; + private SurfaceControl mStartingWindowLeash; @Override public void execute(@NonNull ClientTransactionHandler client, @NonNull ActivityThread.ActivityClientRecord r, PendingTransactionActions pendingActions) { - switch (mRequest) { - case ATTACH_TO: - client.handleAttachSplashScreenView(r, mSplashScreenViewParcelable); - break; - case HANDOVER_TO: - client.handOverSplashScreenView(r); - break; - } + client.handleAttachSplashScreenView(r, mSplashScreenViewParcelable, mStartingWindowLeash); } @Override @@ -68,26 +47,27 @@ public class TransferSplashScreenViewStateItem extends ActivityTransactionItem { @Override public void writeToParcel(Parcel dest, int flags) { - dest.writeInt(mRequest); dest.writeTypedObject(mSplashScreenViewParcelable, flags); + dest.writeTypedObject(mStartingWindowLeash, flags); } private TransferSplashScreenViewStateItem() {} private TransferSplashScreenViewStateItem(Parcel in) { - mRequest = in.readInt(); mSplashScreenViewParcelable = in.readTypedObject(SplashScreenViewParcelable.CREATOR); + mStartingWindowLeash = in.readTypedObject(SurfaceControl.CREATOR); } /** Obtain an instance initialized with provided params. */ - public static TransferSplashScreenViewStateItem obtain(@TransferRequest int state, - @Nullable SplashScreenViewParcelable parcelable) { + public static TransferSplashScreenViewStateItem obtain( + @Nullable SplashScreenViewParcelable parcelable, + @Nullable SurfaceControl startingWindowLeash) { TransferSplashScreenViewStateItem instance = ObjectPool.obtain(TransferSplashScreenViewStateItem.class); if (instance == null) { instance = new TransferSplashScreenViewStateItem(); } - instance.mRequest = state; instance.mSplashScreenViewParcelable = parcelable; + instance.mStartingWindowLeash = startingWindowLeash; return instance; } diff --git a/core/java/android/appwidget/AppWidgetHostView.java b/core/java/android/appwidget/AppWidgetHostView.java index 8aa27853b462..8be2b4873c67 100644 --- a/core/java/android/appwidget/AppWidgetHostView.java +++ b/core/java/android/appwidget/AppWidgetHostView.java @@ -20,6 +20,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.app.Activity; import android.app.ActivityOptions; +import android.app.LoadedApk; import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Context; @@ -96,7 +97,8 @@ public class AppWidgetHostView extends FrameLayout { AppWidgetProviderInfo mInfo; View mView; int mViewMode = VIEW_MODE_NOINIT; - int mLayoutId = -1; + // If true, we should not try to re-apply the RemoteViews on the next inflation. + boolean mColorMappingChanged = false; private InteractionHandler mInteractionHandler; private boolean mOnLightBackground; private SizeF mCurrentSize = null; @@ -539,7 +541,6 @@ public class AppWidgetHostView extends FrameLayout { return; } content = getDefaultView(); - mLayoutId = -1; mViewMode = VIEW_MODE_DEFAULT; } else { // Select the remote view we are actually going to apply. @@ -552,8 +553,11 @@ public class AppWidgetHostView extends FrameLayout { inflateAsync(rvToApply); return; } - int layoutId = rvToApply.getLayoutId(); - if (rvToApply.canRecycleView(mView)) { + // Prepare a local reference to the remote Context so we're ready to + // inflate any requested LayoutParams. + mRemoteContext = getRemoteContextEnsuringCorrectCachedApkPath(); + + if (!mColorMappingChanged && rvToApply.canRecycleView(mView)) { try { rvToApply.reapply(mContext, mView, mInteractionHandler, mCurrentSize, mColorResources); @@ -578,7 +582,6 @@ public class AppWidgetHostView extends FrameLayout { } } - mLayoutId = layoutId; mViewMode = VIEW_MODE_CONTENT; } @@ -586,6 +589,7 @@ public class AppWidgetHostView extends FrameLayout { } private void applyContent(View content, boolean recycled, Exception exception) { + mColorMappingChanged = false; if (content == null) { if (mViewMode == VIEW_MODE_ERROR) { // We've already done this -- nothing to do. @@ -612,7 +616,7 @@ public class AppWidgetHostView extends FrameLayout { private void inflateAsync(@NonNull RemoteViews remoteViews) { // Prepare a local reference to the remote Context so we're ready to // inflate any requested LayoutParams. - mRemoteContext = getRemoteContext(); + mRemoteContext = getRemoteContextEnsuringCorrectCachedApkPath(); int layoutId = remoteViews.getLayoutId(); if (mLastExecutionSignal != null) { @@ -621,7 +625,7 @@ public class AppWidgetHostView extends FrameLayout { // If our stale view has been prepared to match active, and the new // layout matches, try recycling it - if (layoutId == mLayoutId && mView != null) { + if (!mColorMappingChanged && remoteViews.canRecycleView(mView)) { try { mLastExecutionSignal = remoteViews.reapplyAsync(mContext, mView, @@ -661,7 +665,6 @@ public class AppWidgetHostView extends FrameLayout { @Override public void onViewApplied(View v) { - AppWidgetHostView.this.mLayoutId = mLayoutId; mViewMode = VIEW_MODE_CONTENT; applyContent(v, mIsReapply, null); @@ -714,8 +717,10 @@ public class AppWidgetHostView extends FrameLayout { * purposes of reading remote resources. * @hide */ - protected Context getRemoteContext() { + protected Context getRemoteContextEnsuringCorrectCachedApkPath() { try { + ApplicationInfo expectedAppInfo = mInfo.providerInfo.applicationInfo; + LoadedApk.checkAndUpdateApkPaths(expectedAppInfo); // Return if cloned successfully, otherwise default Context newContext = mContext.createApplicationContext( mInfo.providerInfo.applicationInfo, @@ -727,6 +732,9 @@ public class AppWidgetHostView extends FrameLayout { } catch (NameNotFoundException e) { Log.e(TAG, "Package name " + mInfo.providerInfo.packageName + " not found"); return mContext; + } catch (NullPointerException e) { + Log.e(TAG, "Error trying to create the remote context.", e); + return mContext; } } @@ -758,7 +766,7 @@ public class AppWidgetHostView extends FrameLayout { try { if (mInfo != null) { - Context theirContext = getRemoteContext(); + Context theirContext = getRemoteContextEnsuringCorrectCachedApkPath(); mRemoteContext = theirContext; LayoutInflater inflater = (LayoutInflater) theirContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); @@ -897,7 +905,7 @@ public class AppWidgetHostView extends FrameLayout { } mColorMapping = colorMapping.clone(); mColorResources = RemoteViews.ColorResources.create(mContext, mColorMapping); - mLayoutId = -1; + mColorMappingChanged = true; mViewMode = VIEW_MODE_NOINIT; reapplyLastRemoteViews(); } @@ -927,7 +935,7 @@ public class AppWidgetHostView extends FrameLayout { if (mColorResources != null) { mColorResources = null; mColorMapping = null; - mLayoutId = -1; + mColorMappingChanged = true; mViewMode = VIEW_MODE_NOINIT; reapplyLastRemoteViews(); } diff --git a/core/java/android/companion/CompanionDeviceManager.java b/core/java/android/companion/CompanionDeviceManager.java index b99ad5125149..32c491753af4 100644 --- a/core/java/android/companion/CompanionDeviceManager.java +++ b/core/java/android/companion/CompanionDeviceManager.java @@ -108,7 +108,7 @@ public final class CompanionDeviceManager { } private final ICompanionDeviceManager mService; - private final Context mContext; + private Context mContext; /** @hide */ public CompanionDeviceManager( @@ -541,6 +541,7 @@ public final class CompanionDeviceManager { mCallback = null; mHandler = null; mRequest = null; + mContext = null; } } diff --git a/core/java/android/companion/ICompanionDeviceDiscoveryService.aidl b/core/java/android/companion/ICompanionDeviceDiscoveryService.aidl index a630873c7f67..e1c13f7fc9e1 100644 --- a/core/java/android/companion/ICompanionDeviceDiscoveryService.aidl +++ b/core/java/android/companion/ICompanionDeviceDiscoveryService.aidl @@ -29,4 +29,6 @@ oneway interface ICompanionDeviceDiscoveryService { in String callingPackage, in IFindDeviceCallback findCallback, in AndroidFuture serviceCallback); + + void onAssociationCreated(); } diff --git a/core/java/android/content/ClipDescription.java b/core/java/android/content/ClipDescription.java index f49362e9300e..2ecd71bc1f06 100644 --- a/core/java/android/content/ClipDescription.java +++ b/core/java/android/content/ClipDescription.java @@ -124,6 +124,16 @@ public class ClipDescription implements Parcelable { */ public static final String EXTRA_ACTIVITY_OPTIONS = "android.intent.extra.ACTIVITY_OPTIONS"; + /** + * An instance id used for logging. + *

+ * Type: {@link com.android.internal.logging.InstanceId} + *

+ * @hide + */ + public static final String EXTRA_LOGGING_INSTANCE_ID = + "android.intent.extra.LOGGING_INSTANCE_ID"; + /** @hide */ @Retention(RetentionPolicy.SOURCE) @IntDef(value = diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index c3ec09466de6..7f2a740d3228 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -3246,7 +3246,11 @@ public abstract class Context { * Service will call {@link android.app.Service#startForeground(int, android.app.Notification) * startForeground(int, android.app.Notification)} once it begins running. The service is given * an amount of time comparable to the ANR interval to do this, otherwise the system - * will automatically stop the service and declare the app ANR. + * will automatically crash the process, in which case an internal exception + * {@code ForegroundServiceDidNotStartInTimeException} is logged on logcat on devices + * running SDK Version {@link android.os.Build.VERSION_CODES#S} or later. On older Android + * versions, an internal exception {@code RemoteServiceException} is logged instead, with + * a corresponding message. * *

Unlike the ordinary {@link #startService(Intent)}, this method can be used * at any time, regardless of whether the app hosting the service is in a foreground diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java index 95c5612aeee4..d1ef5917ba47 100644 --- a/core/java/android/content/pm/ActivityInfo.java +++ b/core/java/android/content/pm/ActivityInfo.java @@ -22,6 +22,7 @@ import android.app.Activity; import android.app.compat.CompatChanges; import android.compat.annotation.ChangeId; import android.compat.annotation.Disabled; +import android.compat.annotation.EnabledSince; import android.compat.annotation.Overridable; import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; @@ -994,9 +995,9 @@ public class ActivityInfo extends ComponentInfo implements Parcelable { * OVERRIDE_MIN_ASPECT_RATIO_MEDIUM * OVERRIDE_MIN_ASPECT_RATIO_LARGE * - * If OVERRIDE_MIN_ASPECT_RATIO is applied, the min aspect ratio given in the app's - * manifest will be overridden to the largest enabled aspect ratio treatment unless the app's - * manifest value is higher. + * If OVERRIDE_MIN_ASPECT_RATIO is applied, the min aspect ratio given in the app's manifest + * will be overridden to the largest enabled aspect ratio treatment unless the app's manifest + * value is higher. * @hide */ @ChangeId @@ -1005,6 +1006,19 @@ public class ActivityInfo extends ComponentInfo implements Parcelable { @TestApi public static final long OVERRIDE_MIN_ASPECT_RATIO = 174042980L; // buganizer id + /** + * This change id restricts treatments that force a given min aspect ratio to activities + * whose orientation is fixed to portrait. + * + * This treatment is enabled by default and only takes effect if OVERRIDE_MIN_ASPECT_RATIO is + * also enabled. + * @hide + */ + @ChangeId + @Overridable + @TestApi + public static final long OVERRIDE_MIN_ASPECT_RATIO_PORTRAIT_ONLY = 203647190L; // buganizer id + /** * This change id sets the activity's min aspect ratio to a medium value as defined by * OVERRIDE_MIN_ASPECT_RATIO_MEDIUM_VALUE. @@ -1039,6 +1053,14 @@ public class ActivityInfo extends ComponentInfo implements Parcelable { @TestApi public static final float OVERRIDE_MIN_ASPECT_RATIO_LARGE_VALUE = 16 / 9f; + /** + * Compares activity window layout min width/height with require space for multi window to + * determine if it can be put into multi window mode. + */ + @ChangeId + @EnabledSince(targetSdkVersion = Build.VERSION_CODES.S) + private static final long CHECK_MIN_WIDTH_HEIGHT_FOR_MULTI_WINDOW = 197654537L; + /** * Convert Java change bits to native. * @@ -1232,8 +1254,8 @@ public class ActivityInfo extends ComponentInfo implements Parcelable { * Returns true if the activity has maximum or minimum aspect ratio. * @hide */ - public boolean hasFixedAspectRatio() { - return getMaxAspectRatio() != 0 || getMinAspectRatio() != 0; + public boolean hasFixedAspectRatio(@ScreenOrientation int orientation) { + return getMaxAspectRatio() != 0 || getMinAspectRatio(orientation) != 0; } /** @@ -1326,9 +1348,7 @@ public class ActivityInfo extends ComponentInfo implements Parcelable { */ @SizeChangesSupportMode public int supportsSizeChanges() { - if (CompatChanges.isChangeEnabled(FORCE_NON_RESIZE_APP, - applicationInfo.packageName, - UserHandle.getUserHandleForUid(applicationInfo.uid))) { + if (isChangeEnabled(FORCE_NON_RESIZE_APP)) { return SIZE_CHANGES_UNSUPPORTED_OVERRIDE; } @@ -1336,9 +1356,7 @@ public class ActivityInfo extends ComponentInfo implements Parcelable { return SIZE_CHANGES_SUPPORTED_METADATA; } - if (CompatChanges.isChangeEnabled(FORCE_RESIZE_APP, - applicationInfo.packageName, - UserHandle.getUserHandleForUid(applicationInfo.uid))) { + if (isChangeEnabled(FORCE_RESIZE_APP)) { return SIZE_CHANGES_SUPPORTED_OVERRIDE; } @@ -1349,22 +1367,18 @@ public class ActivityInfo extends ComponentInfo implements Parcelable { * Returns if the activity should never be sandboxed to the activity window bounds. * @hide */ - public boolean neverSandboxDisplayApis() { - return CompatChanges.isChangeEnabled(NEVER_SANDBOX_DISPLAY_APIS, - applicationInfo.packageName, - UserHandle.getUserHandleForUid(applicationInfo.uid)) - || ConstrainDisplayApisConfig.neverConstrainDisplayApis(applicationInfo); + public boolean neverSandboxDisplayApis(ConstrainDisplayApisConfig constrainDisplayApisConfig) { + return isChangeEnabled(NEVER_SANDBOX_DISPLAY_APIS) + || constrainDisplayApisConfig.getNeverConstrainDisplayApis(applicationInfo); } /** * Returns if the activity should always be sandboxed to the activity window bounds. * @hide */ - public boolean alwaysSandboxDisplayApis() { - return CompatChanges.isChangeEnabled(ALWAYS_SANDBOX_DISPLAY_APIS, - applicationInfo.packageName, - UserHandle.getUserHandleForUid(applicationInfo.uid)) - || ConstrainDisplayApisConfig.alwaysConstrainDisplayApis(applicationInfo); + public boolean alwaysSandboxDisplayApis(ConstrainDisplayApisConfig constrainDisplayApisConfig) { + return isChangeEnabled(ALWAYS_SANDBOX_DISPLAY_APIS) + || constrainDisplayApisConfig.getAlwaysConstrainDisplayApis(applicationInfo); } /** @hide */ @@ -1392,28 +1406,29 @@ public class ActivityInfo extends ComponentInfo implements Parcelable { * {@code getManifestMinAspectRatio}. * @hide */ - public float getMinAspectRatio() { - if (applicationInfo == null || !CompatChanges.isChangeEnabled(OVERRIDE_MIN_ASPECT_RATIO, - applicationInfo.packageName, - UserHandle.getUserHandleForUid(applicationInfo.uid))) { + public float getMinAspectRatio(@ScreenOrientation int orientation) { + if (applicationInfo == null || !isChangeEnabled(OVERRIDE_MIN_ASPECT_RATIO) || ( + isChangeEnabled(OVERRIDE_MIN_ASPECT_RATIO_PORTRAIT_ONLY) + && !isFixedOrientationPortrait(orientation))) { return mMinAspectRatio; } - if (CompatChanges.isChangeEnabled(OVERRIDE_MIN_ASPECT_RATIO_LARGE, - applicationInfo.packageName, - UserHandle.getUserHandleForUid(applicationInfo.uid))) { + if (isChangeEnabled(OVERRIDE_MIN_ASPECT_RATIO_LARGE)) { return Math.max(OVERRIDE_MIN_ASPECT_RATIO_LARGE_VALUE, mMinAspectRatio); } - if (CompatChanges.isChangeEnabled(OVERRIDE_MIN_ASPECT_RATIO_MEDIUM, - applicationInfo.packageName, - UserHandle.getUserHandleForUid(applicationInfo.uid))) { + if (isChangeEnabled(OVERRIDE_MIN_ASPECT_RATIO_MEDIUM)) { return Math.max(OVERRIDE_MIN_ASPECT_RATIO_MEDIUM_VALUE, mMinAspectRatio); } return mMinAspectRatio; } + private boolean isChangeEnabled(long changeId) { + return CompatChanges.isChangeEnabled(changeId, applicationInfo.packageName, + UserHandle.getUserHandleForUid(applicationInfo.uid)); + } + /** @hide */ public float getManifestMinAspectRatio() { return mMinAspectRatio; @@ -1475,6 +1490,15 @@ public class ActivityInfo extends ComponentInfo implements Parcelable { } } + /** + * Whether we should compare activity window layout min width/height with require space for + * multi window to determine if it can be put into multi window mode. + * @hide + */ + public boolean shouldCheckMinWidthHeightForMultiWindow() { + return isChangeEnabled(CHECK_MIN_WIDTH_HEIGHT_FOR_MULTI_WINDOW); + } + public void dump(Printer pw, String prefix) { dump(pw, prefix, DUMP_FLAG_ALL); } @@ -1521,9 +1545,10 @@ public class ActivityInfo extends ComponentInfo implements Parcelable { if (getMaxAspectRatio() != 0) { pw.println(prefix + "maxAspectRatio=" + getMaxAspectRatio()); } - if (getMinAspectRatio() != 0) { - pw.println(prefix + "minAspectRatio=" + getMinAspectRatio()); - if (getManifestMinAspectRatio() != getMinAspectRatio()) { + final float minAspectRatio = getMinAspectRatio(screenOrientation); + if (minAspectRatio != 0) { + pw.println(prefix + "minAspectRatio=" + minAspectRatio); + if (getManifestMinAspectRatio() != minAspectRatio) { pw.println(prefix + "getManifestMinAspectRatio=" + getManifestMinAspectRatio()); } } diff --git a/core/java/android/content/pm/ConstrainDisplayApisConfig.java b/core/java/android/content/pm/ConstrainDisplayApisConfig.java index 11ba3d4ba9a2..98b73aa8860a 100644 --- a/core/java/android/content/pm/ConstrainDisplayApisConfig.java +++ b/core/java/android/content/pm/ConstrainDisplayApisConfig.java @@ -19,10 +19,15 @@ package android.content.pm; import static android.provider.DeviceConfig.NAMESPACE_CONSTRAIN_DISPLAY_APIS; import android.provider.DeviceConfig; +import android.util.ArrayMap; +import android.util.Pair; import android.util.Slog; +import com.android.internal.os.BackgroundThread; + import java.util.Arrays; import java.util.List; +import java.util.Map; /** * Class for processing flags in the Device Config namespace 'constrain_display_apis'. @@ -54,6 +59,33 @@ public final class ConstrainDisplayApisConfig { private static final String FLAG_ALWAYS_CONSTRAIN_DISPLAY_APIS = "always_constrain_display_apis"; + /** + * Indicates that display APIs should never be constrained to the activity window bounds for all + * packages. + */ + private boolean mNeverConstrainDisplayApisAllPackages; + + /** + * Indicates that display APIs should never be constrained to the activity window bounds for + * a set of defined packages. Map keys are package names, and entries are a + * 'Pair(, )'. + */ + private ArrayMap> mNeverConstrainConfigMap; + + /** + * Indicates that display APIs should always be constrained to the activity window bounds for + * a set of defined packages. Map keys are package names, and entries are a + * 'Pair(, )'. + */ + private ArrayMap> mAlwaysConstrainConfigMap; + + public ConstrainDisplayApisConfig() { + updateCache(); + + DeviceConfig.addOnPropertiesChangedListener(NAMESPACE_CONSTRAIN_DISPLAY_APIS, + BackgroundThread.getExecutor(), properties -> updateCache()); + } + /** * Returns true if either the flag 'never_constrain_display_apis_all_packages' is true or the * flag 'never_constrain_display_apis' contains a package entry that matches the given {@code @@ -61,13 +93,12 @@ public final class ConstrainDisplayApisConfig { * * @param applicationInfo Information about the application/package. */ - public static boolean neverConstrainDisplayApis(ApplicationInfo applicationInfo) { - if (DeviceConfig.getBoolean(NAMESPACE_CONSTRAIN_DISPLAY_APIS, - FLAG_NEVER_CONSTRAIN_DISPLAY_APIS_ALL_PACKAGES, /* defaultValue= */ false)) { + public boolean getNeverConstrainDisplayApis(ApplicationInfo applicationInfo) { + if (mNeverConstrainDisplayApisAllPackages) { return true; } - return flagHasMatchingPackageEntry(FLAG_NEVER_CONSTRAIN_DISPLAY_APIS, applicationInfo); + return flagHasMatchingPackageEntry(mNeverConstrainConfigMap, applicationInfo); } /** @@ -76,73 +107,106 @@ public final class ConstrainDisplayApisConfig { * * @param applicationInfo Information about the application/package. */ - public static boolean alwaysConstrainDisplayApis(ApplicationInfo applicationInfo) { - return flagHasMatchingPackageEntry(FLAG_ALWAYS_CONSTRAIN_DISPLAY_APIS, applicationInfo); + public boolean getAlwaysConstrainDisplayApis(ApplicationInfo applicationInfo) { + return flagHasMatchingPackageEntry(mAlwaysConstrainConfigMap, applicationInfo); } + /** - * Returns true if the flag with the given {@code flagName} contains a package entry that - * matches the given {@code applicationInfo}. - * - * @param applicationInfo Information about the application/package. + * Updates {@link #mNeverConstrainDisplayApisAllPackages}, {@link #mNeverConstrainConfigMap}, + * and {@link #mAlwaysConstrainConfigMap} from the {@link DeviceConfig}. */ - private static boolean flagHasMatchingPackageEntry(String flagName, - ApplicationInfo applicationInfo) { - String configStr = DeviceConfig.getString(NAMESPACE_CONSTRAIN_DISPLAY_APIS, - flagName, /* defaultValue= */ ""); + private void updateCache() { + mNeverConstrainDisplayApisAllPackages = DeviceConfig.getBoolean( + NAMESPACE_CONSTRAIN_DISPLAY_APIS, + FLAG_NEVER_CONSTRAIN_DISPLAY_APIS_ALL_PACKAGES, /* defaultValue= */ false); + + final String neverConstrainConfigStr = DeviceConfig.getString( + NAMESPACE_CONSTRAIN_DISPLAY_APIS, + FLAG_NEVER_CONSTRAIN_DISPLAY_APIS, /* defaultValue= */ ""); + mNeverConstrainConfigMap = buildConfigMap(neverConstrainConfigStr); + + final String alwaysConstrainConfigStr = DeviceConfig.getString( + NAMESPACE_CONSTRAIN_DISPLAY_APIS, + FLAG_ALWAYS_CONSTRAIN_DISPLAY_APIS, /* defaultValue= */ ""); + mAlwaysConstrainConfigMap = buildConfigMap(alwaysConstrainConfigStr); + } + /** + * Processes the configuration string into a map of version codes, for the given + * configuration to be applied to the specified packages. If the given package + * entry string is invalid, then the map will not contain an entry for the package. + * + * @param configStr A configuration string expected to be in the format of a list of package + * entries separated by ','. A package entry expected to be in the format + * ':?:?'. + * @return a map of configuration entries, where each key is a package name. Each value is + * a pair of version codes, in the format 'Pair(, )'. + */ + private static ArrayMap> buildConfigMap(String configStr) { + ArrayMap> configMap = new ArrayMap<>(); // String#split returns a non-empty array given an empty string. if (configStr.isEmpty()) { - return false; + return configMap; } - for (String packageEntryString : configStr.split(",")) { - if (matchesApplicationInfo(packageEntryString, applicationInfo)) { - return true; + List packageAndVersions = Arrays.asList(packageEntryString.split(":", 3)); + if (packageAndVersions.size() != 3) { + Slog.w(TAG, "Invalid package entry in flag 'never/always_constrain_display_apis': " + + packageEntryString); + // Skip this entry. + continue; + } + String packageName = packageAndVersions.get(0); + String minVersionCodeStr = packageAndVersions.get(1); + String maxVersionCodeStr = packageAndVersions.get(2); + try { + final long minVersion = + minVersionCodeStr.isEmpty() ? Long.MIN_VALUE : Long.parseLong( + minVersionCodeStr); + final long maxVersion = + maxVersionCodeStr.isEmpty() ? Long.MAX_VALUE : Long.parseLong( + maxVersionCodeStr); + Pair minMaxVersionCodes = new Pair<>(minVersion, maxVersion); + configMap.put(packageName, minMaxVersionCodes); + } catch (NumberFormatException e) { + Slog.w(TAG, "Invalid APK version code in package entry: " + packageEntryString); + // Skip this entry. } } - - return false; + return configMap; } /** - * Parses the given {@code packageEntryString} and returns true if {@code - * applicationInfo.packageName} matches the package name in the config and {@code - * applicationInfo.longVersionCode} is within the version range in the config. - * - *

Logs a warning and returns false in case the given {@code packageEntryString} is invalid. + * Returns true if the flag with the given {@code flagName} contains a package entry that + * matches the given {@code applicationInfo}. * - * @param packageEntryStr A package entry expected to be in the format - * ':?:?'. + * @param configMap the map representing the current configuration value to examine * @param applicationInfo Information about the application/package. */ - private static boolean matchesApplicationInfo(String packageEntryStr, + private static boolean flagHasMatchingPackageEntry(Map> configMap, ApplicationInfo applicationInfo) { - List packageAndVersions = Arrays.asList(packageEntryStr.split(":", 3)); - if (packageAndVersions.size() != 3) { - Slog.w(TAG, "Invalid package entry in flag 'never_constrain_display_apis': " - + packageEntryStr); + if (configMap.isEmpty()) { return false; } - String packageName = packageAndVersions.get(0); - String minVersionCodeStr = packageAndVersions.get(1); - String maxVersionCodeStr = packageAndVersions.get(2); - - if (!packageName.equals(applicationInfo.packageName)) { + if (!configMap.containsKey(applicationInfo.packageName)) { return false; } - long version = applicationInfo.longVersionCode; - try { - if (!minVersionCodeStr.isEmpty() && version < Long.parseLong(minVersionCodeStr)) { - return false; - } - if (!maxVersionCodeStr.isEmpty() && version > Long.parseLong(maxVersionCodeStr)) { - return false; - } - } catch (NumberFormatException e) { - Slog.w(TAG, "Invalid APK version code in package entry: " + packageEntryStr); - return false; - } - return true; + return matchesApplicationInfo(configMap.get(applicationInfo.packageName), applicationInfo); + } + + /** + * Parses the given {@code minMaxVersionCodes} and returns true if {@code + * applicationInfo.longVersionCode} is within the version range in the pair. + * Returns false otherwise. + * + * @param minMaxVersionCodes A pair expected to be in the format + * 'Pair(, )'. + * @param applicationInfo Information about the application/package. + */ + private static boolean matchesApplicationInfo(Pair minMaxVersionCodes, + ApplicationInfo applicationInfo) { + return applicationInfo.longVersionCode >= minMaxVersionCodes.first + && applicationInfo.longVersionCode <= minMaxVersionCodes.second; } } diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 2ed00b5d2982..a6bf6a41e756 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -2473,6 +2473,16 @@ public abstract class PackageManager { @SdkConstant(SdkConstantType.FEATURE) public static final String FEATURE_CTS = "android.software.cts"; + /** + * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}: The device + * is opted-in to render the application using Automotive App Host + * + * @hide + */ + @SdkConstant(SdkConstantType.FEATURE) + public static final String FEATURE_CAR_TEMPLATES_HOST = + "android.software.car.templates_host"; + /** * Feature for {@link #getSystemAvailableFeatures} and * {@link #hasSystemFeature(String, int)}: If this feature is supported, the device supports @@ -3699,6 +3709,17 @@ public abstract class PackageManager { public static final String FEATURE_KEYSTORE_APP_ATTEST_KEY = "android.hardware.keystore.app_attest_key"; + /** + * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}: The device + * is opted-in to receive per-app compatibility overrides that are applied in + * {@link com.android.server.compat.overrides.AppCompatOverridesService}. + * + * @hide + */ + @SdkConstant(SdkConstantType.FEATURE) + public static final String FEATURE_APP_COMPAT_OVERRIDES = + "android.software.app_compat_overrides"; + /** @hide */ public static final boolean APP_ENUMERATION_ENABLED_BY_DEFAULT = true; diff --git a/core/java/android/hardware/biometrics/BiometricConstants.java b/core/java/android/hardware/biometrics/BiometricConstants.java index 43ef33e1f420..28046c56b9f8 100644 --- a/core/java/android/hardware/biometrics/BiometricConstants.java +++ b/core/java/android/hardware/biometrics/BiometricConstants.java @@ -150,6 +150,12 @@ public interface BiometricConstants { */ int BIOMETRIC_ERROR_RE_ENROLL = 16; + /** + * The privacy setting has been enabled and will block use of the sensor. + * @hide + */ + int BIOMETRIC_ERROR_SENSOR_PRIVACY_ENABLED = 18; + /** * This constant is only used by SystemUI. It notifies SystemUI that authentication was paused * because the authentication attempt was unsuccessful. diff --git a/core/java/android/hardware/biometrics/BiometricFaceConstants.java b/core/java/android/hardware/biometrics/BiometricFaceConstants.java index fe43c83d17f1..fd46f243874b 100644 --- a/core/java/android/hardware/biometrics/BiometricFaceConstants.java +++ b/core/java/android/hardware/biometrics/BiometricFaceConstants.java @@ -69,7 +69,7 @@ public interface BiometricFaceConstants { BIOMETRIC_ERROR_NO_DEVICE_CREDENTIAL, BIOMETRIC_ERROR_SECURITY_UPDATE_REQUIRED, BIOMETRIC_ERROR_RE_ENROLL, - FACE_ERROR_UNKNOWN + FACE_ERROR_UNKNOWN, }) @Retention(RetentionPolicy.SOURCE) @interface FaceError {} diff --git a/core/java/android/hardware/biometrics/BiometricOverlayConstants.java b/core/java/android/hardware/biometrics/BiometricOverlayConstants.java new file mode 100644 index 000000000000..065ae64a92ad --- /dev/null +++ b/core/java/android/hardware/biometrics/BiometricOverlayConstants.java @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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.biometrics; + +import android.annotation.IntDef; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * Common constants for biometric overlays. + * @hide + */ +public interface BiometricOverlayConstants { + /** Unknown usage. */ + int REASON_UNKNOWN = 0; + /** User is about to enroll. */ + int REASON_ENROLL_FIND_SENSOR = 1; + /** User is enrolling. */ + int REASON_ENROLL_ENROLLING = 2; + /** Usage from BiometricPrompt. */ + int REASON_AUTH_BP = 3; + /** Usage from Keyguard. */ + int REASON_AUTH_KEYGUARD = 4; + /** Non-specific usage (from FingerprintManager). */ + int REASON_AUTH_OTHER = 5; + /** Usage from Settings. */ + int REASON_AUTH_SETTINGS = 6; + + @IntDef({REASON_UNKNOWN, + REASON_ENROLL_FIND_SENSOR, + REASON_ENROLL_ENROLLING, + REASON_AUTH_BP, + REASON_AUTH_KEYGUARD, + REASON_AUTH_OTHER, + REASON_AUTH_SETTINGS}) + @Retention(RetentionPolicy.SOURCE) + @interface ShowReason {} +} diff --git a/core/java/android/hardware/biometrics/BiometricPrompt.java b/core/java/android/hardware/biometrics/BiometricPrompt.java index c8c122da4ab8..6b5bec99e674 100644 --- a/core/java/android/hardware/biometrics/BiometricPrompt.java +++ b/core/java/android/hardware/biometrics/BiometricPrompt.java @@ -407,6 +407,19 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan return this; } + /** + * Flag to decide if authentication should ignore enrollment state. + * Defaults to false (not ignoring enrollment state) + * @param ignoreEnrollmentState + * @return This builder. + * @hide + */ + @NonNull + public Builder setIgnoreEnrollmentState(boolean ignoreEnrollmentState) { + mPromptInfo.setIgnoreEnrollmentState(ignoreEnrollmentState); + return this; + } + /** * Creates a {@link BiometricPrompt}. * diff --git a/core/java/android/hardware/biometrics/PromptInfo.java b/core/java/android/hardware/biometrics/PromptInfo.java index 339c654f4d2f..e6b762a64384 100644 --- a/core/java/android/hardware/biometrics/PromptInfo.java +++ b/core/java/android/hardware/biometrics/PromptInfo.java @@ -45,6 +45,7 @@ public class PromptInfo implements Parcelable { private boolean mReceiveSystemEvents; @NonNull private List mAllowedSensorIds = new ArrayList<>(); private boolean mAllowBackgroundAuthentication; + private boolean mIgnoreEnrollmentState; public PromptInfo() { @@ -66,6 +67,7 @@ public class PromptInfo implements Parcelable { mReceiveSystemEvents = in.readBoolean(); mAllowedSensorIds = in.readArrayList(Integer.class.getClassLoader()); mAllowBackgroundAuthentication = in.readBoolean(); + mIgnoreEnrollmentState = in.readBoolean(); } public static final Creator CREATOR = new Creator() { @@ -102,6 +104,7 @@ public class PromptInfo implements Parcelable { dest.writeBoolean(mReceiveSystemEvents); dest.writeList(mAllowedSensorIds); dest.writeBoolean(mAllowBackgroundAuthentication); + dest.writeBoolean(mIgnoreEnrollmentState); } public boolean containsTestConfigurations() { @@ -192,6 +195,10 @@ public class PromptInfo implements Parcelable { mAllowBackgroundAuthentication = allow; } + public void setIgnoreEnrollmentState(boolean ignoreEnrollmentState) { + mIgnoreEnrollmentState = ignoreEnrollmentState; + } + // Getters public CharSequence getTitle() { @@ -261,4 +268,8 @@ public class PromptInfo implements Parcelable { public boolean isAllowBackgroundAuthentication() { return mAllowBackgroundAuthentication; } + + public boolean isIgnoreEnrollmentState() { + return mIgnoreEnrollmentState; + } } diff --git a/core/java/android/hardware/biometrics/SensorLocationInternal.aidl b/core/java/android/hardware/biometrics/SensorLocationInternal.aidl new file mode 100644 index 000000000000..098190449d53 --- /dev/null +++ b/core/java/android/hardware/biometrics/SensorLocationInternal.aidl @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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.biometrics; + +// @hide +parcelable SensorLocationInternal; diff --git a/core/java/android/hardware/biometrics/SensorLocationInternal.java b/core/java/android/hardware/biometrics/SensorLocationInternal.java new file mode 100644 index 000000000000..fb25a2fcd823 --- /dev/null +++ b/core/java/android/hardware/biometrics/SensorLocationInternal.java @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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.biometrics; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.os.Parcel; +import android.os.Parcelable; + +/** + * The location of a sensor relative to a physical display. + * + * Note that the location may change depending on other attributes of the device, such as + * fold status, which are not yet included in this class. + * @hide + */ +public class SensorLocationInternal implements Parcelable { + + /** Default value to use when the sensor's location is unknown or undefined. */ + public static final SensorLocationInternal DEFAULT = new SensorLocationInternal("", 0, 0, 0); + + /** + * The stable display id. + */ + @NonNull + public final String displayId; + + /** + * The location of the center of the sensor if applicable. For example, sensors of type + * {@link FingerprintSensorProperties#TYPE_UDFPS_OPTICAL} would report this value as the + * distance in pixels, measured from the left edge of the screen. + */ + public final int sensorLocationX; + + /** + * The location of the center of the sensor if applicable. For example, sensors of type + * {@link FingerprintSensorProperties#TYPE_UDFPS_OPTICAL} would report this value as the + * distance in pixels, measured from the top edge of the screen. + * + */ + public final int sensorLocationY; + + /** + * The radius of the sensor if applicable. For example, sensors of type + * {@link FingerprintSensorProperties#TYPE_UDFPS_OPTICAL} would report this value as the radius + * of the sensor, in pixels. + */ + public final int sensorRadius; + + public SensorLocationInternal(@Nullable String displayId, + int sensorLocationX, int sensorLocationY, int sensorRadius) { + this.displayId = displayId != null ? displayId : ""; + this.sensorLocationX = sensorLocationX; + this.sensorLocationY = sensorLocationY; + this.sensorRadius = sensorRadius; + } + + protected SensorLocationInternal(Parcel in) { + displayId = in.readString16NoHelper(); + sensorLocationX = in.readInt(); + sensorLocationY = in.readInt(); + sensorRadius = in.readInt(); + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeString(displayId); + dest.writeInt(sensorLocationX); + dest.writeInt(sensorLocationY); + dest.writeInt(sensorRadius); + } + + @Override + public int describeContents() { + return 0; + } + + public static final Creator CREATOR = + new Creator() { + @Override + public SensorLocationInternal createFromParcel(Parcel in) { + return new SensorLocationInternal(in); + } + + @Override + public SensorLocationInternal[] newArray(int size) { + return new SensorLocationInternal[size]; + } + }; + + @Override + public String toString() { + return "[id: " + displayId + + ", x: " + sensorLocationX + + ", y: " + sensorLocationY + + ", r: " + sensorRadius + "]"; + } +} diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java index e0138c5db178..0b02a919b2d9 100644 --- a/core/java/android/hardware/camera2/CameraCharacteristics.java +++ b/core/java/android/hardware/camera2/CameraCharacteristics.java @@ -22,15 +22,18 @@ import android.compat.annotation.UnsupportedAppUsage; import android.hardware.camera2.impl.CameraMetadataNative; import android.hardware.camera2.impl.PublicKey; import android.hardware.camera2.impl.SyntheticKey; +import android.hardware.camera2.params.DeviceStateSensorOrientationMap; import android.hardware.camera2.params.RecommendedStreamConfigurationMap; import android.hardware.camera2.params.SessionConfiguration; import android.hardware.camera2.utils.TypeReference; import android.os.Build; +import android.util.Log; import android.util.Rational; +import com.android.internal.annotations.GuardedBy; + import java.util.ArrayList; import java.util.Collections; -import java.util.HashSet; import java.util.List; import java.util.Set; @@ -202,8 +205,25 @@ public final class CameraCharacteristics extends CameraMetadata> mAvailableResultKeys; private ArrayList mRecommendedConfigurations; + private final Object mLock = new Object(); + @GuardedBy("mLock") + private boolean mFoldedDeviceState; + + private final CameraManager.DeviceStateListener mFoldStateListener = + new CameraManager.DeviceStateListener() { + @Override + public final void onDeviceStateChanged(boolean folded) { + synchronized (mLock) { + mFoldedDeviceState = folded; + } + }}; + + private static final String TAG = "CameraCharacteristics"; + /** * Takes ownership of the passed-in properties object + * + * @param properties Camera properties. * @hide */ public CameraCharacteristics(CameraMetadataNative properties) { @@ -219,6 +239,42 @@ public final class CameraCharacteristics extends CameraMetadataCheck whether a given property value needs to be overridden in some specific + * case.

+ * + * @param key The characteristics field to override. + * @return The value of overridden property, or {@code null} if the property doesn't need an + * override. + */ + @Nullable + private T overrideProperty(Key key) { + if (CameraCharacteristics.SENSOR_ORIENTATION.equals(key) && (mFoldStateListener != null) && + (mProperties.get(CameraCharacteristics.INFO_DEVICE_STATE_ORIENTATIONS) != null)) { + DeviceStateSensorOrientationMap deviceStateSensorOrientationMap = + mProperties.get(CameraCharacteristics.INFO_DEVICE_STATE_SENSOR_ORIENTATION_MAP); + synchronized (mLock) { + Integer ret = deviceStateSensorOrientationMap.getSensorOrientation( + mFoldedDeviceState ? DeviceStateSensorOrientationMap.FOLDED : + DeviceStateSensorOrientationMap.NORMAL); + if (ret >= 0) { + return (T) ret; + } else { + Log.w(TAG, "No valid device state to orientation mapping! Using default!"); + } + } + } + + return null; + } + /** * Get a camera characteristics field value. * @@ -235,7 +291,8 @@ public final class CameraCharacteristics extends CameraMetadata T get(Key key) { - return mProperties.get(key); + T propertyOverride = overrideProperty(key); + return (propertyOverride != null) ? propertyOverride : mProperties.get(key); } /** @@ -2575,7 +2632,8 @@ public final class CameraCharacteristics extends CameraMetadata * *

For applications targeting SDK version 31 or newer, if the mobile device declares to be - * {@link android.os.Build.VERSION_CDOES.MEDIA_PERFORMANCE_CLASS media performance class} S, + * media performance class 12 or higher by setting + * {@link android.os.Build.VERSION_CDOES.MEDIA_PERFORMANCE_CLASS } to be 31 or larger, * the primary camera devices (first rear/front camera in the camera ID list) will not * support JPEG sizes smaller than 1080p. If the application configures a JPEG stream * smaller than 1080p, the camera device will round up the JPEG image size to at least @@ -2648,9 +2706,11 @@ public final class CameraCharacteristics extends CameraMetadata * *

For applications targeting SDK version 31 or newer, if the mobile device doesn't declare - * to be media performance class S, or if the camera device isn't a primary rear/front - * camera, the minimum required output stream configurations are the same as for applications - * targeting SDK version older than 31.

+ * to be media performance class 12 or better by setting + * {@link android.os.Build.VERSION_CDOES.MEDIA_PERFORMANCE_CLASS } to be 31 or larger, + * or if the camera device isn't a primary rear/front camera, the minimum required output + * stream configurations are the same as for applications targeting SDK version older than + * 31.

*

Refer to {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities} for additional * mandatory stream configurations on a per-capability basis.

*

Exception on 176x144 (QCIF) resolution: camera devices usually have a fixed capability for @@ -3993,11 +4053,26 @@ public final class CameraCharacteristics extends CameraMetadata *

Also defines the direction of rolling shutter readout, which is from top to bottom in * the sensor's coordinate system.

+ *

Starting with Android API level 32, camera clients that query the orientation via + * {@link android.hardware.camera2.CameraCharacteristics#get } on foldable devices which + * include logical cameras can receive a value that can dynamically change depending on the + * device/fold state. + * Clients are advised to not cache or store the orientation value of such logical sensors. + * In case repeated queries to CameraCharacteristics are not preferred, then clients can + * also access the entire mapping from device state to sensor orientation in + * {@link android.hardware.camera2.params.DeviceStateSensorOrientationMap }. + * Do note that a dynamically changing sensor orientation value in camera characteristics + * will not be the best way to establish the orientation per frame. Clients that want to + * know the sensor orientation of a particular captured frame should query the + * {@link CaptureResult#LOGICAL_MULTI_CAMERA_ACTIVE_PHYSICAL_ID android.logicalMultiCamera.activePhysicalId} from the corresponding capture result and + * check the respective physical camera orientation.

*

Units: Degrees of clockwise rotation; always a multiple of * 90

*

Range of valid values:
* 0, 90, 180, 270

*

This key is available on all devices.

+ * + * @see CaptureResult#LOGICAL_MULTI_CAMERA_ACTIVE_PHYSICAL_ID */ @PublicKey @NonNull @@ -4306,6 +4381,46 @@ public final class CameraCharacteristics extends CameraMetadata INFO_VERSION = new Key("android.info.version", String.class); + /** + *

This lists the mapping between a device folding state and + * specific camera sensor orientation for logical cameras on a foldable device.

+ *

Logical cameras on foldable devices can support sensors with different orientation + * values. The orientation value may need to change depending on the specific folding + * state. Information about the mapping between the device folding state and the + * sensor orientation can be obtained in + * {@link android.hardware.camera2.params.DeviceStateSensorOrientationMap }. + * Device state orientation maps are optional and maybe present on devices that support + * {@link CaptureRequest#SCALER_ROTATE_AND_CROP android.scaler.rotateAndCrop}.

+ *

Optional - The value for this key may be {@code null} on some devices.

+ *

Limited capability - + * Present on all camera devices that report being at least {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED HARDWARE_LEVEL_LIMITED} devices in the + * {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL android.info.supportedHardwareLevel} key

+ * + * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL + * @see CaptureRequest#SCALER_ROTATE_AND_CROP + */ + @PublicKey + @NonNull + @SyntheticKey + public static final Key INFO_DEVICE_STATE_SENSOR_ORIENTATION_MAP = + new Key("android.info.deviceStateSensorOrientationMap", android.hardware.camera2.params.DeviceStateSensorOrientationMap.class); + + /** + *

HAL must populate the array with + * (hardware::camera::provider::V2_5::DeviceState, sensorOrientation) pairs for each + * supported device state bitwise combination.

+ *

Units: (device fold state, sensor orientation) x n

+ *

Optional - The value for this key may be {@code null} on some devices.

+ *

Limited capability - + * Present on all camera devices that report being at least {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED HARDWARE_LEVEL_LIMITED} devices in the + * {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL android.info.supportedHardwareLevel} key

+ * + * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL + * @hide + */ + public static final Key INFO_DEVICE_STATE_ORIENTATIONS = + new Key("android.info.deviceStateOrientations", long[].class); + /** *

The maximum number of frames that can occur after a request * (different than the previous) has been submitted, and before the diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java index 564907118c26..0fca32196518 100644 --- a/core/java/android/hardware/camera2/CameraManager.java +++ b/core/java/android/hardware/camera2/CameraManager.java @@ -36,10 +36,13 @@ import android.hardware.camera2.params.SessionConfiguration; import android.hardware.camera2.params.StreamConfiguration; import android.hardware.camera2.utils.CameraIdAndSessionConfiguration; import android.hardware.camera2.utils.ConcurrentCameraIdCombination; +import android.hardware.devicestate.DeviceStateManager; import android.hardware.display.DisplayManager; import android.os.Binder; import android.os.DeadObjectException; import android.os.Handler; +import android.os.HandlerExecutor; +import android.os.HandlerThread; import android.os.IBinder; import android.os.RemoteException; import android.os.ServiceManager; @@ -53,6 +56,10 @@ import android.util.Log; import android.util.Size; import android.view.Display; +import com.android.internal.annotations.GuardedBy; +import com.android.internal.util.ArrayUtils; + +import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; @@ -100,6 +107,90 @@ public final class CameraManager { synchronized(mLock) { mContext = context; } + + mHandlerThread = new HandlerThread(TAG); + mHandlerThread.start(); + mHandler = new Handler(mHandlerThread.getLooper()); + mFoldStateListener = new FoldStateListener(context); + try { + context.getSystemService(DeviceStateManager.class) + .registerCallback(new HandlerExecutor(mHandler), mFoldStateListener); + } catch (IllegalStateException e) { + Log.v(TAG, "Failed to register device state listener!"); + Log.v(TAG, "Device state dependent characteristics updates will not be functional!"); + mHandlerThread.quitSafely(); + mHandler = null; + mFoldStateListener = null; + } + } + + private HandlerThread mHandlerThread; + private Handler mHandler; + private FoldStateListener mFoldStateListener; + @GuardedBy("mLock") + private ArrayList> mDeviceStateListeners = new ArrayList<>(); + private boolean mFoldedDeviceState; + + /** + * @hide + */ + public interface DeviceStateListener { + void onDeviceStateChanged(boolean folded); + } + + private final class FoldStateListener implements DeviceStateManager.DeviceStateCallback { + private final int[] mFoldedDeviceStates; + + public FoldStateListener(Context context) { + mFoldedDeviceStates = context.getResources().getIntArray( + com.android.internal.R.array.config_foldedDeviceStates); + } + + private void handleStateChange(int state) { + boolean folded = ArrayUtils.contains(mFoldedDeviceStates, state); + synchronized (mLock) { + mFoldedDeviceState = folded; + ArrayList> invalidListeners = new ArrayList<>(); + for (WeakReference listener : mDeviceStateListeners) { + DeviceStateListener callback = listener.get(); + if (callback != null) { + callback.onDeviceStateChanged(folded); + } else { + invalidListeners.add(listener); + } + } + if (!invalidListeners.isEmpty()) { + mDeviceStateListeners.removeAll(invalidListeners); + } + } + } + + @Override + public final void onBaseStateChanged(int state) { + handleStateChange(state); + } + + @Override + public final void onStateChanged(int state) { + handleStateChange(state); + } + } + + /** + * Register a {@link CameraCharacteristics} device state listener + * + * @param chars Camera characteristics that need to receive device state updates + * + * @hide + */ + public void registerDeviceStateListener(@NonNull CameraCharacteristics chars) { + synchronized (mLock) { + DeviceStateListener listener = chars.getDeviceStateListener(); + listener.onDeviceStateChanged(mFoldedDeviceState); + if (mFoldStateListener != null) { + mDeviceStateListeners.add(new WeakReference<>(listener)); + } + } } /** @@ -507,6 +598,7 @@ public final class CameraManager { "Camera service is currently unavailable", e); } } + registerDeviceStateListener(characteristics); return characteristics; } @@ -1330,8 +1422,7 @@ public final class CameraManager { private ICameraService mCameraService; // Singleton, don't allow construction - private CameraManagerGlobal() { - } + private CameraManagerGlobal() { } public static final boolean sCameraServiceDisabled = SystemProperties.getBoolean("config.disable_cameraservice", false); diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java index 9361d2caa85f..cabb14122e00 100644 --- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java +++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java @@ -115,6 +115,11 @@ public class CameraDeviceImpl extends CameraDevice private int mRepeatingRequestId = REQUEST_ID_NONE; // Latest repeating request list's types private int[] mRepeatingRequestTypes; + + // Cache failed requests to process later in case of a repeating error callback + private int mFailedRepeatingRequestId = REQUEST_ID_NONE; + private int[] mFailedRepeatingRequestTypes; + // Map stream IDs to input/output configurations private SimpleEntry mConfiguredInput = new SimpleEntry<>(REQUEST_ID_NONE, null); @@ -1338,16 +1343,25 @@ public class CameraDeviceImpl extends CameraDevice int requestId = mRepeatingRequestId; mRepeatingRequestId = REQUEST_ID_NONE; + mFailedRepeatingRequestId = REQUEST_ID_NONE; int[] requestTypes = mRepeatingRequestTypes; mRepeatingRequestTypes = null; + mFailedRepeatingRequestTypes = null; long lastFrameNumber; try { lastFrameNumber = mRemoteDevice.cancelRequest(requestId); } catch (IllegalArgumentException e) { if (DEBUG) { - Log.v(TAG, "Repeating request was already stopped for request " + requestId); + Log.v(TAG, "Repeating request was already stopped for request " + + requestId); } + // Cache request id and request types in case of a race with + // "onRepeatingRequestError" which may no yet be scheduled on another thread + // or blocked by us. + mFailedRepeatingRequestId = requestId; + mFailedRepeatingRequestTypes = requestTypes; + // Repeating request was already stopped. Nothing more to do. return; } @@ -2006,7 +2020,17 @@ public class CameraDeviceImpl extends CameraDevice synchronized(mInterfaceLock) { // Camera is already closed or no repeating request is present. if (mRemoteDevice == null || mRepeatingRequestId == REQUEST_ID_NONE) { - return; // Camera already closed + if ((mFailedRepeatingRequestId == repeatingRequestId) && + (mFailedRepeatingRequestTypes != null) && (mRemoteDevice != null)) { + Log.v(TAG, "Resuming stop of failed repeating request with id: " + + mFailedRepeatingRequestId); + + checkEarlyTriggerSequenceCompleteLocked(mFailedRepeatingRequestId, + lastFrameNumber, mFailedRepeatingRequestTypes); + mFailedRepeatingRequestId = REQUEST_ID_NONE; + mFailedRepeatingRequestTypes = null; + } + return; } // Redirect device callback to the offline session in case we are in the middle diff --git a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java index 196134b397cb..e393a66eb733 100644 --- a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java +++ b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java @@ -50,10 +50,10 @@ import android.hardware.camera2.marshal.impl.MarshalQueryableStreamConfiguration import android.hardware.camera2.marshal.impl.MarshalQueryableStreamConfigurationDuration; import android.hardware.camera2.marshal.impl.MarshalQueryableString; import android.hardware.camera2.params.Capability; +import android.hardware.camera2.params.DeviceStateSensorOrientationMap; import android.hardware.camera2.params.Face; import android.hardware.camera2.params.HighSpeedVideoConfiguration; import android.hardware.camera2.params.LensShadingMap; -import android.hardware.camera2.params.MeteringRectangle; import android.hardware.camera2.params.MandatoryStreamCombination; import android.hardware.camera2.params.MultiResolutionStreamConfigurationMap; import android.hardware.camera2.params.OisSample; @@ -754,13 +754,22 @@ public class CameraMetadataNative implements Parcelable { }); sGetCommandMap.put( CaptureResult.STATISTICS_LENS_SHADING_CORRECTION_MAP.getNativeKey(), - new GetCommand() { + new GetCommand() { @Override @SuppressWarnings("unchecked") public T getValue(CameraMetadataNative metadata, Key key) { return (T) metadata.getLensShadingMap(); } }); + sGetCommandMap.put( + CameraCharacteristics.INFO_DEVICE_STATE_SENSOR_ORIENTATION_MAP.getNativeKey(), + new GetCommand() { + @Override + @SuppressWarnings("unchecked") + public T getValue(CameraMetadataNative metadata, Key key) { + return (T) metadata.getDeviceStateOrientationMap(); + } + }); sGetCommandMap.put( CaptureResult.STATISTICS_OIS_SAMPLES.getNativeKey(), new GetCommand() { @@ -994,6 +1003,18 @@ public class CameraMetadataNative implements Parcelable { return map; } + private DeviceStateSensorOrientationMap getDeviceStateOrientationMap() { + long[] mapArray = getBase(CameraCharacteristics.INFO_DEVICE_STATE_ORIENTATIONS); + + // Do not warn if map is null while s is not. This is valid. + if (mapArray == null) { + return null; + } + + DeviceStateSensorOrientationMap map = new DeviceStateSensorOrientationMap(mapArray); + return map; + } + private Location getGpsLocation() { String processingMethod = get(CaptureResult.JPEG_GPS_PROCESSING_METHOD); double[] coords = get(CaptureResult.JPEG_GPS_COORDINATES); diff --git a/core/java/android/hardware/camera2/params/DeviceStateSensorOrientationMap.java b/core/java/android/hardware/camera2/params/DeviceStateSensorOrientationMap.java new file mode 100644 index 000000000000..200409e9e000 --- /dev/null +++ b/core/java/android/hardware/camera2/params/DeviceStateSensorOrientationMap.java @@ -0,0 +1,156 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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.camera2.params; + +import android.annotation.LongDef; +import android.hardware.camera2.CameraCharacteristics; +import android.hardware.camera2.utils.HashCodeHelpers; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Objects; + +/** + * Immutable class that maps the device fold state to sensor orientation. + * + *

Some {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA logical} + * cameras on foldables can include physical sensors with different sensor orientation + * values. As a result, the values of the logical camera device can potentially change depending + * on the device fold state.

+ * + *

The device fold state to sensor orientation map will contain information about the + * respective logical camera sensor orientation given a device state. Clients + * can query the mapping for all possible supported folded states. + * + * @see CameraCharacteristics#SENSOR_ORIENTATION + */ +public final class DeviceStateSensorOrientationMap { + /** + * Needs to be kept in sync with the HIDL/AIDL DeviceState + */ + + /** + * The device is in its normal physical configuration. This is the default if the + * device does not support multiple different states. + */ + public static final long NORMAL = 0; + + /** + * The device is folded. If not set, the device is unfolded or does not + * support folding. + * + * The exact point when this status change happens during the folding + * operation is device-specific. + */ + public static final long FOLDED = 1 << 2; + + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @LongDef(prefix = {"DEVICE_STATE"}, value = + {NORMAL, + FOLDED }) + public @interface DeviceState {}; + + private final HashMap mDeviceStateOrientationMap = new HashMap<>(); + + /** + * Create a new immutable DeviceStateOrientationMap instance. + * + *

This constructor takes over the array; do not write to the array afterwards.

+ * + * @param elements + * An array of elements describing the map + * + * @throws IllegalArgumentException + * if the {@code elements} array length is invalid, not divisible by 2 or contains + * invalid element values + * @throws NullPointerException + * if {@code elements} is {@code null} + * + * @hide + */ + public DeviceStateSensorOrientationMap(final long[] elements) { + mElements = Objects.requireNonNull(elements, "elements must not be null"); + if ((elements.length % 2) != 0) { + throw new IllegalArgumentException("Device state sensor orientation map length " + + elements.length + " is not even!"); + } + + for (int i = 0; i < elements.length; i += 2) { + if ((elements[i+1] % 90) != 0) { + throw new IllegalArgumentException("Sensor orientation not divisible by 90: " + + elements[i+1]); + } + + mDeviceStateOrientationMap.put(elements[i], Math.toIntExact(elements[i + 1])); + } + } + + /** + * Return the logical camera sensor orientation given a specific device fold state. + * + * @param deviceState Device fold state + * + * @return Valid {@link android.hardware.camera2.CameraCharacteristics#SENSOR_ORIENTATION} for + * any supported device fold state + * + * @throws IllegalArgumentException if the given device state is invalid + */ + public int getSensorOrientation(@DeviceState long deviceState) { + if (!mDeviceStateOrientationMap.containsKey(deviceState)) { + throw new IllegalArgumentException("Invalid device state: " + deviceState); + } + + return mDeviceStateOrientationMap.get(deviceState); + } + + /** + * Check if this DeviceStateSensorOrientationMap is equal to another + * DeviceStateSensorOrientationMap. + * + *

Two device state orientation maps are equal if and only if all of their elements are + * {@link Object#equals equal}.

+ * + * @return {@code true} if the objects were equal, {@code false} otherwise + */ + @Override + public boolean equals(final Object obj) { + if (obj == null) { + return false; + } + if (this == obj) { + return true; + } + if (obj instanceof DeviceStateSensorOrientationMap) { + final DeviceStateSensorOrientationMap other = (DeviceStateSensorOrientationMap) obj; + return Arrays.equals(mElements, other.mElements); + } + return false; + } + + /** + * {@inheritDoc} + */ + @Override + public int hashCode() { + return HashCodeHelpers.hashCodeGeneric(mElements); + } + + private final long[] mElements; +} diff --git a/core/java/android/hardware/devicestate/DeviceStateManager.java b/core/java/android/hardware/devicestate/DeviceStateManager.java index 52dad3efefb8..b06d076fe08e 100644 --- a/core/java/android/hardware/devicestate/DeviceStateManager.java +++ b/core/java/android/hardware/devicestate/DeviceStateManager.java @@ -75,27 +75,28 @@ public final class DeviceStateManager { /** * Submits a {@link DeviceStateRequest request} to modify the device state. *

- * By default, the request is kept active until a call to - * {@link #cancelRequest(DeviceStateRequest)} or until one of the following occurs: + * By default, the request is kept active until one of the following occurs: *

    + *
  • The system deems the request can no longer be honored, for example if the requested + * state becomes unsupported. + *
  • A call to {@link #cancelRequest(DeviceStateRequest)}. *
  • Another processes submits a request succeeding this request in which case the request * will be suspended until the interrupting request is canceled. - *
  • The requested state has become unsupported. - *
  • The process submitting the request dies. *
* However, this behavior can be changed by setting flags on the {@link DeviceStateRequest}. * * @throws IllegalArgumentException if the requested state is unsupported. - * @throws SecurityException if the {@link android.Manifest.permission#CONTROL_DEVICE_STATE} - * permission is not held. + * @throws SecurityException if the caller is neither the current top-focused activity nor if + * the {@link android.Manifest.permission#CONTROL_DEVICE_STATE} permission is held. * * @see DeviceStateRequest */ - @RequiresPermission(android.Manifest.permission.CONTROL_DEVICE_STATE) + @RequiresPermission(value = android.Manifest.permission.CONTROL_DEVICE_STATE, + conditional = true) public void requestState(@NonNull DeviceStateRequest request, @Nullable @CallbackExecutor Executor executor, @Nullable DeviceStateRequest.Callback callback) { - mGlobal.requestState(request, callback, executor); + mGlobal.requestState(request, executor, callback); } /** @@ -105,10 +106,11 @@ public final class DeviceStateManager { * This method is noop if the {@code request} has not been submitted with a call to * {@link #requestState(DeviceStateRequest, Executor, DeviceStateRequest.Callback)}. * - * @throws SecurityException if the {@link android.Manifest.permission#CONTROL_DEVICE_STATE} - * permission is not held. + * @throws SecurityException if the caller is neither the current top-focused activity nor if + * the {@link android.Manifest.permission#CONTROL_DEVICE_STATE} permission is held. */ - @RequiresPermission(android.Manifest.permission.CONTROL_DEVICE_STATE) + @RequiresPermission(value = android.Manifest.permission.CONTROL_DEVICE_STATE, + conditional = true) public void cancelRequest(@NonNull DeviceStateRequest request) { mGlobal.cancelRequest(request); } diff --git a/core/java/android/hardware/devicestate/DeviceStateManagerGlobal.java b/core/java/android/hardware/devicestate/DeviceStateManagerGlobal.java index 904a54b00fa3..85e70b0fb3e9 100644 --- a/core/java/android/hardware/devicestate/DeviceStateManagerGlobal.java +++ b/core/java/android/hardware/devicestate/DeviceStateManagerGlobal.java @@ -117,7 +117,7 @@ public final class DeviceStateManagerGlobal { * @see DeviceStateRequest */ public void requestState(@NonNull DeviceStateRequest request, - @Nullable DeviceStateRequest.Callback callback, @Nullable Executor executor) { + @Nullable Executor executor, @Nullable DeviceStateRequest.Callback callback) { if (callback == null && executor != null) { throw new IllegalArgumentException("Callback must be supplied with executor."); } else if (executor == null && callback != null) { @@ -149,7 +149,7 @@ public final class DeviceStateManagerGlobal { /** * Cancels a {@link DeviceStateRequest request} previously submitted with a call to - * {@link #requestState(DeviceStateRequest, DeviceStateRequest.Callback, Executor)}. + * {@link #requestState(DeviceStateRequest, Executor, DeviceStateRequest.Callback)}. * * @see DeviceStateManager#cancelRequest(DeviceStateRequest) */ @@ -408,7 +408,7 @@ public final class DeviceStateManagerGlobal { return; } - mExecutor.execute(() -> mCallback.onRequestSuspended(mRequest)); + mExecutor.execute(() -> mCallback.onRequestCanceled(mRequest)); } } } diff --git a/core/java/android/hardware/display/AmbientDisplayConfiguration.java b/core/java/android/hardware/display/AmbientDisplayConfiguration.java index a1f7aa12264b..0b1ed65ef937 100644 --- a/core/java/android/hardware/display/AmbientDisplayConfiguration.java +++ b/core/java/android/hardware/display/AmbientDisplayConfiguration.java @@ -24,6 +24,7 @@ import android.provider.Settings; import android.text.TextUtils; import com.android.internal.R; +import com.android.internal.util.ArrayUtils; /** * AmbientDisplayConfiguration encapsulates reading access to the configuration of ambient display. @@ -32,7 +33,7 @@ import com.android.internal.R; */ @TestApi public class AmbientDisplayConfiguration { - + private static final String TAG = "AmbientDisplayConfig"; private final Context mContext; private final boolean mAlwaysOnByDefault; @@ -87,7 +88,12 @@ public class AmbientDisplayConfiguration { /** {@hide} */ public boolean tapSensorAvailable() { - return !TextUtils.isEmpty(tapSensorType()); + for (String tapType : tapSensorTypeMapping()) { + if (!TextUtils.isEmpty(tapType)) { + return true; + } + } + return false; } /** {@hide} */ @@ -103,7 +109,10 @@ public class AmbientDisplayConfiguration { /** {@hide} */ public boolean quickPickupSensorEnabled(int user) { - return !TextUtils.isEmpty(quickPickupSensorType()) && !alwaysOnEnabled(user); + return boolSettingDefaultOn(Settings.Secure.DOZE_QUICK_PICKUP_GESTURE, user) + && !TextUtils.isEmpty(quickPickupSensorType()) + && pickupGestureEnabled(user) + && !alwaysOnEnabled(user); } /** {@hide} */ @@ -140,9 +149,18 @@ public class AmbientDisplayConfiguration { return mContext.getResources().getString(R.string.config_dozeDoubleTapSensorType); } - /** {@hide} */ - public String tapSensorType() { - return mContext.getResources().getString(R.string.config_dozeTapSensorType); + /** {@hide} + * May support multiple postures. + */ + public String[] tapSensorTypeMapping() { + String[] postureMapping = + mContext.getResources().getStringArray(R.array.config_dozeTapSensorPostureMapping); + if (ArrayUtils.isEmpty(postureMapping)) { + return new String[] { + mContext.getResources().getString(R.string.config_dozeTapSensorType) + }; + } + return postureMapping; } /** {@hide} */ diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java index fc8337ac3155..d8f20391098c 100644 --- a/core/java/android/hardware/display/DisplayManager.java +++ b/core/java/android/hardware/display/DisplayManager.java @@ -864,7 +864,8 @@ public final class DisplayManager { if (surface != null) { builder.setSurface(surface); } - return createVirtualDisplay(null /* projection */, builder.build(), callback, handler); + return createVirtualDisplay(null /* projection */, builder.build(), callback, handler, + null /* windowContext */); } // TODO : Remove this hidden API after remove all callers. (Refer to MultiDisplayService) @@ -882,15 +883,17 @@ public final class DisplayManager { if (surface != null) { builder.setSurface(surface); } - return createVirtualDisplay(projection, builder.build(), callback, handler); + return createVirtualDisplay(projection, builder.build(), callback, handler, + null /* windowContext */); } /** @hide */ public VirtualDisplay createVirtualDisplay(@Nullable MediaProjection projection, @NonNull VirtualDisplayConfig virtualDisplayConfig, - @Nullable VirtualDisplay.Callback callback, @Nullable Handler handler) { + @Nullable VirtualDisplay.Callback callback, @Nullable Handler handler, + @Nullable Context windowContext) { return mGlobal.createVirtualDisplay(mContext, projection, virtualDisplayConfig, callback, - handler); + handler, windowContext); } /** @@ -939,6 +942,34 @@ public final class DisplayManager { setBrightnessConfigurationForUser(c, mContext.getUserId(), mContext.getPackageName()); } + /** + * Sets the brightness configuration for the specified display. + * If the specified display doesn't exist, then this will return and do nothing. + * + * @hide + */ + @SystemApi + @RequiresPermission(Manifest.permission.CONFIGURE_DISPLAY_BRIGHTNESS) + public void setBrightnessConfigurationForDisplay(@NonNull BrightnessConfiguration c, + @NonNull String uniqueId) { + mGlobal.setBrightnessConfigurationForDisplay(c, uniqueId, mContext.getUserId(), + mContext.getPackageName()); + } + + /** + * Gets the brightness configuration for the specified display and default user. + * Returns the default configuration if unset or display is invalid. + * + * @hide + */ + @Nullable + @SystemApi + @RequiresPermission(Manifest.permission.CONFIGURE_DISPLAY_BRIGHTNESS) + public BrightnessConfiguration getBrightnessConfigurationForDisplay( + @NonNull String uniqueId) { + return mGlobal.getBrightnessConfigurationForDisplay(uniqueId, mContext.getUserId()); + } + /** * Sets the global display brightness configuration for a specific user. * diff --git a/core/java/android/hardware/display/DisplayManagerGlobal.java b/core/java/android/hardware/display/DisplayManagerGlobal.java index 6c3936569c28..1fec3c9ff50a 100644 --- a/core/java/android/hardware/display/DisplayManagerGlobal.java +++ b/core/java/android/hardware/display/DisplayManagerGlobal.java @@ -583,7 +583,7 @@ public final class DisplayManagerGlobal { public VirtualDisplay createVirtualDisplay(@NonNull Context context, MediaProjection projection, @NonNull VirtualDisplayConfig virtualDisplayConfig, VirtualDisplay.Callback callback, - Handler handler) { + Handler handler, @Nullable Context windowContext) { VirtualDisplayCallback callbackWrapper = new VirtualDisplayCallback(callback, handler); IMediaProjection projectionToken = projection != null ? projection.getProjection() : null; int displayId; @@ -609,7 +609,7 @@ public final class DisplayManagerGlobal { return null; } return new VirtualDisplay(this, display, callbackWrapper, - virtualDisplayConfig.getSurface()); + virtualDisplayConfig.getSurface(), windowContext); } public void setVirtualDisplaySurface(IVirtualDisplayCallback token, Surface surface) { @@ -709,6 +709,34 @@ public final class DisplayManagerGlobal { } } + /** + * Sets the brightness configuration for a given display. + * + * @hide + */ + public void setBrightnessConfigurationForDisplay(BrightnessConfiguration c, + String uniqueDisplayId, int userId, String packageName) { + try { + mDm.setBrightnessConfigurationForDisplay(c, uniqueDisplayId, userId, packageName); + } catch (RemoteException ex) { + throw ex.rethrowFromSystemServer(); + } + } + + /** + * Gets the brightness configuration for a given display or null if one hasn't been set. + * + * @hide + */ + public BrightnessConfiguration getBrightnessConfigurationForDisplay(String uniqueDisplayId, + int userId) { + try { + return mDm.getBrightnessConfigurationForDisplay(uniqueDisplayId, userId); + } catch (RemoteException ex) { + throw ex.rethrowFromSystemServer(); + } + } + /** * Gets the global brightness configuration for a given user or null if one hasn't been set. * diff --git a/core/java/android/hardware/display/DisplayManagerInternal.java b/core/java/android/hardware/display/DisplayManagerInternal.java index abcc33c43c74..4f205530ef0d 100644 --- a/core/java/android/hardware/display/DisplayManagerInternal.java +++ b/core/java/android/hardware/display/DisplayManagerInternal.java @@ -21,6 +21,7 @@ import android.annotation.Nullable; import android.graphics.Point; import android.hardware.SensorManager; import android.os.Handler; +import android.os.IBinder; import android.os.PowerManager; import android.util.IntArray; import android.util.Slog; @@ -339,6 +340,28 @@ public abstract class DisplayManagerInternal { */ public abstract List getRefreshRateLimitations(int displayId); + /** + * Returns the window token of the level of the WindowManager hierarchy to mirror. Returns null + * if layer mirroring by SurfaceFlinger should not be performed for the given displayId. + * For now, only used for mirroring started from MediaProjection. + */ + public abstract IBinder getWindowTokenClientToMirror(int displayId); + + /** + * For the given displayId, updates the window token of the level of the WindowManager hierarchy + * to mirror. If windowToken is null, then SurfaceFlinger performs no layer mirroring to the + * given display. + * For now, only used for mirroring started from MediaProjection. + */ + public abstract void setWindowTokenClientToMirror(int displayId, IBinder windowToken); + + /** + * Returns the default size of the surface associated with the display, or null if the surface + * is not provided for layer mirroring by SurfaceFlinger. + * For now, only used for mirroring started from MediaProjection. + */ + public abstract Point getDisplaySurfaceDefaultSize(int displayId); + /** * Describes the requested power state of the display. * diff --git a/core/java/android/hardware/display/IDisplayManager.aidl b/core/java/android/hardware/display/IDisplayManager.aidl index 2303353ad101..116214625e26 100644 --- a/core/java/android/hardware/display/IDisplayManager.aidl +++ b/core/java/android/hardware/display/IDisplayManager.aidl @@ -118,6 +118,16 @@ interface IDisplayManager { void setBrightnessConfigurationForUser(in BrightnessConfiguration c, int userId, String packageName); + // Sets the global brightness configuration for a given display. Requires + // CONFIGURE_DISPLAY_BRIGHTNESS. + void setBrightnessConfigurationForDisplay(in BrightnessConfiguration c, String uniqueDisplayId, + int userId, String packageName); + + // Gets the brightness configuration for a given display. Requires + // CONFIGURE_DISPLAY_BRIGHTNESS. + BrightnessConfiguration getBrightnessConfigurationForDisplay(String uniqueDisplayId, + int userId); + // Gets the global brightness configuration for a given user. Requires // CONFIGURE_DISPLAY_BRIGHTNESS, and INTERACT_ACROSS_USER if the user is not // the same as the calling user. diff --git a/core/java/android/hardware/display/VirtualDisplay.java b/core/java/android/hardware/display/VirtualDisplay.java index bf62c95cf6db..71cbd20e8005 100644 --- a/core/java/android/hardware/display/VirtualDisplay.java +++ b/core/java/android/hardware/display/VirtualDisplay.java @@ -15,6 +15,8 @@ */ package android.hardware.display; +import android.annotation.Nullable; +import android.content.Context; import android.view.Display; import android.view.Surface; @@ -36,13 +38,19 @@ public final class VirtualDisplay { private final Display mDisplay; private IVirtualDisplayCallback mToken; private Surface mSurface; + /** + * Store the WindowContext in a field. If it is a local variable, and it is garbage collected + * during a MediaProjection session, the WindowContainer listener no longer exists. + */ + @Nullable private final Context mWindowContext; VirtualDisplay(DisplayManagerGlobal global, Display display, - IVirtualDisplayCallback token, Surface surface) { + IVirtualDisplayCallback token, Surface surface, Context windowContext) { mGlobal = global; mDisplay = display; mToken = token; mSurface = surface; + mWindowContext = windowContext; } /** diff --git a/core/java/android/hardware/display/VirtualDisplayConfig.java b/core/java/android/hardware/display/VirtualDisplayConfig.java index 71688c7cc7e8..0e86f43207aa 100644 --- a/core/java/android/hardware/display/VirtualDisplayConfig.java +++ b/core/java/android/hardware/display/VirtualDisplayConfig.java @@ -23,6 +23,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.media.projection.MediaProjection; import android.os.Handler; +import android.os.IBinder; import android.os.Parcel; import android.os.Parcelable; import android.view.Surface; @@ -91,9 +92,16 @@ public final class VirtualDisplayConfig implements Parcelable { */ private int mDisplayIdToMirror = DEFAULT_DISPLAY; + /** + * The window token of the level of the WindowManager hierarchy to mirror, or null if mirroring + * should not be performed. + */ + @Nullable + private IBinder mWindowTokenClientToMirror = null; - // Code below generated by codegen v1.0.20. + + // Code below generated by codegen v1.0.23. // // DO NOT MODIFY! // CHECKSTYLE:OFF Generated code @@ -115,7 +123,8 @@ public final class VirtualDisplayConfig implements Parcelable { int flags, @Nullable Surface surface, @Nullable String uniqueId, - int displayIdToMirror) { + int displayIdToMirror, + @Nullable IBinder windowTokenClientToMirror) { this.mName = name; com.android.internal.util.AnnotationValidations.validate( NonNull.class, null, mName); @@ -135,6 +144,7 @@ public final class VirtualDisplayConfig implements Parcelable { this.mSurface = surface; this.mUniqueId = uniqueId; this.mDisplayIdToMirror = displayIdToMirror; + this.mWindowTokenClientToMirror = windowTokenClientToMirror; // onConstructed(); // You can define this method to get a callback } @@ -212,6 +222,15 @@ public final class VirtualDisplayConfig implements Parcelable { return mDisplayIdToMirror; } + /** + * The window token of the level of the WindowManager hierarchy to mirror, or null if mirroring + * should not be performed. + */ + @DataClass.Generated.Member + public @Nullable IBinder getWindowTokenClientToMirror() { + return mWindowTokenClientToMirror; + } + @Override @DataClass.Generated.Member public void writeToParcel(@NonNull Parcel dest, int flags) { @@ -221,6 +240,7 @@ public final class VirtualDisplayConfig implements Parcelable { int flg = 0; if (mSurface != null) flg |= 0x20; if (mUniqueId != null) flg |= 0x40; + if (mWindowTokenClientToMirror != null) flg |= 0x100; dest.writeInt(flg); dest.writeString(mName); dest.writeInt(mWidth); @@ -230,6 +250,7 @@ public final class VirtualDisplayConfig implements Parcelable { if (mSurface != null) dest.writeTypedObject(mSurface, flags); if (mUniqueId != null) dest.writeString(mUniqueId); dest.writeInt(mDisplayIdToMirror); + if (mWindowTokenClientToMirror != null) dest.writeStrongBinder(mWindowTokenClientToMirror); } @Override @@ -252,6 +273,7 @@ public final class VirtualDisplayConfig implements Parcelable { Surface surface = (flg & 0x20) == 0 ? null : (Surface) in.readTypedObject(Surface.CREATOR); String uniqueId = (flg & 0x40) == 0 ? null : in.readString(); int displayIdToMirror = in.readInt(); + IBinder windowTokenClientToMirror = (flg & 0x100) == 0 ? null : (IBinder) in.readStrongBinder(); this.mName = name; com.android.internal.util.AnnotationValidations.validate( @@ -272,6 +294,7 @@ public final class VirtualDisplayConfig implements Parcelable { this.mSurface = surface; this.mUniqueId = uniqueId; this.mDisplayIdToMirror = displayIdToMirror; + this.mWindowTokenClientToMirror = windowTokenClientToMirror; // onConstructed(); // You can define this method to get a callback } @@ -305,6 +328,7 @@ public final class VirtualDisplayConfig implements Parcelable { private @Nullable Surface mSurface; private @Nullable String mUniqueId; private int mDisplayIdToMirror; + private @Nullable IBinder mWindowTokenClientToMirror; private long mBuilderFieldsSet = 0L; @@ -439,10 +463,22 @@ public final class VirtualDisplayConfig implements Parcelable { return this; } + /** + * The window token of the level of the WindowManager hierarchy to mirror, or null if mirroring + * should not be performed. + */ + @DataClass.Generated.Member + public @NonNull Builder setWindowTokenClientToMirror(@NonNull IBinder value) { + checkNotUsed(); + mBuilderFieldsSet |= 0x100; + mWindowTokenClientToMirror = value; + return this; + } + /** Builds the instance. This builder should not be touched after calling this! */ public @NonNull VirtualDisplayConfig build() { checkNotUsed(); - mBuilderFieldsSet |= 0x100; // Mark builder used + mBuilderFieldsSet |= 0x200; // Mark builder used if ((mBuilderFieldsSet & 0x10) == 0) { mFlags = 0; @@ -456,6 +492,9 @@ public final class VirtualDisplayConfig implements Parcelable { if ((mBuilderFieldsSet & 0x80) == 0) { mDisplayIdToMirror = DEFAULT_DISPLAY; } + if ((mBuilderFieldsSet & 0x100) == 0) { + mWindowTokenClientToMirror = null; + } VirtualDisplayConfig o = new VirtualDisplayConfig( mName, mWidth, @@ -464,12 +503,13 @@ public final class VirtualDisplayConfig implements Parcelable { mFlags, mSurface, mUniqueId, - mDisplayIdToMirror); + mDisplayIdToMirror, + mWindowTokenClientToMirror); return o; } private void checkNotUsed() { - if ((mBuilderFieldsSet & 0x100) != 0) { + if ((mBuilderFieldsSet & 0x200) != 0) { throw new IllegalStateException( "This Builder should not be reused. Use a new Builder instance instead"); } @@ -477,10 +517,10 @@ public final class VirtualDisplayConfig implements Parcelable { } @DataClass.Generated( - time = 1604456298440L, - codegenVersion = "1.0.20", + time = 1620657851981L, + codegenVersion = "1.0.23", sourceFile = "frameworks/base/core/java/android/hardware/display/VirtualDisplayConfig.java", - inputSignatures = "private @android.annotation.NonNull java.lang.String mName\nprivate @android.annotation.IntRange int mWidth\nprivate @android.annotation.IntRange int mHeight\nprivate @android.annotation.IntRange int mDensityDpi\nprivate int mFlags\nprivate @android.annotation.Nullable android.view.Surface mSurface\nprivate @android.annotation.Nullable java.lang.String mUniqueId\nprivate int mDisplayIdToMirror\nclass VirtualDisplayConfig extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genParcelable=true, genAidl=true, genBuilder=true)") + inputSignatures = "private @android.annotation.NonNull java.lang.String mName\nprivate @android.annotation.IntRange int mWidth\nprivate @android.annotation.IntRange int mHeight\nprivate @android.annotation.IntRange int mDensityDpi\nprivate int mFlags\nprivate @android.annotation.Nullable android.view.Surface mSurface\nprivate @android.annotation.Nullable java.lang.String mUniqueId\nprivate int mDisplayIdToMirror\nprivate @android.annotation.Nullable android.os.IBinder mWindowTokenClientToMirror\nclass VirtualDisplayConfig extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genParcelable=true, genAidl=true, genBuilder=true)") @Deprecated private void __metadata() {} diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java index a3d595c23095..fe04e5d35784 100644 --- a/core/java/android/hardware/fingerprint/FingerprintManager.java +++ b/core/java/android/hardware/fingerprint/FingerprintManager.java @@ -531,7 +531,7 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing @RequiresPermission(anyOf = {USE_BIOMETRIC, USE_FINGERPRINT}) public void authenticate(@Nullable CryptoObject crypto, @Nullable CancellationSignal cancel, int flags, @NonNull AuthenticationCallback callback, @Nullable Handler handler) { - authenticate(crypto, cancel, callback, handler, mContext.getUserId()); + authenticate(crypto, cancel, callback, handler, SENSOR_ID_ANY, mContext.getUserId(), flags); } /** @@ -541,7 +541,7 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing @RequiresPermission(anyOf = {USE_BIOMETRIC, USE_FINGERPRINT}) public void authenticate(@Nullable CryptoObject crypto, @Nullable CancellationSignal cancel, @NonNull AuthenticationCallback callback, Handler handler, int userId) { - authenticate(crypto, cancel, callback, handler, SENSOR_ID_ANY, userId); + authenticate(crypto, cancel, callback, handler, SENSOR_ID_ANY, userId, 0 /* flags */); } /** @@ -550,7 +550,8 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing */ @RequiresPermission(anyOf = {USE_BIOMETRIC, USE_FINGERPRINT}) public void authenticate(@Nullable CryptoObject crypto, @Nullable CancellationSignal cancel, - @NonNull AuthenticationCallback callback, Handler handler, int sensorId, int userId) { + @NonNull AuthenticationCallback callback, Handler handler, int sensorId, int userId, + int flags) { FrameworkStatsLog.write(FrameworkStatsLog.AUTH_DEPRECATED_API_USED, AUTH_DEPRECATED_APIUSED__DEPRECATED_API__API_FINGERPRINT_MANAGER_AUTHENTICATE, @@ -566,6 +567,8 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing return; } + final boolean ignoreEnrollmentState = flags == 0 ? false : true; + if (mService != null) { try { useHandler(handler); @@ -573,7 +576,7 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing mCryptoObject = crypto; final long operationId = crypto != null ? crypto.getOpId() : 0; final long authId = mService.authenticate(mToken, operationId, sensorId, userId, - mServiceReceiver, mContext.getOpPackageName()); + mServiceReceiver, mContext.getOpPackageName(), ignoreEnrollmentState); if (cancel != null) { cancel.setOnCancelListener(new OnAuthenticationCancelListener(authId)); } diff --git a/core/java/android/hardware/fingerprint/FingerprintSensorPropertiesInternal.java b/core/java/android/hardware/fingerprint/FingerprintSensorPropertiesInternal.java index 45c6b290be11..4bf9a740f971 100644 --- a/core/java/android/hardware/fingerprint/FingerprintSensorPropertiesInternal.java +++ b/core/java/android/hardware/fingerprint/FingerprintSensorPropertiesInternal.java @@ -21,7 +21,9 @@ import static android.hardware.fingerprint.FingerprintSensorProperties.TYPE_UDFP import static android.hardware.fingerprint.FingerprintSensorProperties.TYPE_UDFPS_ULTRASONIC; import android.annotation.NonNull; +import android.annotation.Nullable; import android.hardware.biometrics.ComponentInfoInternal; +import android.hardware.biometrics.SensorLocationInternal; import android.hardware.biometrics.SensorProperties; import android.hardware.biometrics.SensorPropertiesInternal; import android.os.Parcel; @@ -38,34 +40,14 @@ public class FingerprintSensorPropertiesInternal extends SensorPropertiesInterna */ public final @FingerprintSensorProperties.SensorType int sensorType; - /** - * The location of the center of the sensor if applicable. For example, sensors of type - * {@link FingerprintSensorProperties#TYPE_UDFPS_OPTICAL} would report this value as the - * distance in pixels, measured from the left edge of the screen. - */ - public final int sensorLocationX; - - /** - * The location of the center of the sensor if applicable. For example, sensors of type - * {@link FingerprintSensorProperties#TYPE_UDFPS_OPTICAL} would report this value as the - * distance in pixels, measured from the top edge of the screen. - * - */ - public final int sensorLocationY; - - /** - * The radius of the sensor if applicable. For example, sensors of type - * {@link FingerprintSensorProperties#TYPE_UDFPS_OPTICAL} would report this value as the radius - * of the sensor, in pixels. - */ - public final int sensorRadius; + private final List mSensorLocations; public FingerprintSensorPropertiesInternal(int sensorId, @SensorProperties.Strength int strength, int maxEnrollmentsPerUser, @NonNull List componentInfo, @FingerprintSensorProperties.SensorType int sensorType, - boolean resetLockoutRequiresHardwareAuthToken, int sensorLocationX, int sensorLocationY, - int sensorRadius) { + boolean resetLockoutRequiresHardwareAuthToken, + @NonNull List sensorLocations) { // IBiometricsFingerprint@2.1 handles lockout in the framework, so the challenge is not // required as it can only be generated/attested/verified by TEE components. // IFingerprint@1.0 handles lockout below the HAL, but does not require a challenge. See @@ -73,9 +55,7 @@ public class FingerprintSensorPropertiesInternal extends SensorPropertiesInterna super(sensorId, strength, maxEnrollmentsPerUser, componentInfo, resetLockoutRequiresHardwareAuthToken, false /* resetLockoutRequiresChallenge */); this.sensorType = sensorType; - this.sensorLocationX = sensorLocationX; - this.sensorLocationY = sensorLocationY; - this.sensorRadius = sensorRadius; + this.mSensorLocations = List.copyOf(sensorLocations); } /** @@ -88,16 +68,15 @@ public class FingerprintSensorPropertiesInternal extends SensorPropertiesInterna boolean resetLockoutRequiresHardwareAuthToken) { // TODO(b/179175438): Value should be provided from the HAL this(sensorId, strength, maxEnrollmentsPerUser, componentInfo, sensorType, - resetLockoutRequiresHardwareAuthToken, 540 /* sensorLocationX */, - 1636 /* sensorLocationY */, 130 /* sensorRadius */); + resetLockoutRequiresHardwareAuthToken, List.of(new SensorLocationInternal( + "" /* displayId */, 540 /* sensorLocationX */, 1636 /* sensorLocationY */, + 130 /* sensorRadius */))); } protected FingerprintSensorPropertiesInternal(Parcel in) { super(in); sensorType = in.readInt(); - sensorLocationX = in.readInt(); - sensorLocationY = in.readInt(); - sensorRadius = in.readInt(); + mSensorLocations = in.createTypedArrayList(SensorLocationInternal.CREATOR); } public static final Creator CREATOR = @@ -122,9 +101,7 @@ public class FingerprintSensorPropertiesInternal extends SensorPropertiesInterna public void writeToParcel(Parcel dest, int flags) { super.writeToParcel(dest, flags); dest.writeInt(sensorType); - dest.writeInt(sensorLocationX); - dest.writeInt(sensorLocationY); - dest.writeInt(sensorRadius); + dest.writeTypedList(mSensorLocations); } public boolean isAnyUdfpsType() { @@ -150,6 +127,44 @@ public class FingerprintSensorPropertiesInternal extends SensorPropertiesInterna } } + /** + * Get the default location. + * + * Use this method when the sensor's relationship to the displays on the device do not + * matter. + * @return + */ + @NonNull + public SensorLocationInternal getLocation() { + final SensorLocationInternal location = getLocation("" /* displayId */); + return location != null ? location : SensorLocationInternal.DEFAULT; + } + + /** + * Get the location of a sensor relative to a physical display layout. + * + * @param displayId stable display id + * @return location or null if none is specified + */ + @Nullable + public SensorLocationInternal getLocation(String displayId) { + for (SensorLocationInternal location : mSensorLocations) { + if (location.displayId.equals(displayId)) { + return location; + } + } + return null; + } + + /** + * Gets all locations relative to all supported display layouts. + * @return supported locations + */ + @NonNull + public List getAllLocations() { + return mSensorLocations; + } + @Override public String toString() { return "ID: " + sensorId + ", Strength: " + sensorStrength + ", Type: " + sensorType; diff --git a/core/java/android/hardware/fingerprint/IFingerprintService.aidl b/core/java/android/hardware/fingerprint/IFingerprintService.aidl index de94b2fbb5b5..ba1dc6da62a6 100644 --- a/core/java/android/hardware/fingerprint/IFingerprintService.aidl +++ b/core/java/android/hardware/fingerprint/IFingerprintService.aidl @@ -52,7 +52,8 @@ interface IFingerprintService { // permission. This is effectively deprecated, since it only comes through FingerprintManager // now. A requestId is returned that can be used to cancel this operation. long authenticate(IBinder token, long operationId, int sensorId, int userId, - IFingerprintServiceReceiver receiver, String opPackageName); + IFingerprintServiceReceiver receiver, String opPackageName, + boolean shouldIgnoreEnrollmentState); // Uses the fingerprint hardware to detect for the presence of a finger, without giving details // about accept/reject/lockout. A requestId is returned that can be used to cancel this diff --git a/core/java/android/hardware/fingerprint/ISidefpsController.aidl b/core/java/android/hardware/fingerprint/ISidefpsController.aidl index 00f40048cbae..684f18f3fd94 100644 --- a/core/java/android/hardware/fingerprint/ISidefpsController.aidl +++ b/core/java/android/hardware/fingerprint/ISidefpsController.aidl @@ -21,9 +21,9 @@ package android.hardware.fingerprint; */ oneway interface ISidefpsController { - // Shows the overlay. - void show(); + // Shows the overlay for the given sensor with a reason from BiometricOverlayConstants. + void show(int sensorId, int reason); // Hides the overlay. - void hide(); + void hide(int sensorId); } diff --git a/core/java/android/hardware/fingerprint/IUdfpsOverlayController.aidl b/core/java/android/hardware/fingerprint/IUdfpsOverlayController.aidl index f18360ff4108..648edda62171 100644 --- a/core/java/android/hardware/fingerprint/IUdfpsOverlayController.aidl +++ b/core/java/android/hardware/fingerprint/IUdfpsOverlayController.aidl @@ -22,14 +22,7 @@ import android.hardware.fingerprint.IUdfpsOverlayControllerCallback; * @hide */ oneway interface IUdfpsOverlayController { - const int REASON_UNKNOWN = 0; - const int REASON_ENROLL_FIND_SENSOR = 1; - const int REASON_ENROLL_ENROLLING = 2; - const int REASON_AUTH_BP = 3; // BiometricPrompt - const int REASON_AUTH_FPM_KEYGUARD = 4; // FingerprintManager usage from Keyguard - const int REASON_AUTH_FPM_OTHER = 5; // Other FingerprintManager usage - - // Shows the overlay. + // Shows the overlay for the given sensor with a reason from BiometricOverlayConstants. void showUdfpsOverlay(int sensorId, int reason, IUdfpsOverlayControllerCallback callback); // Hides the overlay. diff --git a/core/java/android/inputmethodservice/AbstractInputMethodService.java b/core/java/android/inputmethodservice/AbstractInputMethodService.java index 3cd13a212a4b..f8f0970ecfe4 100644 --- a/core/java/android/inputmethodservice/AbstractInputMethodService.java +++ b/core/java/android/inputmethodservice/AbstractInputMethodService.java @@ -18,16 +18,23 @@ package android.inputmethodservice; import android.annotation.MainThread; import android.annotation.NonNull; -import android.app.Service; +import android.annotation.Nullable; +import android.content.Context; import android.content.Intent; +import android.content.res.Configuration; +import android.os.Bundle; import android.os.IBinder; +import android.os.RemoteException; import android.util.proto.ProtoOutputStream; import android.view.KeyEvent; import android.view.MotionEvent; +import android.view.WindowManager; +import android.view.WindowManagerGlobal; import android.view.inputmethod.InputConnection; import android.view.inputmethod.InputContentInfo; import android.view.inputmethod.InputMethod; import android.view.inputmethod.InputMethodSession; +import android.window.WindowProviderService; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -44,9 +51,22 @@ import java.io.PrintWriter; * implement. This base class takes care of reporting your InputMethod from * the service when clients bind to it, but provides no standard implementation * of the InputMethod interface itself. Derived classes must implement that - * interface. + * interface.

+ * + *

After {@link android.os.Build.VERSION_CODES#S}, the maximum possible area to show the soft + * input may not be the entire screen. For example, some devices may support to show the soft input + * on only half of screen.

+ * + *

In that case, moving the soft input from one half screen to another will trigger a + * {@link android.content.res.Resources} update to match the new {@link Configuration} and + * this {@link AbstractInputMethodService} may also receive a + * {@link #onConfigurationChanged(Configuration)} callback if there's notable configuration changes + *

+ * + * @see android.content.ComponentCallbacks#onConfigurationChanged(Configuration) + * @see Context#isUiContext Context#isUiContext to see the concept of UI Context. */ -public abstract class AbstractInputMethodService extends Service +public abstract class AbstractInputMethodService extends WindowProviderService implements KeyEvent.Callback { private InputMethod mInputMethod; @@ -272,9 +292,33 @@ public abstract class AbstractInputMethodService extends Service public void notifyUserActionIfNecessary() { } + // TODO(b/149463653): remove it in T. We missed the API deadline in S. /** @hide */ @Override public final boolean isUiContext() { return true; } + + /** @hide */ + @Override + public final int getWindowType() { + return WindowManager.LayoutParams.TYPE_INPUT_METHOD; + } + + /** @hide */ + @Override + @Nullable + public final Bundle getWindowContextOptions() { + return super.getWindowContextOptions(); + } + + /** @hide */ + @Override + public final int getInitialDisplayId() { + try { + return WindowManagerGlobal.getWindowManagerService().getImeDisplayId(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } } diff --git a/core/java/android/inputmethodservice/IInputMethodWrapper.java b/core/java/android/inputmethodservice/IInputMethodWrapper.java index 9198eb74d1f8..89612fe753df 100644 --- a/core/java/android/inputmethodservice/IInputMethodWrapper.java +++ b/core/java/android/inputmethodservice/IInputMethodWrapper.java @@ -170,8 +170,8 @@ class IInputMethodWrapper extends IInputMethod.Stub case DO_INITIALIZE_INTERNAL: { SomeArgs args = (SomeArgs) msg.obj; try { - inputMethod.initializeInternal((IBinder) args.arg1, msg.arg1, - (IInputMethodPrivilegedOperations) args.arg2, (int) args.arg3); + inputMethod.initializeInternal((IBinder) args.arg1, + (IInputMethodPrivilegedOperations) args.arg2, msg.arg1); } finally { args.recycle(); } @@ -279,11 +279,10 @@ class IInputMethodWrapper extends IInputMethod.Stub @BinderThread @Override - public void initializeInternal(IBinder token, int displayId, - IInputMethodPrivilegedOperations privOps, int configChanges) { + public void initializeInternal(IBinder token, IInputMethodPrivilegedOperations privOps, + int configChanges) { mCaller.executeOrSendMessage( - mCaller.obtainMessageIOOO(DO_INITIALIZE_INTERNAL, displayId, token, privOps, - configChanges)); + mCaller.obtainMessageIOO(DO_INITIALIZE_INTERNAL, configChanges, token, privOps)); } @BinderThread diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java index 74cb42db7858..9f798869e54a 100644 --- a/core/java/android/inputmethodservice/InputMethodService.java +++ b/core/java/android/inputmethodservice/InputMethodService.java @@ -395,7 +395,7 @@ public class InputMethodService extends AbstractInputMethodService { /** * @hide - * The IME is visible. + * The IME is perceptibly visible to the user. */ public static final int IME_VISIBLE = 0x2; @@ -406,6 +406,15 @@ public class InputMethodService extends AbstractInputMethodService { */ public static final int IME_INVISIBLE = 0x4; + /** + * @hide + * The IME is visible, but not yet perceptible to the user (e.g. fading in) + * by {@link android.view.WindowInsetsController}. + * + * @see InputMethodManager#reportPerceptible + */ + public static final int IME_VISIBLE_IMPERCEPTIBLE = 0x8; + // Min and max values for back disposition. private static final int BACK_DISPOSITION_MIN = BACK_DISPOSITION_DEFAULT; private static final int BACK_DISPOSITION_MAX = BACK_DISPOSITION_ADJUST_NOTHING; @@ -515,6 +524,7 @@ public class InputMethodService extends AbstractInputMethodService { private Handler mHandler; private boolean mImeSurfaceScheduledForRemoval; private ImsConfigurationTracker mConfigTracker = new ImsConfigurationTracker(); + private boolean mDestroyed; /** * An opaque {@link Binder} token of window requesting {@link InputMethodImpl#showSoftInput} @@ -589,17 +599,21 @@ public class InputMethodService extends AbstractInputMethodService { */ @MainThread @Override - public final void initializeInternal(@NonNull IBinder token, int displayId, + public final void initializeInternal(@NonNull IBinder token, IInputMethodPrivilegedOperations privilegedOperations, int configChanges) { if (InputMethodPrivilegedOperationsRegistry.isRegistered(token)) { Log.w(TAG, "The token has already registered, ignore this initialization."); return; } + if (mDestroyed) { + Log.i(TAG, "The InputMethodService has already onDestroyed()." + + "Ignore the initialization."); + return; + } Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMS.initializeInternal"); mConfigTracker.onInitialize(configChanges); mPrivOps.set(privilegedOperations); InputMethodPrivilegedOperationsRegistry.put(token, mPrivOps); - updateInputMethodDisplay(displayId); attachToken(token); Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); } @@ -629,27 +643,11 @@ public class InputMethodService extends AbstractInputMethodService { throw new IllegalStateException( "attachToken() must be called at most once. token=" + token); } + attachToWindowToken(token); mToken = token; mWindow.setToken(token); } - /** - * {@inheritDoc} - * @hide - */ - @MainThread - @Override - public void updateInputMethodDisplay(int displayId) { - if (getDisplayId() == displayId) { - return; - } - // Update display for adding IME window to the right display. - // TODO(b/111364446) Need to address context lifecycle issue if need to re-create - // for update resources & configuration correctly when show soft input - // in non-default display. - updateDisplay(displayId); - } - /** * {@inheritDoc} * @@ -807,11 +805,6 @@ public class InputMethodService extends AbstractInputMethodService { return; } - if (Trace.isEnabled()) { - Binder.enableTracing(); - } else { - Binder.disableTracing(); - } Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMS.showSoftInput"); ImeTracing.getInstance().triggerServiceDump( "InputMethodService.InputMethodImpl#showSoftInput", InputMethodService.this, @@ -1416,6 +1409,7 @@ public class InputMethodService extends AbstractInputMethodService { } @Override public void onDestroy() { + mDestroyed = true; super.onDestroy(); mRootView.getViewTreeObserver().removeOnComputeInternalInsetsListener( mInsetsComputer); diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java index 762816dd9f11..798a0015925e 100644 --- a/core/java/android/net/NetworkTemplate.java +++ b/core/java/android/net/NetworkTemplate.java @@ -47,7 +47,6 @@ import android.text.TextUtils; import android.util.BackupUtils; import android.util.Log; -import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ArrayUtils; import com.android.net.module.util.NetworkIdentityUtils; @@ -151,24 +150,6 @@ public class NetworkTemplate implements Parcelable { } } - private static boolean sForceAllNetworkTypes = false; - - /** - * Results in matching against all mobile network types. - * - *

See {@link #matchesMobile} and {@link matchesMobileWildcard}. - */ - @VisibleForTesting - public static void forceAllNetworkTypes() { - sForceAllNetworkTypes = true; - } - - /** Resets the affect of {@link #forceAllNetworkTypes}. */ - @VisibleForTesting - public static void resetForceAllNetworkTypes() { - sForceAllNetworkTypes = false; - } - /** * Template to match {@link ConnectivityManager#TYPE_MOBILE} networks with * the given IMSI. @@ -179,19 +160,19 @@ public class NetworkTemplate implements Parcelable { } /** - * Template to match cellular networks with the given IMSI and {@code ratType}. - * Use {@link #NETWORK_TYPE_ALL} to include all network types when filtering. - * See {@code TelephonyManager.NETWORK_TYPE_*}. + * Template to match cellular networks with the given IMSI, {@code ratType} and + * {@code metered}. Use {@link #NETWORK_TYPE_ALL} to include all network types when + * filtering. See {@code TelephonyManager.NETWORK_TYPE_*}. */ public static NetworkTemplate buildTemplateMobileWithRatType(@Nullable String subscriberId, - @NetworkType int ratType) { + @NetworkType int ratType, int metered) { if (TextUtils.isEmpty(subscriberId)) { return new NetworkTemplate(MATCH_MOBILE_WILDCARD, null, null, null, - METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType, OEM_MANAGED_ALL, + metered, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType, OEM_MANAGED_ALL, SUBSCRIBER_ID_MATCH_RULE_EXACT); } return new NetworkTemplate(MATCH_MOBILE, subscriberId, new String[]{subscriberId}, null, - METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType, OEM_MANAGED_ALL, + metered, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType, OEM_MANAGED_ALL, SUBSCRIBER_ID_MATCH_RULE_EXACT); } @@ -324,6 +305,7 @@ public class NetworkTemplate implements Parcelable { } } + // TODO: Deprecate this constructor, mark it @UnsupportedAppUsage(maxTargetSdk = S) @UnsupportedAppUsage public NetworkTemplate(int matchRule, String subscriberId, String networkId) { this(matchRule, subscriberId, new String[] { subscriberId }, networkId); @@ -331,9 +313,14 @@ public class NetworkTemplate implements Parcelable { public NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds, String networkId) { - this(matchRule, subscriberId, matchSubscriberIds, networkId, METERED_ALL, ROAMING_ALL, - DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_ALL, - SUBSCRIBER_ID_MATCH_RULE_EXACT); + // Older versions used to only match MATCH_MOBILE and MATCH_MOBILE_WILDCARD templates + // to metered networks. It is now possible to match mobile with any meteredness, but + // in order to preserve backward compatibility of @UnsupportedAppUsage methods, this + //constructor passes METERED_YES for these types. + this(matchRule, subscriberId, matchSubscriberIds, networkId, + (matchRule == MATCH_MOBILE || matchRule == MATCH_MOBILE_WILDCARD) ? METERED_YES + : METERED_ALL , ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, + OEM_MANAGED_ALL, SUBSCRIBER_ID_MATCH_RULE_EXACT); } // TODO: Remove it after updating all of the caller. @@ -608,11 +595,7 @@ public class NetworkTemplate implements Parcelable { // TODO: consider matching against WiMAX subscriber identity return true; } else { - // Only metered mobile network would be matched regardless of metered filter. - // This is used to exclude non-metered APNs, e.g. IMS. See ag/908650. - // TODO: Respect metered filter and remove mMetered condition. - return (sForceAllNetworkTypes || (ident.mType == TYPE_MOBILE && ident.mMetered)) - && !ArrayUtils.isEmpty(mMatchSubscriberIds) + return ident.mType == TYPE_MOBILE && !ArrayUtils.isEmpty(mMatchSubscriberIds) && ArrayUtils.contains(mMatchSubscriberIds, ident.mSubscriberId) && matchesCollapsedRatType(ident); } @@ -726,8 +709,7 @@ public class NetworkTemplate implements Parcelable { if (ident.mType == TYPE_WIMAX) { return true; } else { - return (sForceAllNetworkTypes || (ident.mType == TYPE_MOBILE && ident.mMetered)) - && matchesCollapsedRatType(ident); + return ident.mType == TYPE_MOBILE && matchesCollapsedRatType(ident); } } diff --git a/core/java/android/os/AppZygote.java b/core/java/android/os/AppZygote.java index 74b814ea4159..c8b4226ecae0 100644 --- a/core/java/android/os/AppZygote.java +++ b/core/java/android/os/AppZygote.java @@ -45,6 +45,8 @@ public class AppZygote { // Last UID/GID of the range the AppZygote can setuid()/setgid() to private final int mZygoteUidGidMax; + private final int mZygoteRuntimeFlags; + private final Object mLock = new Object(); /** @@ -56,11 +58,13 @@ public class AppZygote { private final ApplicationInfo mAppInfo; - public AppZygote(ApplicationInfo appInfo, int zygoteUid, int uidGidMin, int uidGidMax) { + public AppZygote(ApplicationInfo appInfo, int zygoteUid, int uidGidMin, int uidGidMax, + int runtimeFlags) { mAppInfo = appInfo; mZygoteUid = zygoteUid; mZygoteUidGidMin = uidGidMin; mZygoteUidGidMax = uidGidMax; + mZygoteRuntimeFlags = runtimeFlags; } /** @@ -110,7 +114,7 @@ public class AppZygote { mZygoteUid, mZygoteUid, null, // gids - 0, // runtimeFlags + mZygoteRuntimeFlags, // runtimeFlags "app_zygote", // seInfo abi, // abi abi, // acceptedAbiList diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java index fb9911811da9..79ec55482c50 100644 --- a/core/java/android/os/BatteryStats.java +++ b/core/java/android/os/BatteryStats.java @@ -2302,6 +2302,38 @@ public abstract class BatteryStats implements Parcelable { */ public abstract Timer getScreenBrightnessTimer(int brightnessBin); + /** + * Returns the number of physical displays on the device. + * + * {@hide} + */ + public abstract int getDisplayCount(); + + /** + * Returns the time in microseconds that the screen has been on for a display while the + * device was running on battery. + * + * {@hide} + */ + public abstract long getDisplayScreenOnTime(int display, long elapsedRealtimeUs); + + /** + * Returns the time in microseconds that a display has been dozing while the device was + * running on battery. + * + * {@hide} + */ + public abstract long getDisplayScreenDozeTime(int display, long elapsedRealtimeUs); + + /** + * Returns the time in microseconds that a display has been on with the given brightness + * level while the device was running on battery. + * + * {@hide} + */ + public abstract long getDisplayScreenBrightnessTime(int display, int brightnessBin, + long elapsedRealtimeUs); + /** * Returns the time in microseconds that power save mode has been enabled while the device was * running on battery. @@ -5038,6 +5070,71 @@ public abstract class BatteryStats implements Parcelable { pw.println(sb.toString()); } + final int numDisplays = getDisplayCount(); + if (numDisplays > 1) { + pw.println(""); + pw.print(prefix); + sb.setLength(0); + sb.append(prefix); + sb.append(" MULTI-DISPLAY POWER SUMMARY START"); + pw.println(sb.toString()); + + for (int display = 0; display < numDisplays; display++) { + sb.setLength(0); + sb.append(prefix); + sb.append(" Display "); + sb.append(display); + sb.append(" Statistics:"); + pw.println(sb.toString()); + + final long displayScreenOnTime = getDisplayScreenOnTime(display, rawRealtime); + sb.setLength(0); + sb.append(prefix); + sb.append(" Screen on: "); + formatTimeMs(sb, displayScreenOnTime / 1000); + sb.append("("); + sb.append(formatRatioLocked(displayScreenOnTime, whichBatteryRealtime)); + sb.append(") "); + pw.println(sb.toString()); + + sb.setLength(0); + sb.append(" Screen brightness levels:"); + didOne = false; + for (int bin = 0; bin < NUM_SCREEN_BRIGHTNESS_BINS; bin++) { + final long timeUs = getDisplayScreenBrightnessTime(display, bin, rawRealtime); + if (timeUs == 0) { + continue; + } + didOne = true; + sb.append("\n "); + sb.append(prefix); + sb.append(SCREEN_BRIGHTNESS_NAMES[bin]); + sb.append(" "); + formatTimeMs(sb, timeUs / 1000); + sb.append("("); + sb.append(formatRatioLocked(timeUs, displayScreenOnTime)); + sb.append(")"); + } + if (!didOne) sb.append(" (no activity)"); + pw.println(sb.toString()); + + final long displayScreenDozeTimeUs = getDisplayScreenDozeTime(display, rawRealtime); + sb.setLength(0); + sb.append(prefix); + sb.append(" Screen Doze: "); + formatTimeMs(sb, displayScreenDozeTimeUs / 1000); + sb.append("("); + sb.append(formatRatioLocked(displayScreenDozeTimeUs, whichBatteryRealtime)); + sb.append(") "); + pw.println(sb.toString()); + } + pw.print(prefix); + sb.setLength(0); + sb.append(prefix); + sb.append(" MULTI-DISPLAY POWER SUMMARY END"); + pw.println(sb.toString()); + } + pw.println(""); pw.print(prefix); sb.setLength(0); diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java index 6bf394dc347b..b7dd36e2c4f5 100755 --- a/core/java/android/os/Build.java +++ b/core/java/android/os/Build.java @@ -1024,7 +1024,7 @@ public class Build { * will also enable {@link StrictMode.ThreadPolicy.Builder#detectUnbufferedIo}. *

  • {@link android.provider.DocumentsContract}'s various methods will throw failure * exceptions back to the caller instead of returning null. - *
  • {@link View#hasFocusable View.hasFocusable} now includes auto-focusable views.
  • + *
  • {@link View#hasFocusable() View.hasFocusable} now includes auto-focusable views.
  • *
  • {@link android.view.SurfaceView} will no longer always change the underlying * Surface object when something about it changes; apps need to look at the current * state of the object to determine which things they are interested in have changed.
  • @@ -1130,6 +1130,15 @@ public class Build { * S. */ public static final int S = 31; + + /** + * S V2. + * + * Once more unto the breach, dear friends, once more. + * + */ + public static final int S_V2 = 32; + } /** The type of build, like "user" or "eng". */ diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java index 2ed0bad69460..0257408b3e42 100644 --- a/core/java/android/os/Environment.java +++ b/core/java/android/os/Environment.java @@ -189,13 +189,11 @@ public class Environment { } @UnsupportedAppUsage - @Deprecated public File getExternalStorageDirectory() { return getExternalDirs()[0]; } @UnsupportedAppUsage - @Deprecated public File getExternalStoragePublicDirectory(String type) { return buildExternalStoragePublicDirs(type)[0]; } @@ -695,14 +693,13 @@ public class Environment { *

    * {@sample development/samples/ApiDemos/src/com/example/android/apis/content/ExternalStorage.java * monitor_storage} + *

    + * Note that alternatives such as {@link Context#getExternalFilesDir(String)} or + * {@link MediaStore} offer better performance. * * @see #getExternalStorageState() * @see #isExternalStorageRemovable() - * @deprecated Alternatives such as {@link Context#getExternalFilesDir(String)}, - * {@link MediaStore}, or {@link Intent#ACTION_OPEN_DOCUMENT} offer better - * performance. */ - @Deprecated public static File getExternalStorageDirectory() { throwIfUserRequired(); return sCurrentUser.getExternalDirs()[0]; @@ -999,6 +996,9 @@ public class Environment { *

    * {@sample development/samples/ApiDemos/src/com/example/android/apis/content/ExternalStorage.java * public_picture} + *

    + * Note that alternatives such as {@link Context#getExternalFilesDir(String)} or + * {@link MediaStore} offer better performance. * * @param type The type of storage directory to return. Should be one of * {@link #DIRECTORY_MUSIC}, {@link #DIRECTORY_PODCASTS}, @@ -1009,11 +1009,7 @@ public class Environment { * @return Returns the File path for the directory. Note that this directory * may not yet exist, so you must make sure it exists before using * it such as with {@link File#mkdirs File.mkdirs()}. - * @deprecated Alternatives such as {@link Context#getExternalFilesDir(String)}, - * {@link MediaStore}, or {@link Intent#ACTION_OPEN_DOCUMENT} offer better - * performance. */ - @Deprecated public static File getExternalStoragePublicDirectory(String type) { throwIfUserRequired(); return sCurrentUser.buildExternalStoragePublicDirs(type)[0]; diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java index 3aa0bcb6abee..4dae7c7c96d5 100644 --- a/core/java/android/os/PowerManager.java +++ b/core/java/android/os/PowerManager.java @@ -548,6 +548,7 @@ public final class PowerManager { WAKE_REASON_HDMI, WAKE_REASON_DISPLAY_GROUP_ADDED, WAKE_REASON_DISPLAY_GROUP_TURNED_ON, + WAKE_REASON_UNFOLD_DEVICE }) @Retention(RetentionPolicy.SOURCE) public @interface WakeReason{} @@ -646,6 +647,12 @@ public final class PowerManager { */ public static final int WAKE_REASON_DISPLAY_GROUP_TURNED_ON = 11; + /** + * Wake up reason code: Waking the device due to unfolding of a foldable device. + * @hide + */ + public static final int WAKE_REASON_UNFOLD_DEVICE = 12; + /** * Convert the wake reason to a string for debugging purposes. * @hide @@ -664,6 +671,7 @@ public final class PowerManager { case WAKE_REASON_LID: return "WAKE_REASON_LID"; case WAKE_REASON_DISPLAY_GROUP_ADDED: return "WAKE_REASON_DISPLAY_GROUP_ADDED"; case WAKE_REASON_DISPLAY_GROUP_TURNED_ON: return "WAKE_REASON_DISPLAY_GROUP_TURNED_ON"; + case WAKE_REASON_UNFOLD_DEVICE: return "WAKE_REASON_UNFOLD_DEVICE"; default: return Integer.toString(wakeReason); } } diff --git a/core/java/android/os/SharedMemory.java b/core/java/android/os/SharedMemory.java index 136e3de731a9..da478594dc1c 100644 --- a/core/java/android/os/SharedMemory.java +++ b/core/java/android/os/SharedMemory.java @@ -63,7 +63,7 @@ public final class SharedMemory implements Parcelable, Closeable { mMemoryRegistration = new MemoryRegistration(mSize); mCleaner = Cleaner.create(mFileDescriptor, - new Closer(mFileDescriptor, mMemoryRegistration)); + new Closer(mFileDescriptor.getInt$(), mMemoryRegistration)); } /** @@ -256,6 +256,7 @@ public final class SharedMemory implements Parcelable, Closeable { */ @Override public void close() { + mFileDescriptor.setInt$(-1); if (mCleaner != null) { mCleaner.clean(); mCleaner = null; @@ -305,10 +306,10 @@ public final class SharedMemory implements Parcelable, Closeable { * Cleaner that closes the FD */ private static final class Closer implements Runnable { - private FileDescriptor mFd; + private int mFd; private MemoryRegistration mMemoryReference; - private Closer(FileDescriptor fd, MemoryRegistration memoryReference) { + private Closer(int fd, MemoryRegistration memoryReference) { mFd = fd; mMemoryReference = memoryReference; } @@ -316,7 +317,9 @@ public final class SharedMemory implements Parcelable, Closeable { @Override public void run() { try { - Os.close(mFd); + FileDescriptor fd = new FileDescriptor(); + fd.setInt$(mFd); + Os.close(fd); } catch (ErrnoException e) { /* swallow error */ } mMemoryReference.release(); mMemoryReference = null; diff --git a/core/java/android/os/TEST_MAPPING b/core/java/android/os/TEST_MAPPING index 55b1f940c764..07f40828eb56 100644 --- a/core/java/android/os/TEST_MAPPING +++ b/core/java/android/os/TEST_MAPPING @@ -73,6 +73,15 @@ "[^/]*BatteryConsumer[^/]*\\.java" ], "name": "BatteryUsageStatsProtoTests" + }, + { + "file_patterns": ["SharedMemory[^/]*\\.java"], + "name": "CtsOsTestCases", + "options": [ + { + "include-filter": "android.os.cts.SharedMemoryTest" + } + ] } ], "postsubmit": [ diff --git a/core/java/android/permission/PermissionManager.java b/core/java/android/permission/PermissionManager.java index 63bcc9c89ca9..c64aa4db561a 100644 --- a/core/java/android/permission/PermissionManager.java +++ b/core/java/android/permission/PermissionManager.java @@ -159,8 +159,6 @@ public final class PermissionManager { mPermissionManager = IPermissionManager.Stub.asInterface(ServiceManager.getServiceOrThrow( "permissionmgr")); mLegacyPermissionManager = context.getSystemService(LegacyPermissionManager.class); - //TODO ntmyren: there should be a way to only enable the watcher when requested - mUsageHelper = new PermissionUsageHelper(context); } /** @@ -871,6 +869,29 @@ public final class PermissionManager { return mSplitPermissionInfos; } + /** + * Initialize the PermissionUsageHelper, which will register active app op listeners + * + * @hide + */ + public void initializeUsageHelper() { + if (mUsageHelper == null) { + mUsageHelper = new PermissionUsageHelper(mContext); + } + } + + /** + * Teardown the PermissionUsageHelper, removing listeners + * + * @hide + */ + public void tearDownUsageHelper() { + if (mUsageHelper != null) { + mUsageHelper.tearDown(); + mUsageHelper = null; + } + } + /** * @return A list of permission groups currently or recently used by all apps by all users in * the current profile group. @@ -881,7 +902,7 @@ public final class PermissionManager { @NonNull @RequiresPermission(Manifest.permission.GET_APP_OPS_STATS) public List getIndicatorAppOpUsageData() { - return mUsageHelper.getOpUsageData(new AudioManager().isMicrophoneMute()); + return getIndicatorAppOpUsageData(new AudioManager().isMicrophoneMute()); } /** @@ -896,9 +917,7 @@ public final class PermissionManager { @RequiresPermission(Manifest.permission.GET_APP_OPS_STATS) public List getIndicatorAppOpUsageData(boolean micMuted) { // Lazily initialize the usage helper - if (mUsageHelper == null) { - mUsageHelper = new PermissionUsageHelper(mContext); - } + initializeUsageHelper(); return mUsageHelper.getOpUsageData(micMuted); } diff --git a/core/java/android/permission/PermissionUsageHelper.java b/core/java/android/permission/PermissionUsageHelper.java index 19f204b377c8..cf2361a1026a 100644 --- a/core/java/android/permission/PermissionUsageHelper.java +++ b/core/java/android/permission/PermissionUsageHelper.java @@ -176,6 +176,11 @@ public class PermissionUsageHelper implements AppOpsManager.OnOpActiveChangedLis return mUserContexts.get(user); } + public void tearDown() { + mAppOpsManager.stopWatchingActive(this); + mAppOpsManager.stopWatchingStarted(this); + } + @Override public void onOpActiveChanged(@NonNull String op, int uid, @NonNull String packageName, boolean active) { @@ -194,22 +199,24 @@ public class PermissionUsageHelper implements AppOpsManager.OnOpActiveChangedLis // if any link in the chain is finished, remove the chain. Then, find any other chains that // contain this op/package/uid/tag combination, and remove them, as well. // TODO ntmyren: be smarter about this - mAttributionChains.remove(attributionChainId); - int numChains = mAttributionChains.size(); - ArrayList toRemove = new ArrayList<>(); - for (int i = 0; i < numChains; i++) { - int chainId = mAttributionChains.keyAt(i); - ArrayList chain = mAttributionChains.valueAt(i); - int chainSize = chain.size(); - for (int j = 0; j < chainSize; j++) { - AccessChainLink link = chain.get(j); - if (link.packageAndOpEquals(op, packageName, attributionTag, uid)) { - toRemove.add(chainId); - break; + synchronized(mAttributionChains) { + mAttributionChains.remove(attributionChainId); + int numChains = mAttributionChains.size(); + ArrayList toRemove = new ArrayList<>(); + for (int i = 0; i < numChains; i++) { + int chainId = mAttributionChains.keyAt(i); + ArrayList chain = mAttributionChains.valueAt(i); + int chainSize = chain.size(); + for (int j = 0; j < chainSize; j++) { + AccessChainLink link = chain.get(j); + if (link.packageAndOpEquals(op, packageName, attributionTag, uid)) { + toRemove.add(chainId); + break; + } } } + mAttributionChains.removeAll(toRemove); } - mAttributionChains.removeAll(toRemove); } @Override @@ -229,8 +236,10 @@ public class PermissionUsageHelper implements AppOpsManager.OnOpActiveChangedLis // If this is not a successful start, or it is not a chain, or it is untrusted, return return; } - addLinkToChainIfNotPresent(AppOpsManager.opToPublicName(op), packageName, uid, - attributionTag, attributionFlags, attributionChainId); + synchronized(mAttributionChains) { + addLinkToChainIfNotPresent(AppOpsManager.opToPublicName(op), packageName, uid, + attributionTag, attributionFlags, attributionChainId); + } } private void addLinkToChainIfNotPresent(String op, String packageName, int uid, @@ -305,7 +314,7 @@ public class PermissionUsageHelper implements AppOpsManager.OnOpActiveChangedLis String permGroup = usedPermGroups.get(permGroupNum); ArrayMap usagesWithLabels = - getUniqueUsagesWithLabels(rawUsages.get(permGroup)); + getUniqueUsagesWithLabels(permGroup, rawUsages.get(permGroup)); if (permGroup.equals(OPSTR_PHONE_CALL_MICROPHONE)) { isPhone = true; @@ -426,7 +435,8 @@ public class PermissionUsageHelper implements AppOpsManager.OnOpActiveChangedLis return ListFormatter.getInstance().format(labels); } - private ArrayMap getUniqueUsagesWithLabels(List usages) { + private ArrayMap getUniqueUsagesWithLabels(String permGroup, + List usages) { ArrayMap usagesAndLabels = new ArrayMap<>(); if (usages == null || usages.isEmpty()) { @@ -461,7 +471,7 @@ public class PermissionUsageHelper implements AppOpsManager.OnOpActiveChangedLis // If this usage has a proxy, but is not a proxy, it is the end of a chain. // TODO remove once camera converted if (!proxies.containsKey(usageAttr) && usage.proxy != null - && !usage.op.equals(OPSTR_RECORD_AUDIO)) { + && !MICROPHONE.equals(permGroup)) { proxyLabels.put(usage, new ArrayList<>()); proxyPackages.add(usage.getPackageIdHash()); } @@ -533,48 +543,51 @@ public class PermissionUsageHelper implements AppOpsManager.OnOpActiveChangedLis // TODO ntmyren: remove this proxy logic once camera is converted to AttributionSource // For now: don't add mic proxy usages - if (!start.op.equals(OPSTR_RECORD_AUDIO)) { + if (!MICROPHONE.equals(permGroup)) { usagesAndLabels.put(start, proxyLabelList.isEmpty() ? null : formatLabelList(proxyLabelList)); } } - for (int i = 0; i < mAttributionChains.size(); i++) { - List usageList = mAttributionChains.valueAt(i); - int lastVisible = usageList.size() - 1; - // TODO ntmyren: remove this mic code once camera is converted to AttributionSource - // if the list is empty or incomplete, do not show it. - if (usageList.isEmpty() || !usageList.get(lastVisible).isEnd() - || !usageList.get(0).isStart() - || !usageList.get(lastVisible).usage.op.equals(OPSTR_RECORD_AUDIO)) { - continue; - } + synchronized (mAttributionChains) { + for (int i = 0; i < mAttributionChains.size(); i++) { + List usageList = mAttributionChains.valueAt(i); + int lastVisible = usageList.size() - 1; + // TODO ntmyren: remove this mic code once camera is converted to AttributionSource + // if the list is empty or incomplete, do not show it. + if (usageList.isEmpty() || !usageList.get(lastVisible).isEnd() + || !usageList.get(0).isStart() + || !permGroup.equals(getGroupForOp(usageList.get(0).usage.op)) + || !MICROPHONE.equals(permGroup)) { + continue; + } - //TODO ntmyren: remove once camera etc. etc. - for (AccessChainLink link: usageList) { - proxyPackages.add(link.usage.getPackageIdHash()); - } + //TODO ntmyren: remove once camera etc. etc. + for (AccessChainLink link : usageList) { + proxyPackages.add(link.usage.getPackageIdHash()); + } - AccessChainLink start = usageList.get(0); - AccessChainLink lastVisibleLink = usageList.get(lastVisible); - while (lastVisible > 0 && !shouldShowPackage(lastVisibleLink.usage.packageName)) { - lastVisible--; - lastVisibleLink = usageList.get(lastVisible); - } - String proxyLabel = null; - if (!lastVisibleLink.usage.packageName.equals(start.usage.packageName)) { - try { - PackageManager userPkgManager = - getUserContext(lastVisibleLink.usage.getUser()).getPackageManager(); - ApplicationInfo appInfo = userPkgManager.getApplicationInfo( - lastVisibleLink.usage.packageName, 0); - proxyLabel = appInfo.loadLabel(userPkgManager).toString(); - } catch (PackageManager.NameNotFoundException e) { - // do nothing + AccessChainLink start = usageList.get(0); + AccessChainLink lastVisibleLink = usageList.get(lastVisible); + while (lastVisible > 0 && !shouldShowPackage(lastVisibleLink.usage.packageName)) { + lastVisible--; + lastVisibleLink = usageList.get(lastVisible); } + String proxyLabel = null; + if (!lastVisibleLink.usage.packageName.equals(start.usage.packageName)) { + try { + PackageManager userPkgManager = + getUserContext(lastVisibleLink.usage.getUser()).getPackageManager(); + ApplicationInfo appInfo = userPkgManager.getApplicationInfo( + lastVisibleLink.usage.packageName, 0); + proxyLabel = appInfo.loadLabel(userPkgManager).toString(); + } catch (PackageManager.NameNotFoundException e) { + // do nothing + } + } + usagesAndLabels.put(start.usage, proxyLabel); } - usagesAndLabels.put(start.usage, proxyLabel); } for (int packageHash : mostRecentUsages.keySet()) { diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java index 217e17ddd7b4..e58419fb688d 100644 --- a/core/java/android/provider/DeviceConfig.java +++ b/core/java/android/provider/DeviceConfig.java @@ -604,6 +604,14 @@ public final class DeviceConfig { @TestApi public static final String NAMESPACE_CONSTRAIN_DISPLAY_APIS = "constrain_display_apis"; + /** + * Namespace for App Compat Overrides related features. + * + * @hide + */ + @TestApi + public static final String NAMESPACE_APP_COMPAT_OVERRIDES = "app_compat_overrides"; + private static final Object sLock = new Object(); @GuardedBy("sLock") private static ArrayMap> sListeners = diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index c16e1115ca94..042445b5011f 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -28,6 +28,7 @@ import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.annotation.TestApi; import android.annotation.UserIdInt; +import android.app.Activity; import android.app.ActivityThread; import android.app.AppOpsManager; import android.app.Application; @@ -377,6 +378,21 @@ public final class Settings { public static final String ACTION_REDUCE_BRIGHT_COLORS_SETTINGS = "android.settings.REDUCE_BRIGHT_COLORS_SETTINGS"; + /** + * Activity Action: Show settings to allow configuration of Color inversion. + *

    + * In some cases, a matching Activity may not exist, so ensure you + * safeguard against this. + *

    + * Input: Nothing. + *

    + * Output: Nothing. + * @hide + */ + @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) + public static final String ACTION_COLOR_INVERSION_SETTINGS = + "android.settings.COLOR_INVERSION_SETTINGS"; + /** * Activity Action: Show settings to control access to usage information. *

    @@ -936,6 +952,22 @@ public final class Settings { @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) public static final String ACTION_LOCKSCREEN_SETTINGS = "android.settings.LOCK_SCREEN_SETTINGS"; + /** + * Activity Action: Show settings to allow pairing bluetooth devices. + *

    + * In some cases, a matching Activity may not exist, so ensure you + * safeguard against this. + *

    + * Input: Nothing. + *

    + * Output: Nothing. + * + * @hide + */ + @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) + public static final String ACTION_BLUETOOTH_PAIRING_SETTINGS = + "android.settings.BLUETOOTH_PAIRING_SETTINGS"; + /** * Activity Action: Show settings to configure input methods, in particular * allowing the user to enable input methods. @@ -6342,6 +6374,27 @@ public final class Settings { @Readable public static final String ALLOW_MOCK_LOCATION = "mock_location"; + /** + * This is used by Bluetooth Manager to store adapter name + * @hide + */ + @Readable(maxTargetSdk = Build.VERSION_CODES.S) + public static final String BLUETOOTH_NAME = "bluetooth_name"; + + /** + * This is used by Bluetooth Manager to store adapter address + * @hide + */ + @Readable(maxTargetSdk = Build.VERSION_CODES.S) + public static final String BLUETOOTH_ADDRESS = "bluetooth_address"; + + /** + * This is used by Bluetooth Manager to store whether adapter address is valid + * @hide + */ + @Readable(maxTargetSdk = Build.VERSION_CODES.S) + public static final String BLUETOOTH_ADDR_VALID = "bluetooth_addr_valid"; + /** * Setting to indicate that on device captions are enabled. * @@ -8989,6 +9042,15 @@ public final class Settings { @Readable public static final String UNSAFE_VOLUME_MUSIC_ACTIVE_MS = "unsafe_volume_music_active_ms"; + /** + * Indicates whether the spatial audio feature was enabled for this user. + * + * Type : int (0 disabled, 1 enabled) + * + * @hide + */ + public static final String SPATIAL_AUDIO_ENABLED = "spatial_audio_enabled"; + /** * Indicates whether notification display on the lock screen is enabled. *

    @@ -9604,6 +9666,14 @@ public final class Settings { */ public static final String LOCKSCREEN_SHOW_WALLET = "lockscreen_show_wallet"; + /** + * Whether to use the lockscreen double-line clock + * + * @hide + */ + public static final String LOCKSCREEN_USE_DOUBLE_LINE_CLOCK = + "lockscreen_use_double_line_clock"; + /** * Specifies whether the web action API is enabled. * @@ -9990,15 +10060,18 @@ public final class Settings { /** * Controls the accessibility button mode. System will force-set the value to {@link - * #ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU} if {@link #NAVIGATION_MODE} is fully - * gestural. + * #ACCESSIBILITY_BUTTON_MODE_GESTURE} if {@link #NAVIGATION_MODE} is button; force-set the + * value to {@link ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR} if {@link #NAVIGATION_MODE} is + * gestural; otherwise, remain the option. *

      *
    • 0 = button in navigation bar
    • *
    • 1 = button floating on the display
    • + *
    • 2 = button using gesture to trigger
    • *
    * * @see #ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR * @see #ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU + * @see #ACCESSIBILITY_BUTTON_MODE_GESTURE * @hide */ public static final String ACCESSIBILITY_BUTTON_MODE = @@ -10020,6 +10093,14 @@ public final class Settings { */ public static final int ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU = 0x1; + /** + * Accessibility button mode value that specifying the accessibility service or feature to + * be toggled via the gesture. + * + * @hide + */ + public static final int ACCESSIBILITY_BUTTON_MODE_GESTURE = 0x2; + /** * The size of the accessibility floating menu. *
      @@ -10134,6 +10215,61 @@ public final class Settings { @Readable public static final String GAME_DASHBOARD_ALWAYS_ON = "game_dashboard_always_on"; + + /** + * For this device state, no specific auto-rotation lock setting should be applied. + * If the user toggles the auto-rotate lock in this state, the setting will apply to the + * previously valid device state. + * @hide + */ + public static final int DEVICE_STATE_ROTATION_LOCK_IGNORED = 0; + /** + * For this device state, the setting for auto-rotation is locked. + * @hide + */ + public static final int DEVICE_STATE_ROTATION_LOCK_LOCKED = 1; + /** + * For this device state, the setting for auto-rotation is unlocked. + * @hide + */ + public static final int DEVICE_STATE_ROTATION_LOCK_UNLOCKED = 2; + + /** + * The different settings that can be used as values with + * {@link #DEVICE_STATE_ROTATION_LOCK}. + * @hide + */ + @IntDef(prefix = {"DEVICE_STATE_ROTATION_LOCK_"}, value = { + DEVICE_STATE_ROTATION_LOCK_IGNORED, + DEVICE_STATE_ROTATION_LOCK_LOCKED, + DEVICE_STATE_ROTATION_LOCK_UNLOCKED, + }) + @Retention(RetentionPolicy.SOURCE) + @interface DeviceStateRotationLockSetting { + } + + /** + * Rotation lock setting keyed on device state. + * + * This holds a serialized map using int keys that represent Device States and value of + * {@link DeviceStateRotationLockSetting} representing the rotation lock setting for that + * device state. + * + * Serialized as key0:value0:key1:value1:...:keyN:valueN. + * + * Example: "0:1:1:2:2:1" + * This example represents a map of: + *
        + *
      • 0 -> DEVICE_STATE_ROTATION_LOCK_LOCKED
      • + *
      • 1 -> DEVICE_STATE_ROTATION_LOCK_UNLOCKED
      • + *
      • 2 -> DEVICE_STATE_ROTATION_LOCK_IGNORED
      • + *
      + * + * @hide + */ + public static final String DEVICE_STATE_ROTATION_LOCK = + "device_state_rotation_lock"; + /** * These entries are considered common between the personal and the managed profile, * since the managed profile doesn't get to change them. @@ -16920,6 +17056,44 @@ public final class Settings { public static final String ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION = "android.settings.MANAGE_APP_ALL_FILES_ACCESS_PERMISSION"; + /** + * Activity Action: For system or preinstalled apps to show their {@link Activity} embedded + * in Settings app on large screen devices. + *

      + * Input: {@link #EXTRA_SETTINGS_EMBEDDED_DEEP_LINK_INTENT_URI} must be included to + * specify the intent for the activity which will be embedded in Settings app. + * It's an intent URI string from {@code intent.toUri(Intent.URI_INTENT_SCHEME)}. + * + * Input: {@link #EXTRA_SETTINGS_EMBEDDED_DEEP_LINK_HIGHLIGHT_MENU_KEY} must be included to + * specify a key that indicates the menu item which will be highlighted on settings home menu. + *

      + * Output: Nothing. + */ + @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) + public static final String ACTION_SETTINGS_EMBED_DEEP_LINK_ACTIVITY = + "android.settings.SETTINGS_EMBED_DEEP_LINK_ACTIVITY"; + + /** + * Activity Extra: Specify the intent for the {@link Activity} which will be embedded in + * Settings app. It's an intent URI string from + * {@code intent.toUri(Intent.URI_INTENT_SCHEME)}. + *

      + * This must be passed as an extra field to + * {@link #ACTION_SETTINGS_EMBED_DEEP_LINK_ACTIVITY}. + */ + public static final String EXTRA_SETTINGS_EMBEDDED_DEEP_LINK_INTENT_URI = + "android.provider.extra.SETTINGS_EMBEDDED_DEEP_LINK_INTENT_URI"; + + /** + * Activity Extra: Specify a key that indicates the menu item which should be highlighted on + * settings home menu. + *

      + * This must be passed as an extra field to + * {@link #ACTION_SETTINGS_EMBED_DEEP_LINK_ACTIVITY}. + */ + public static final String EXTRA_SETTINGS_EMBEDDED_DEEP_LINK_HIGHLIGHT_MENU_KEY = + "android.provider.extra.SETTINGS_EMBEDDED_DEEP_LINK_HIGHLIGHT_MENU_KEY"; + /** * Performs a strict and comprehensive check of whether a calling package is allowed to * write/modify system settings, as the condition differs for pre-M, M+, and diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java index bdda849a0b00..3baecf0acc7f 100644 --- a/core/java/android/provider/Telephony.java +++ b/core/java/android/provider/Telephony.java @@ -5416,5 +5416,14 @@ public final class Telephony { */ public static final String COLUMN_D2D_STATUS_SHARING_SELECTED_CONTACTS = "d2d_sharing_contacts"; + + /** + * TelephonyProvider column name for NR Advanced calling + * Determines if the user has enabled VoNR settings for this subscription. + * + * @hide + */ + public static final String COLUMN_NR_ADVANCED_CALLING_ENABLED = + "nr_advanced_calling_enabled"; } } diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java index 71f90fd28e3f..c94595468aec 100644 --- a/core/java/android/service/notification/NotificationListenerService.java +++ b/core/java/android/service/notification/NotificationListenerService.java @@ -83,11 +83,11 @@ import java.util.Objects; * </intent-filter> * <meta-data * android:name="android.service.notification.default_filter_types" - * android:value="conversations,alerting"> + * android:value="conversations|alerting"> * </meta-data> * <meta-data * android:name="android.service.notification.disabled_filter_types" - * android:value="ongoing,silent"> + * android:value="ongoing|silent"> * </meta-data> * </service> * @@ -112,8 +112,9 @@ public abstract class NotificationListenerService extends Service { private final String TAG = getClass().getSimpleName(); /** - * The name of the {@code meta-data} tag containing a comma separated list of default - * integer notification types that should be provided to this listener. See + * The name of the {@code meta-data} tag containing a pipe separated list of default + * integer notification types or "ongoing", "conversations", "alerting", or "silent" + * that should be provided to this listener. See * {@link #FLAG_FILTER_TYPE_ONGOING}, * {@link #FLAG_FILTER_TYPE_CONVERSATIONS}, {@link #FLAG_FILTER_TYPE_ALERTING), * and {@link #FLAG_FILTER_TYPE_SILENT}. @@ -1698,7 +1699,7 @@ public abstract class NotificationListenerService extends Service { private ArrayList mSmartActions; private ArrayList mSmartReplies; private boolean mCanBubble; - private boolean mVisuallyInterruptive; + private boolean mIsTextChanged; private boolean mIsConversation; private ShortcutInfo mShortcutInfo; private @RankingAdjustment int mRankingAdjustment; @@ -1735,7 +1736,7 @@ public abstract class NotificationListenerService extends Service { out.writeTypedList(mSmartActions, flags); out.writeCharSequenceList(mSmartReplies); out.writeBoolean(mCanBubble); - out.writeBoolean(mVisuallyInterruptive); + out.writeBoolean(mIsTextChanged); out.writeBoolean(mIsConversation); out.writeParcelable(mShortcutInfo, flags); out.writeInt(mRankingAdjustment); @@ -1773,7 +1774,7 @@ public abstract class NotificationListenerService extends Service { mSmartActions = in.createTypedArrayList(Notification.Action.CREATOR); mSmartReplies = in.readCharSequenceList(); mCanBubble = in.readBoolean(); - mVisuallyInterruptive = in.readBoolean(); + mIsTextChanged = in.readBoolean(); mIsConversation = in.readBoolean(); mShortcutInfo = in.readParcelable(cl); mRankingAdjustment = in.readInt(); @@ -1976,8 +1977,8 @@ public abstract class NotificationListenerService extends Service { } /** @hide */ - public boolean visuallyInterruptive() { - return mVisuallyInterruptive; + public boolean isTextChanged() { + return mIsTextChanged; } /** @hide */ @@ -2032,7 +2033,7 @@ public abstract class NotificationListenerService extends Service { int userSentiment, boolean hidden, long lastAudiblyAlertedMs, boolean noisy, ArrayList smartActions, ArrayList smartReplies, boolean canBubble, - boolean visuallyInterruptive, boolean isConversation, ShortcutInfo shortcutInfo, + boolean isTextChanged, boolean isConversation, ShortcutInfo shortcutInfo, int rankingAdjustment, boolean isBubble) { mKey = key; mRank = rank; @@ -2054,7 +2055,7 @@ public abstract class NotificationListenerService extends Service { mSmartActions = smartActions; mSmartReplies = smartReplies; mCanBubble = canBubble; - mVisuallyInterruptive = visuallyInterruptive; + mIsTextChanged = isTextChanged; mIsConversation = isConversation; mShortcutInfo = shortcutInfo; mRankingAdjustment = rankingAdjustment; @@ -2095,7 +2096,7 @@ public abstract class NotificationListenerService extends Service { other.mSmartActions, other.mSmartReplies, other.mCanBubble, - other.mVisuallyInterruptive, + other.mIsTextChanged, other.mIsConversation, other.mShortcutInfo, other.mRankingAdjustment, @@ -2152,7 +2153,7 @@ public abstract class NotificationListenerService extends Service { == (other.mSmartActions == null ? 0 : other.mSmartActions.size())) && Objects.equals(mSmartReplies, other.mSmartReplies) && Objects.equals(mCanBubble, other.mCanBubble) - && Objects.equals(mVisuallyInterruptive, other.mVisuallyInterruptive) + && Objects.equals(mIsTextChanged, other.mIsTextChanged) && Objects.equals(mIsConversation, other.mIsConversation) // Shortcutinfo doesn't have equals either; use id && Objects.equals((mShortcutInfo == null ? 0 : mShortcutInfo.getId()), diff --git a/core/java/android/service/voice/IVoiceInteractionSession.aidl b/core/java/android/service/voice/IVoiceInteractionSession.aidl index c142a53e047e..59f1e8eed89c 100644 --- a/core/java/android/service/voice/IVoiceInteractionSession.aidl +++ b/core/java/android/service/voice/IVoiceInteractionSession.aidl @@ -22,6 +22,7 @@ import android.content.Intent; import android.graphics.Bitmap; import android.os.Bundle; import android.os.IBinder; +import android.service.voice.VisibleActivityInfo; import com.android.internal.app.IVoiceInteractionSessionShowCallback; @@ -39,4 +40,5 @@ oneway interface IVoiceInteractionSession { void closeSystemDialogs(); void onLockscreenShown(); void destroy(); + void updateVisibleActivityInfo(in VisibleActivityInfo visibleActivityInfo, int type); } diff --git a/core/java/android/service/voice/VisibleActivityInfo.aidl b/core/java/android/service/voice/VisibleActivityInfo.aidl new file mode 100644 index 000000000000..34bd57c15456 --- /dev/null +++ b/core/java/android/service/voice/VisibleActivityInfo.aidl @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.service.voice; + +parcelable VisibleActivityInfo; diff --git a/core/java/android/service/voice/VisibleActivityInfo.java b/core/java/android/service/voice/VisibleActivityInfo.java new file mode 100644 index 000000000000..139544c76a50 --- /dev/null +++ b/core/java/android/service/voice/VisibleActivityInfo.java @@ -0,0 +1,205 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.service.voice; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.TestApi; +import android.os.CancellationSignal; +import android.os.IBinder; +import android.os.Parcel; +import android.os.Parcelable; + +import com.android.internal.util.DataClass; + +import java.util.Objects; +import java.util.concurrent.Executor; +import java.util.function.Consumer; + +/** + * The class is used to represent a visible activity information. The system provides this to + * services that need to know {@link android.service.voice.VoiceInteractionSession.ActivityId}. + */ +@DataClass( + genConstructor = false, + genEqualsHashCode = true, + genHiddenConstDefs = false, + genGetters = false, + genToString = true +) +public final class VisibleActivityInfo implements Parcelable { + + /** + * Indicates that it is a new visible activity. + * + * @hide + */ + public static final int TYPE_ACTIVITY_ADDED = 1; + + /** + * Indicates that it has become a invisible activity. + * + * @hide + */ + public static final int TYPE_ACTIVITY_REMOVED = 2; + + /** + * The identifier of the task this activity is in. + */ + private final int mTaskId; + + /** + * Token for targeting this activity for assist purposes. + */ + @NonNull + private final IBinder mAssistToken; + + /** @hide */ + @TestApi + public VisibleActivityInfo( + int taskId, + @NonNull IBinder assistToken) { + Objects.requireNonNull(assistToken); + mTaskId = taskId; + mAssistToken = assistToken; + } + + /** + * Returns the {@link android.service.voice.VoiceInteractionSession.ActivityId} of this + * visible activity which can be used to interact with an activity, for example through + * {@link VoiceInteractionSession#requestDirectActions(VoiceInteractionSession.ActivityId, + * CancellationSignal, Executor, Consumer)}. + */ + public @NonNull VoiceInteractionSession.ActivityId getActivityId() { + return new VoiceInteractionSession.ActivityId(mTaskId, mAssistToken); + } + + + + // Code below generated by codegen v1.0.23. + // + // DO NOT MODIFY! + // CHECKSTYLE:OFF Generated code + // + // To regenerate run: + // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/service/voice/VisibleActivityInfo.java + // + // To exclude the generated code from IntelliJ auto-formatting enable (one-time): + // Settings > Editor > Code Style > Formatter Control + //@formatter:off + + + @Override + @DataClass.Generated.Member + public String toString() { + // You can override field toString logic by defining methods like: + // String fieldNameToString() { ... } + + return "VisibleActivityInfo { " + + "taskId = " + mTaskId + ", " + + "assistToken = " + mAssistToken + + " }"; + } + + @Override + @DataClass.Generated.Member + public boolean equals(@Nullable Object o) { + // You can override field equality logic by defining either of the methods like: + // boolean fieldNameEquals(VisibleActivityInfo other) { ... } + // boolean fieldNameEquals(FieldType otherValue) { ... } + + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + @SuppressWarnings("unchecked") + VisibleActivityInfo that = (VisibleActivityInfo) o; + //noinspection PointlessBooleanExpression + return true + && mTaskId == that.mTaskId + && Objects.equals(mAssistToken, that.mAssistToken); + } + + @Override + @DataClass.Generated.Member + public int hashCode() { + // You can override field hashCode logic by defining methods like: + // int fieldNameHashCode() { ... } + + int _hash = 1; + _hash = 31 * _hash + mTaskId; + _hash = 31 * _hash + Objects.hashCode(mAssistToken); + return _hash; + } + + @Override + @DataClass.Generated.Member + public void writeToParcel(@NonNull Parcel dest, int flags) { + // You can override field parcelling by defining methods like: + // void parcelFieldName(Parcel dest, int flags) { ... } + + dest.writeInt(mTaskId); + dest.writeStrongBinder(mAssistToken); + } + + @Override + @DataClass.Generated.Member + public int describeContents() { return 0; } + + /** @hide */ + @SuppressWarnings({"unchecked", "RedundantCast"}) + @DataClass.Generated.Member + /* package-private */ VisibleActivityInfo(@NonNull Parcel in) { + // You can override field unparcelling by defining methods like: + // static FieldType unparcelFieldName(Parcel in) { ... } + + int taskId = in.readInt(); + IBinder assistToken = (IBinder) in.readStrongBinder(); + + this.mTaskId = taskId; + this.mAssistToken = assistToken; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mAssistToken); + + // onConstructed(); // You can define this method to get a callback + } + + @DataClass.Generated.Member + public static final @NonNull Parcelable.Creator CREATOR + = new Parcelable.Creator() { + @Override + public VisibleActivityInfo[] newArray(int size) { + return new VisibleActivityInfo[size]; + } + + @Override + public VisibleActivityInfo createFromParcel(@NonNull Parcel in) { + return new VisibleActivityInfo(in); + } + }; + + @DataClass.Generated( + time = 1632383555284L, + codegenVersion = "1.0.23", + sourceFile = "frameworks/base/core/java/android/service/voice/VisibleActivityInfo.java", + inputSignatures = "public static final int TYPE_ACTIVITY_ADDED\npublic static final int TYPE_ACTIVITY_REMOVED\nprivate final int mTaskId\nprivate final @android.annotation.NonNull android.os.IBinder mAssistToken\npublic @android.annotation.NonNull android.service.voice.VoiceInteractionSession.ActivityId getActivityId()\nclass VisibleActivityInfo extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genConstructor=false, genEqualsHashCode=true, genHiddenConstDefs=false, genGetters=false, genToString=true)") + @Deprecated + private void __metadata() {} + + + //@formatter:on + // End of generated code + +} diff --git a/core/java/android/service/voice/VoiceInteractionManagerInternal.java b/core/java/android/service/voice/VoiceInteractionManagerInternal.java index c048286545c3..c80640910bc2 100644 --- a/core/java/android/service/voice/VoiceInteractionManagerInternal.java +++ b/core/java/android/service/voice/VoiceInteractionManagerInternal.java @@ -22,7 +22,6 @@ import android.os.IBinder; import com.android.internal.annotations.Immutable; - /** * @hide * Private interface to the VoiceInteractionManagerService for use by ActivityManagerService. diff --git a/core/java/android/service/voice/VoiceInteractionSession.java b/core/java/android/service/voice/VoiceInteractionSession.java index 725e20f2a74d..ee32ce43821c 100644 --- a/core/java/android/service/voice/VoiceInteractionSession.java +++ b/core/java/android/service/voice/VoiceInteractionSession.java @@ -74,9 +74,11 @@ import com.android.internal.util.function.pooled.PooledLambda; import java.io.FileDescriptor; import java.io.PrintWriter; import java.lang.ref.WeakReference; +import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.concurrent.Executor; import java.util.function.Consumer; @@ -177,6 +179,10 @@ public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCall ICancellationSignal mKillCallback; + private final Map mVisibleActivityCallbacks = + new ArrayMap<>(); + private final List mVisibleActivityInfos = new ArrayList<>(); + final IVoiceInteractor mInteractor = new IVoiceInteractor.Stub() { @Override public IVoiceInteractorRequest startConfirmation(String callingPackage, @@ -352,6 +358,13 @@ public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCall public void destroy() { mHandlerCaller.sendMessage(mHandlerCaller.obtainMessage(MSG_DESTROY)); } + + @Override + public void updateVisibleActivityInfo(VisibleActivityInfo visibleActivityInfo, int type) { + mHandlerCaller.sendMessage( + mHandlerCaller.obtainMessageIO(MSG_UPDATE_VISIBLE_ACTIVITY_INFO, type, + visibleActivityInfo)); + } }; /** @@ -843,6 +856,9 @@ public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCall static final int MSG_SHOW = 106; static final int MSG_HIDE = 107; static final int MSG_ON_LOCKSCREEN_SHOWN = 108; + static final int MSG_UPDATE_VISIBLE_ACTIVITY_INFO = 109; + static final int MSG_REGISTER_VISIBLE_ACTIVITY_CALLBACK = 110; + static final int MSG_UNREGISTER_VISIBLE_ACTIVITY_CALLBACK = 111; class MyCallbacks implements HandlerCaller.Callback, SoftInputWindow.Callback { @Override @@ -928,6 +944,27 @@ public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCall if (DEBUG) Log.d(TAG, "onLockscreenShown"); onLockscreenShown(); break; + case MSG_UPDATE_VISIBLE_ACTIVITY_INFO: + if (DEBUG) { + Log.d(TAG, "doUpdateVisibleActivityInfo: visibleActivityInfo=" + msg.obj + + " type=" + msg.arg1); + } + doUpdateVisibleActivityInfo((VisibleActivityInfo) msg.obj, msg.arg1); + break; + case MSG_REGISTER_VISIBLE_ACTIVITY_CALLBACK: + if (DEBUG) { + Log.d(TAG, "doRegisterVisibleActivityCallback"); + } + args = (SomeArgs) msg.obj; + doRegisterVisibleActivityCallback((Executor) args.arg1, + (VisibleActivityCallback) args.arg2); + break; + case MSG_UNREGISTER_VISIBLE_ACTIVITY_CALLBACK: + if (DEBUG) { + Log.d(TAG, "doUnregisterVisibleActivityCallback"); + } + doUnregisterVisibleActivityCallback((VisibleActivityCallback) msg.obj); + break; } if (args != null) { args.recycle(); @@ -1122,6 +1159,86 @@ public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCall } } + private void doUpdateVisibleActivityInfo(VisibleActivityInfo visibleActivityInfo, int type) { + + if (mVisibleActivityCallbacks.isEmpty()) { + return; + } + + switch (type) { + case VisibleActivityInfo.TYPE_ACTIVITY_ADDED: + informVisibleActivityChanged(visibleActivityInfo, type); + mVisibleActivityInfos.add(visibleActivityInfo); + break; + case VisibleActivityInfo.TYPE_ACTIVITY_REMOVED: + informVisibleActivityChanged(visibleActivityInfo, type); + mVisibleActivityInfos.remove(visibleActivityInfo); + break; + } + } + + private void doRegisterVisibleActivityCallback(@NonNull @CallbackExecutor Executor executor, + @NonNull VisibleActivityCallback callback) { + if (mVisibleActivityCallbacks.containsKey(callback)) { + if (DEBUG) { + Log.d(TAG, "doRegisterVisibleActivityCallback: callback has registered"); + } + return; + } + + int preCallbackCount = mVisibleActivityCallbacks.size(); + mVisibleActivityCallbacks.put(callback, executor); + + if (preCallbackCount == 0) { + try { + mSystemService.startListeningVisibleActivityChanged(mToken); + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } + } else { + for (int i = 0; i < mVisibleActivityInfos.size(); i++) { + final VisibleActivityInfo visibleActivityInfo = mVisibleActivityInfos.get(i); + executor.execute(() -> callback.onVisible(visibleActivityInfo)); + } + } + } + + private void doUnregisterVisibleActivityCallback(@NonNull VisibleActivityCallback callback) { + mVisibleActivityCallbacks.remove(callback); + + if (mVisibleActivityCallbacks.size() == 0) { + mVisibleActivityInfos.clear(); + try { + mSystemService.stopListeningVisibleActivityChanged(mToken); + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } + } + } + + private void informVisibleActivityChanged(VisibleActivityInfo visibleActivityInfo, int type) { + for (Map.Entry e : + mVisibleActivityCallbacks.entrySet()) { + final Executor executor = e.getValue(); + final VisibleActivityCallback visibleActivityCallback = e.getKey(); + + switch (type) { + case VisibleActivityInfo.TYPE_ACTIVITY_ADDED: + Binder.withCleanCallingIdentity(() -> { + executor.execute( + () -> visibleActivityCallback.onVisible(visibleActivityInfo)); + }); + break; + case VisibleActivityInfo.TYPE_ACTIVITY_REMOVED: + Binder.withCleanCallingIdentity(() -> { + executor.execute(() -> visibleActivityCallback.onInvisible( + visibleActivityInfo.getActivityId())); + }); + break; + } + } + } + void ensureWindowCreated() { if (mInitialized) { return; @@ -1633,8 +1750,9 @@ public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCall /** * Called when there has been a failure transferring the {@link AssistStructure} to * the assistant. This may happen, for example, if the data is too large and results - * in an out of memory exception, or the client has provided corrupt data. This will - * be called immediately before {@link #onHandleAssist} and the AssistStructure supplied + * in an out of memory exception, the data has been cleared during transferring due to + * the new incoming assist data, or the client has provided corrupt data. This will be + * called immediately before {@link #onHandleAssist} and the AssistStructure supplied * there afterwards will be null. * * @param failure The failure exception that was thrown when building the @@ -1672,7 +1790,8 @@ public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCall * Called to receive data from the application that the user was currently viewing when * an assist session is started. If the original show request did not specify * {@link #SHOW_WITH_ASSIST}, {@link AssistState} parameter will only provide - * {@link ActivityId}. + * {@link ActivityId}. If there was a failure to write the assist data to + * {@link AssistStructure}, the {@link AssistState#getAssistStructure()} will return null. * *

      This method is called for all activities along with an index and count that indicates * which activity the data is for. {@code index} will be between 0 and {@code count}-1 and @@ -1925,6 +2044,49 @@ public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCall public void onCancelRequest(Request request) { } + /** + * Registers a callback that will be notified when visible activities have been changed. + * + * Note: The {@link VisibleActivityCallback#onVisible(VisibleActivityInfo)} will be called + * immediately with current visible activities when the callback is registered for the first + * time. If the callback is already registered, this method does nothing. + * + * @param executor The executor which will be used to invoke the callback. + * @param callback The callback to receive the response. + * + * @throws IllegalStateException if calling this method before onCreate(). + */ + public final void registerVisibleActivityCallback(@NonNull @CallbackExecutor Executor executor, + @NonNull VisibleActivityCallback callback) { + if (DEBUG) { + Log.d(TAG, "registerVisibleActivityCallback"); + } + if (mToken == null) { + throw new IllegalStateException("Can't call before onCreate()"); + } + Objects.requireNonNull(executor); + Objects.requireNonNull(callback); + + mHandlerCaller.sendMessage( + mHandlerCaller.obtainMessageOO(MSG_REGISTER_VISIBLE_ACTIVITY_CALLBACK, executor, + callback)); + } + + /** + * Unregisters the callback. + * + * @param callback The callback to receive the response. + */ + public final void unregisterVisibleActivityCallback(@NonNull VisibleActivityCallback callback) { + if (DEBUG) { + Log.d(TAG, "unregisterVisibleActivityCallback"); + } + Objects.requireNonNull(callback); + + mHandlerCaller.sendMessage( + mHandlerCaller.obtainMessageO(MSG_UNREGISTER_VISIBLE_ACTIVITY_CALLBACK, callback)); + } + /** * Print the Service's state into the given stream. This gets invoked by * {@link VoiceInteractionSessionService} when its Service @@ -1974,6 +2136,17 @@ public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCall } } + /** + * Callback interface for receiving visible activity changes used for assistant usage. + */ + public interface VisibleActivityCallback { + /** Callback to inform that an activity has become visible. */ + default void onVisible(@NonNull VisibleActivityInfo activityInfo) {} + + /** Callback to inform that a visible activity has gone. */ + default void onInvisible(@NonNull ActivityId activityId) {} + } + /** * Represents assist state captured when this session was started. * It contains the various assist data objects and a reference to @@ -2043,7 +2216,8 @@ public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCall * @return If available, the structure definition of all windows currently * displayed by the app. May be null if assist data has been disabled by the user * or device policy; will be null if the original show request did not specify - * {@link #SHOW_WITH_ASSIST}; will be an empty stub if the application has disabled assist + * {@link #SHOW_WITH_ASSIST} or the assist data has been corrupt when writing the data to + * {@link AssistStructure}; will be an empty stub if the application has disabled assist * by marking its window as secure. */ public @Nullable AssistStructure getAssistStructure() { diff --git a/core/java/android/service/wallpaper/EngineWindowPage.java b/core/java/android/service/wallpaper/EngineWindowPage.java index 5ed0ad6f2aeb..006e3cdf03f8 100644 --- a/core/java/android/service/wallpaper/EngineWindowPage.java +++ b/core/java/android/service/wallpaper/EngineWindowPage.java @@ -24,7 +24,6 @@ import android.util.ArraySet; import java.util.Map; import java.util.Set; -import java.util.function.Consumer; /** * This class represents a page of a launcher page used by the wallpaper @@ -84,11 +83,6 @@ public class EngineWindowPage { return mCallbackAreas; } - /** run operations on this page */ - public synchronized void execSync(Consumer run) { - run.accept(this); - } - /** nullify the area color */ public void removeColor(RectF colorArea) { mRectFColors.remove(colorArea); diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java index 4d49454350d7..8a2b15de6757 100644 --- a/core/java/android/service/wallpaper/WallpaperService.java +++ b/core/java/android/service/wallpaper/WallpaperService.java @@ -16,6 +16,8 @@ package android.service.wallpaper; +import static android.app.WallpaperManager.COMMAND_FREEZE; +import static android.app.WallpaperManager.COMMAND_UNFREEZE; import static android.graphics.Matrix.MSCALE_X; import static android.graphics.Matrix.MSCALE_Y; import static android.graphics.Matrix.MSKEW_X; @@ -42,12 +44,14 @@ import android.content.res.TypedArray; import android.graphics.BLASTBufferQueue; import android.graphics.Bitmap; import android.graphics.Canvas; +import android.graphics.GraphicBuffer; import android.graphics.Matrix; import android.graphics.PixelFormat; import android.graphics.Point; import android.graphics.Rect; import android.graphics.RectF; import android.graphics.drawable.Drawable; +import android.hardware.HardwareBuffer; import android.hardware.display.DisplayManager; import android.hardware.display.DisplayManager.DisplayListener; import android.os.Build; @@ -56,6 +60,7 @@ import android.os.Handler; import android.os.IBinder; import android.os.Looper; import android.os.Message; +import android.os.Process; import android.os.RemoteException; import android.os.SystemClock; import android.os.SystemProperties; @@ -73,6 +78,7 @@ import android.view.InputEvent; import android.view.InputEventReceiver; import android.view.InsetsSourceControl; import android.view.InsetsState; +import android.view.InsetsVisibilities; import android.view.MotionEvent; import android.view.PixelCopy; import android.view.Surface; @@ -190,7 +196,7 @@ public abstract class WallpaperService extends Service { EngineWindowPage[] mWindowPages = new EngineWindowPage[1]; Bitmap mLastScreenshot; int mLastWindowPage = -1; - float mLastPageOffset = 0; + private boolean mResetWindowPages; // Copies from mIWallpaperEngine. HandlerCaller mCaller; @@ -201,6 +207,12 @@ public abstract class WallpaperService extends Service { boolean mVisible; boolean mReportedVisible; boolean mDestroyed; + // Set to true after receiving WallpaperManager#COMMAND_FREEZE. It's reset back to false + // after receiving WallpaperManager#COMMAND_UNFREEZE. COMMAND_FREEZE is fully applied once + // mScreenshotSurfaceControl isn't null. When this happens, then Engine is notified through + // doVisibilityChanged that main wallpaper surface is no longer visible and the wallpaper + // host receives onVisibilityChanged(false) callback. + private boolean mFrozenRequested = false; // Current window state. boolean mCreated; @@ -226,10 +238,9 @@ public abstract class WallpaperService extends Service { final ClientWindowFrames mWinFrames = new ClientWindowFrames(); final Rect mDispatchedContentInsets = new Rect(); final Rect mDispatchedStableInsets = new Rect(); - final Rect mFinalSystemInsets = new Rect(); - final Rect mFinalStableInsets = new Rect(); DisplayCutout mDispatchedDisplayCutout = DisplayCutout.NO_CUTOUT; final InsetsState mInsetsState = new InsetsState(); + final InsetsVisibilities mRequestedVisibilities = new InsetsVisibilities(); final InsetsSourceControl[] mTempControls = new InsetsSourceControl[0]; final MergedConfiguration mMergedConfiguration = new MergedConfiguration(); private final Point mSurfaceSize = new Point(); @@ -266,6 +277,8 @@ public abstract class WallpaperService extends Service { SurfaceControl mSurfaceControl = new SurfaceControl(); SurfaceControl mBbqSurfaceControl; BLASTBufferQueue mBlastBufferQueue; + private SurfaceControl mScreenshotSurfaceControl; + private Point mScreenshotSize = new Point(); final BaseSurfaceHolder mSurfaceHolder = new BaseSurfaceHolder() { { @@ -774,7 +787,7 @@ public abstract class WallpaperService extends Service { Log.w(TAG, "Can't notify system because wallpaper connection " + "was not established."); } - resetWindowPages(); + mResetWindowPages = true; processLocalColors(mPendingXOffset, mPendingXOffsetStep); } catch (RemoteException e) { Log.w(TAG, "Can't notify system because wallpaper connection was lost.", e); @@ -1033,8 +1046,8 @@ public abstract class WallpaperService extends Service { InputChannel inputChannel = new InputChannel(); if (mSession.addToDisplay(mWindow, mLayout, View.VISIBLE, - mDisplay.getDisplayId(), mInsetsState, inputChannel, mInsetsState, - mTempControls) < 0) { + mDisplay.getDisplayId(), mRequestedVisibilities, inputChannel, + mInsetsState, mTempControls) < 0) { Log.w(TAG, "Failed to add window while updating wallpaper surface."); return; } @@ -1384,11 +1397,15 @@ public abstract class WallpaperService extends Service { if (!mDestroyed) { mVisible = visible; reportVisibility(); - if (visible) processLocalColors(mPendingXOffset, mPendingXOffsetStep); + if (mReportedVisible) processLocalColors(mPendingXOffset, mPendingXOffsetStep); } } void reportVisibility() { + if (mScreenshotSurfaceControl != null && mVisible) { + if (DEBUG) Log.v(TAG, "Frozen so don't report visibility change"); + return; + } if (!mDestroyed) { mDisplayState = mDisplay == null ? Display.STATE_UNKNOWN : mDisplay.getState(); boolean visible = mVisible && mDisplayState != Display.STATE_OFF; @@ -1405,6 +1422,10 @@ public abstract class WallpaperService extends Service { updateSurface(true, false, false); } onVisibilityChanged(visible); + if (mReportedVisible && mFrozenRequested) { + if (DEBUG) Log.v(TAG, "Freezing wallpaper after visibility update"); + freeze(); + } } } } @@ -1469,7 +1490,7 @@ public abstract class WallpaperService extends Service { //below is the default implementation if (xOffset % xOffsetStep > MIN_PAGE_ALLOWED_MARGIN || !mSurfaceHolder.getSurface().isValid()) return; - int xPage; + int xCurrentPage; int xPages; if (!validStep(xOffsetStep)) { if (DEBUG) { @@ -1477,30 +1498,35 @@ public abstract class WallpaperService extends Service { } xOffset = 0; xOffsetStep = 1; - xPage = 0; + xCurrentPage = 0; xPages = 1; } else { xPages = Math.round(1 / xOffsetStep) + 1; xOffsetStep = (float) 1 / (float) xPages; float shrink = (float) (xPages - 1) / (float) xPages; xOffset *= shrink; - xPage = Math.round(xOffset / xOffsetStep); + xCurrentPage = Math.round(xOffset / xOffsetStep); } if (DEBUG) { - Log.d(TAG, "xPages " + xPages + " xPage " + xPage); + Log.d(TAG, "xPages " + xPages + " xPage " + xCurrentPage); Log.d(TAG, "xOffsetStep " + xOffsetStep + " xOffset " + xOffset); } - EngineWindowPage current; - synchronized (mLock) { + + float finalXOffsetStep = xOffsetStep; + float finalXOffset = xOffset; + mHandler.post(() -> { + resetWindowPages(); + int xPage = xCurrentPage; + EngineWindowPage current; if (mWindowPages.length == 0 || (mWindowPages.length != xPages)) { mWindowPages = new EngineWindowPage[xPages]; - initWindowPages(mWindowPages, xOffsetStep); + initWindowPages(mWindowPages, finalXOffsetStep); } if (mLocalColorsToAdd.size() != 0) { for (RectF colorArea : mLocalColorsToAdd) { if (!isValid(colorArea)) continue; mLocalColorAreas.add(colorArea); - int colorPage = getRectFPage(colorArea, xOffsetStep); + int colorPage = getRectFPage(colorArea, finalXOffsetStep); EngineWindowPage currentPage = mWindowPages[colorPage]; if (currentPage == null) { currentPage = new EngineWindowPage(); @@ -1518,7 +1544,8 @@ public abstract class WallpaperService extends Service { Log.e(TAG, "error xPage >= mWindowPages.length page: " + xPage); Log.e(TAG, "error on page " + xPage + " out of " + xPages); Log.e(TAG, - "error on xOffsetStep " + xOffsetStep + " xOffset " + xOffset); + "error on xOffsetStep " + finalXOffsetStep + + " xOffset " + finalXOffset); } xPage = mWindowPages.length - 1; } @@ -1526,13 +1553,14 @@ public abstract class WallpaperService extends Service { if (current == null) { if (DEBUG) Log.d(TAG, "making page " + xPage + " out of " + xPages); if (DEBUG) { - Log.d(TAG, "xOffsetStep " + xOffsetStep + " xOffset " + xOffset); + Log.d(TAG, "xOffsetStep " + finalXOffsetStep + " xOffset " + + finalXOffset); } current = new EngineWindowPage(); mWindowPages[xPage] = current; } - } - updatePage(current, xPage, xPages, xOffsetStep); + updatePage(current, xPage, xPages, finalXOffsetStep); + }); } private void initWindowPages(EngineWindowPage[] windowPages, float step) { @@ -1554,7 +1582,7 @@ public abstract class WallpaperService extends Service { void updatePage(EngineWindowPage currentPage, int pageIndx, int numPages, float xOffsetStep) { // to save creating a runnable, check twice - long current = SystemClock.elapsedRealtime(); + long current = System.currentTimeMillis(); long lapsed = current - currentPage.getLastUpdateTime(); // Always update the page when the last update time is <= 0 // This is important especially when the device first boots @@ -1582,10 +1610,8 @@ public abstract class WallpaperService extends Service { if (DEBUG) Log.d(TAG, "result of pixel copy is " + res); if (res != PixelCopy.SUCCESS) { Bitmap lastBitmap = currentPage.getBitmap(); - currentPage.execSync((p) -> { - // assign the last bitmap taken for now - p.setBitmap(mLastScreenshot); - }); + // assign the last bitmap taken for now + currentPage.setBitmap(mLastScreenshot); Bitmap lastScreenshot = mLastScreenshot; if (lastScreenshot != null && !lastScreenshot.isRecycled() && !Objects.equals(lastBitmap, lastScreenshot)) { @@ -1594,10 +1620,8 @@ public abstract class WallpaperService extends Service { } else { mLastScreenshot = finalScreenShot; // going to hold this lock for a while - currentPage.execSync((p) -> { - p.setBitmap(finalScreenShot); - p.setLastUpdateTime(current); - }); + currentPage.setBitmap(finalScreenShot); + currentPage.setLastUpdateTime(current); updatePageColors(currentPage, pageIndx, numPages, xOffsetStep); } }, mHandler); @@ -1676,15 +1700,13 @@ public abstract class WallpaperService extends Service { private void resetWindowPages() { if (supportsLocalColorExtraction()) return; + if (!mResetWindowPages) return; + mResetWindowPages = false; mLastWindowPage = -1; - synchronized (mLock) { - for (int i = 0; i < mWindowPages.length; i++) { - EngineWindowPage page = mWindowPages[i]; - if (page != null) { - page.execSync((p) -> { - p.setLastUpdateTime(0L); - }); - } + for (int i = 0; i < mWindowPages.length; i++) { + EngineWindowPage page = mWindowPages[i]; + if (page != null) { + page.setLastUpdateTime(0L); } } } @@ -1709,44 +1731,12 @@ public abstract class WallpaperService extends Service { if (DEBUG) { Log.d(TAG, "addLocalColorsAreas adding local color areas " + regions); } - float step = mPendingXOffsetStep; + mHandler.post(() -> { + mLocalColorsToAdd.addAll(regions); + processLocalColors(mPendingXOffset, mPendingYOffset); + }); - List colors = getLocalWallpaperColors(regions); - synchronized (mLock) { - if (!validStep(step)) { - step = 0; - } - for (int i = 0; i < regions.size(); i++) { - RectF area = regions.get(i); - if (!isValid(area)) continue; - int pageInx = getRectFPage(area, step); - // no page should be null - EngineWindowPage page = mWindowPages[pageInx]; - - if (page != null) { - mLocalColorAreas.add(area); - page.addArea(area); - WallpaperColors color = colors.get(i); - if (color != null && !color.equals(page.getColors(area))) { - page.execSync(p -> { - p.addWallpaperColors(area, color); - }); - } - } else { - mLocalColorsToAdd.add(area); - } - } - } - for (int i = 0; i < colors.size() && colors.get(i) != null; i++) { - try { - mConnection.onLocalWallpaperColorsChanged(regions.get(i), colors.get(i), - mDisplayContext.getDisplayId()); - } catch (RemoteException e) { - Log.e(TAG, "Error calling Connection.onLocalWallpaperColorsChanged", e); - return; - } - } } /** @@ -1756,95 +1746,20 @@ public abstract class WallpaperService extends Service { */ public void removeLocalColorsAreas(@NonNull List regions) { if (supportsLocalColorExtraction()) return; - synchronized (mLock) { + mHandler.post(() -> { float step = mPendingXOffsetStep; mLocalColorsToAdd.removeAll(regions); mLocalColorAreas.removeAll(regions); if (!validStep(step)) { return; } - for (int i = 0; i < regions.size(); i++) { - RectF area = regions.get(i); - if (!isValid(area)) continue; - int pageInx = getRectFPage(area, step); - // no page should be null - EngineWindowPage page = mWindowPages[pageInx]; - if (page != null) { - page.execSync(p -> { - p.removeArea(area); - }); - } - } - } - } - - private @NonNull List getLocalWallpaperColors(@NonNull List areas) { - ArrayList colors = new ArrayList<>(areas.size()); - float step = mPendingXOffsetStep; - if (!validStep(step)) { - if (DEBUG) Log.d(TAG, "invalid step size " + step); - step = 1.0f; - } - for (int i = 0; i < areas.size(); i++) { - RectF currentArea = areas.get(i); - if (currentArea == null || !isValid(currentArea)) { - Log.wtf(TAG, "invalid local area " + currentArea); - continue; - } - EngineWindowPage page; - RectF area; - int pageIndx; - synchronized (mLock) { - pageIndx = getRectFPage(currentArea, step); - if (mWindowPages.length == 0 || pageIndx < 0 - || pageIndx > mWindowPages.length || !isValid(currentArea)) { - colors.add(null); - continue; - } - area = generateSubRect(currentArea, pageIndx, mWindowPages.length); - page = mWindowPages[pageIndx]; - } - if (page == null) { - colors.add(null); - continue; - } - float finalStep = step; - int finalPageIndx = pageIndx; - Bitmap screenShot = page.getBitmap(); - if (screenShot == null) screenShot = mLastScreenshot; - if (screenShot == null || screenShot.isRecycled()) { - if (DEBUG) { - Log.d(TAG, "invalid bitmap " + screenShot - + " for page " + finalPageIndx); + for (int i = 0; i < mWindowPages.length; i++) { + for (int j = 0; j < regions.size(); j++) { + EngineWindowPage page = mWindowPages[i]; + if (page != null) page.removeArea(regions.get(j)); } - page.setLastUpdateTime(0); - colors.add(null); - continue; } - Bitmap b = screenShot; - Rect subImage = new Rect( - Math.round(area.left * b.getWidth() / finalStep), - Math.round(area.top * b.getHeight()), - Math.round(area.right * b.getWidth() / finalStep), - Math.round(area.bottom * b.getHeight()) - ); - subImage = fixRect(b, subImage); - if (DEBUG) { - Log.d(TAG, "getting subbitmap of " + subImage.toString() - + " for RectF " + area.toString() - + " screenshot width " + screenShot.getWidth() + " height " - + screenShot.getHeight()); - } - Bitmap colorImg = Bitmap.createBitmap(screenShot, - subImage.left, subImage.top, subImage.width(), subImage.height()); - if (DEBUG) { - Log.d(TAG, "created bitmap " + colorImg.getWidth() + ", " - + colorImg.getHeight()); - } - WallpaperColors color = WallpaperColors.fromBitmap(colorImg); - colors.add(color); - } - return colors; + }); } // fix the rect to be included within the bounds of the bitmap @@ -1865,6 +1780,9 @@ public abstract class WallpaperService extends Service { void doCommand(WallpaperCommand cmd) { Bundle result; if (!mDestroyed) { + if (COMMAND_FREEZE.equals(cmd.action) || COMMAND_UNFREEZE.equals(cmd.action)) { + updateFrozenState(/* frozenRequested= */ !COMMAND_UNFREEZE.equals(cmd.action)); + } result = onCommand(cmd.action, cmd.x, cmd.y, cmd.z, cmd.extras, cmd.sync); } else { @@ -1879,6 +1797,159 @@ public abstract class WallpaperService extends Service { } } + private void updateFrozenState(boolean frozenRequested) { + if (mIWallpaperEngine.mWallpaperManager.getWallpaperInfo() == null + // Procees the unfreeze command in case the wallaper became static while + // being paused. + && frozenRequested) { + if (DEBUG) Log.v(TAG, "Ignoring the freeze command for static wallpapers"); + return; + } + mFrozenRequested = frozenRequested; + boolean isFrozen = mScreenshotSurfaceControl != null; + if (mFrozenRequested == isFrozen) { + return; + } + if (mFrozenRequested) { + freeze(); + } else { + unfreeze(); + } + } + + private void freeze() { + if (!mReportedVisible || mDestroyed) { + // Screenshot can't be taken until visibility is reported to the wallpaper host. + return; + } + if (!showScreenshotOfWallpaper()) { + return; + } + // Prevent a wallpaper host from rendering wallpaper behind a screeshot. + doVisibilityChanged(false); + // Remember that visibility is requested since it's not guaranteed that + // mWindow#dispatchAppVisibility will be called when letterboxed application with + // wallpaper background transitions to the Home screen. + mVisible = true; + } + + private void unfreeze() { + cleanUpScreenshotSurfaceControl(); + if (mVisible) { + doVisibilityChanged(true); + } + } + + private void cleanUpScreenshotSurfaceControl() { + // TODO(b/194399558): Add crossfade transition. + if (mScreenshotSurfaceControl != null) { + new SurfaceControl.Transaction() + .remove(mScreenshotSurfaceControl) + .show(mBbqSurfaceControl) + .apply(); + mScreenshotSurfaceControl = null; + } + } + + void scaleAndCropScreenshot() { + if (mScreenshotSurfaceControl == null) { + return; + } + if (mScreenshotSize.x <= 0 || mScreenshotSize.y <= 0) { + Log.w(TAG, "Unexpected screenshot size: " + mScreenshotSize); + return; + } + // Don't scale down and using the same scaling factor for both dimensions to + // avoid stretching wallpaper image. + float scaleFactor = Math.max(1, Math.max( + ((float) mSurfaceSize.x) / mScreenshotSize.x, + ((float) mSurfaceSize.y) / mScreenshotSize.y)); + int diffX = ((int) (mScreenshotSize.x * scaleFactor)) - mSurfaceSize.x; + int diffY = ((int) (mScreenshotSize.y * scaleFactor)) - mSurfaceSize.y; + if (DEBUG) { + Log.v(TAG, "Adjusting screenshot: scaleFactor=" + scaleFactor + + " diffX=" + diffX + " diffY=" + diffY + " mSurfaceSize=" + mSurfaceSize + + " mScreenshotSize=" + mScreenshotSize); + } + new SurfaceControl.Transaction() + .setMatrix( + mScreenshotSurfaceControl, + /* dsdx= */ scaleFactor, /* dtdx= */ 0, + /* dtdy= */ 0, /* dsdy= */ scaleFactor) + .setWindowCrop( + mScreenshotSurfaceControl, + new Rect( + /* left= */ diffX / 2, + /* top= */ diffY / 2, + /* right= */ diffX / 2 + mScreenshotSize.x, + /* bottom= */ diffY / 2 + mScreenshotSize.y)) + .setPosition(mScreenshotSurfaceControl, -diffX / 2, -diffY / 2) + .apply(); + } + + private boolean showScreenshotOfWallpaper() { + if (mDestroyed || mSurfaceControl == null || !mSurfaceControl.isValid()) { + if (DEBUG) Log.v(TAG, "Failed to screenshot wallpaper: surface isn't valid"); + return false; + } + + final Rect bounds = new Rect(0, 0, mSurfaceSize.x, mSurfaceSize.y); + if (bounds.isEmpty()) { + Log.w(TAG, "Failed to screenshot wallpaper: surface bounds are empty"); + return false; + } + + if (mScreenshotSurfaceControl != null) { + Log.e(TAG, "Screenshot is unexpectedly not null"); + // Destroying previous screenshot since it can have different size. + cleanUpScreenshotSurfaceControl(); + } + + SurfaceControl.ScreenshotHardwareBuffer screenshotBuffer = + SurfaceControl.captureLayers( + new SurfaceControl.LayerCaptureArgs.Builder(mSurfaceControl) + // Needed because SurfaceFlinger#validateScreenshotPermissions + // uses this parameter to check whether a caller only attempts + // to screenshot itself when call doesn't come from the system. + .setUid(Process.myUid()) + .setChildrenOnly(false) + .setSourceCrop(bounds) + .build()); + + if (screenshotBuffer == null) { + Log.w(TAG, "Failed to screenshot wallpaper: screenshotBuffer is null"); + return false; + } + + final HardwareBuffer hardwareBuffer = screenshotBuffer.getHardwareBuffer(); + + SurfaceControl.Transaction t = new SurfaceControl.Transaction(); + + // TODO(b/194399558): Add crossfade transition. + mScreenshotSurfaceControl = new SurfaceControl.Builder() + .setName("Wallpaper snapshot for engine " + this) + .setFormat(hardwareBuffer.getFormat()) + .setParent(mSurfaceControl) + .setSecure(screenshotBuffer.containsSecureLayers()) + .setCallsite("WallpaperService.Engine.showScreenshotOfWallpaper") + .setBLASTLayer() + .build(); + + mScreenshotSize.set(mSurfaceSize.x, mSurfaceSize.y); + + GraphicBuffer graphicBuffer = GraphicBuffer.createFromHardwareBuffer(hardwareBuffer); + + t.setBuffer(mScreenshotSurfaceControl, graphicBuffer); + t.setColorSpace(mScreenshotSurfaceControl, screenshotBuffer.getColorSpace()); + // Place on top everything else. + t.setLayer(mScreenshotSurfaceControl, Integer.MAX_VALUE); + t.show(mScreenshotSurfaceControl); + t.hide(mBbqSurfaceControl); + t.apply(); + + return true; + } + void reportSurfaceDestroyed() { if (mSurfaceCreated) { mSurfaceCreated = false; @@ -2203,6 +2274,7 @@ public abstract class WallpaperService extends Service { final boolean reportDraw = message.arg1 != 0; mEngine.updateSurface(true, false, reportDraw); mEngine.doOffsetsChanged(true); + mEngine.scaleAndCropScreenshot(); } break; case MSG_WINDOW_MOVED: { // Do nothing. What does it mean for a Wallpaper to move? diff --git a/core/java/android/text/style/StyleSpan.java b/core/java/android/text/style/StyleSpan.java index bdfa700215f8..9cdd54c16a42 100644 --- a/core/java/android/text/style/StyleSpan.java +++ b/core/java/android/text/style/StyleSpan.java @@ -17,8 +17,10 @@ package android.text.style; import android.annotation.NonNull; +import android.content.res.Configuration; import android.graphics.Paint; import android.graphics.Typeface; +import android.graphics.fonts.FontStyle; import android.os.Parcel; import android.text.ParcelableSpan; import android.text.TextPaint; @@ -45,6 +47,7 @@ import android.text.TextUtils; public class StyleSpan extends MetricAffectingSpan implements ParcelableSpan { private final int mStyle; + private final int mFontWeightAdjustment; /** * Creates a {@link StyleSpan} from a style. @@ -54,7 +57,24 @@ public class StyleSpan extends MetricAffectingSpan implements ParcelableSpan { * in {@link Typeface}. */ public StyleSpan(int style) { + this(style, Configuration.FONT_WEIGHT_ADJUSTMENT_UNDEFINED); + } + + /** + * Creates a {@link StyleSpan} from a style and font weight adjustment. + * + * @param style An integer constant describing the style for this span. Examples + * include bold, italic, and normal. Values are constants defined + * in {@link Typeface}. + * @param fontWeightAdjustment An integer describing the adjustment to be made to the font + * weight. + * @see Configuration#fontWeightAdjustment This is the adjustment in text font weight + * that is used to reflect the current user's preference for increasing font weight. + * @hide + */ + public StyleSpan(@Typeface.Style int style, int fontWeightAdjustment) { mStyle = style; + mFontWeightAdjustment = fontWeightAdjustment; } /** @@ -64,6 +84,7 @@ public class StyleSpan extends MetricAffectingSpan implements ParcelableSpan { */ public StyleSpan(@NonNull Parcel src) { mStyle = src.readInt(); + mFontWeightAdjustment = src.readInt(); } @Override @@ -91,6 +112,7 @@ public class StyleSpan extends MetricAffectingSpan implements ParcelableSpan { @Override public void writeToParcelInternal(@NonNull Parcel dest, int flags) { dest.writeInt(mStyle); + dest.writeInt(mFontWeightAdjustment); } /** @@ -100,17 +122,25 @@ public class StyleSpan extends MetricAffectingSpan implements ParcelableSpan { return mStyle; } + /** + * Returns the font weight adjustment specified by this span. + * @hide + */ + public int getFontWeightAdjustment() { + return mFontWeightAdjustment; + } + @Override public void updateDrawState(TextPaint ds) { - apply(ds, mStyle); + apply(ds, mStyle, mFontWeightAdjustment); } @Override public void updateMeasureState(TextPaint paint) { - apply(paint, mStyle); + apply(paint, mStyle, mFontWeightAdjustment); } - private static void apply(Paint paint, int style) { + private static void apply(Paint paint, int style, int fontWeightAdjustment) { int oldStyle; Typeface old = paint.getTypeface(); @@ -129,6 +159,18 @@ public class StyleSpan extends MetricAffectingSpan implements ParcelableSpan { tf = Typeface.create(old, want); } + // Base typeface may already be bolded by auto bold. Bold further. + if ((style & Typeface.BOLD) != 0) { + if (fontWeightAdjustment != 0 + && fontWeightAdjustment != Configuration.FONT_WEIGHT_ADJUSTMENT_UNDEFINED) { + int newWeight = Math.min( + Math.max(tf.getWeight() + fontWeightAdjustment, FontStyle.FONT_WEIGHT_MIN), + FontStyle.FONT_WEIGHT_MAX); + boolean italic = (want & Typeface.ITALIC) != 0; + tf = Typeface.create(tf, newWeight, italic); + } + } + int fake = want & ~tf.getStyle(); if ((fake & Typeface.BOLD) != 0) { diff --git a/core/java/android/util/ArrayMap.java b/core/java/android/util/ArrayMap.java index 4edff27d0ced..0b50192bfa48 100644 --- a/core/java/android/util/ArrayMap.java +++ b/core/java/android/util/ArrayMap.java @@ -646,7 +646,7 @@ public final class ArrayMap implements Map { e.fillInStackTrace(); Log.w(TAG, "New hash " + hash + " is before end of array hash " + mHashes[index-1] - + " at index " + index + " key " + key, e); + + " at index " + index + (DEBUG ? " key " + key : ""), e); put(key, value); return; } diff --git a/core/java/android/util/DisplayUtils.java b/core/java/android/util/DisplayUtils.java new file mode 100644 index 000000000000..4fe7f8369f73 --- /dev/null +++ b/core/java/android/util/DisplayUtils.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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; + +import android.content.res.Resources; + +import com.android.internal.R; + +/** + * Utils for loading resources for multi-display. + * + * @hide + */ +public class DisplayUtils { + + /** + * Gets the index of the given display unique id in {@link R.array#config_displayUniqueIdArray} + * which is used to get the related cutout configs for that display. + * + * For multi-display device, {@link R.array#config_displayUniqueIdArray} should be set for each + * display if there are different type of cutouts on each display. + * For single display device, {@link R.array#config_displayUniqueIdArray} should not to be set + * and the system will load the default configs for main built-in display. + */ + public static int getDisplayUniqueIdConfigIndex(Resources res, String displayUniqueId) { + int index = -1; + if (displayUniqueId == null || displayUniqueId.isEmpty()) { + return index; + } + final String[] ids = res.getStringArray(R.array.config_displayUniqueIdArray); + final int size = ids.length; + for (int i = 0; i < size; i++) { + if (displayUniqueId.equals(ids[i])) { + index = i; + break; + } + } + return index; + } +} diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java index dbfeb113307e..871fd51b5968 100644 --- a/core/java/android/util/FeatureFlagUtils.java +++ b/core/java/android/util/FeatureFlagUtils.java @@ -51,6 +51,13 @@ public class FeatureFlagUtils { /** @hide */ public static final String SETTINGS_ENABLE_SECURITY_HUB = "settings_enable_security_hub"; + /** @hide */ + public static final String SETTINGS_SUPPORT_LARGE_SCREEN = "settings_support_large_screen"; + + /** @hide */ + public static final String SETTINGS_ENABLE_MONITOR_PHANTOM_PROCS = + "settings_enable_monitor_phantom_procs"; + private static final Map DEFAULT_FLAGS; static { @@ -72,12 +79,16 @@ public class FeatureFlagUtils { DEFAULT_FLAGS.put(SETTINGS_PROVIDER_MODEL, "false"); DEFAULT_FLAGS.put(SETTINGS_USE_NEW_BACKUP_ELIGIBILITY_RULES, "true"); DEFAULT_FLAGS.put(SETTINGS_ENABLE_SECURITY_HUB, "true"); + DEFAULT_FLAGS.put(SETTINGS_SUPPORT_LARGE_SCREEN, "true"); + DEFAULT_FLAGS.put(SETTINGS_ENABLE_MONITOR_PHANTOM_PROCS, "true"); } private static final Set PERSISTENT_FLAGS; static { PERSISTENT_FLAGS = new HashSet<>(); PERSISTENT_FLAGS.add(SETTINGS_PROVIDER_MODEL); + PERSISTENT_FLAGS.add(SETTINGS_SUPPORT_LARGE_SCREEN); + PERSISTENT_FLAGS.add(SETTINGS_ENABLE_MONITOR_PHANTOM_PROCS); } /** diff --git a/core/java/android/util/MathUtils.java b/core/java/android/util/MathUtils.java index 971e16185815..aecde4415117 100644 --- a/core/java/android/util/MathUtils.java +++ b/core/java/android/util/MathUtils.java @@ -165,6 +165,10 @@ public final class MathUtils { return start + (stop - start) * amount; } + public static float lerp(int start, int stop, float amount) { + return lerp((float) start, (float) stop, amount); + } + /** * Returns the interpolation scalar (s) that satisfies the equation: {@code value = }{@link * #lerp}{@code (a, b, s)} diff --git a/core/java/android/util/imetracing/ImeTracingServerImpl.java b/core/java/android/util/imetracing/ImeTracingServerImpl.java index 06e4c5002776..d605430bcf14 100644 --- a/core/java/android/util/imetracing/ImeTracingServerImpl.java +++ b/core/java/android/util/imetracing/ImeTracingServerImpl.java @@ -41,9 +41,9 @@ import java.io.PrintWriter; */ class ImeTracingServerImpl extends ImeTracing { private static final String TRACE_DIRNAME = "/data/misc/wmtrace/"; - private static final String TRACE_FILENAME_CLIENTS = "ime_trace_clients.pb"; - private static final String TRACE_FILENAME_IMS = "ime_trace_service.pb"; - private static final String TRACE_FILENAME_IMMS = "ime_trace_managerservice.pb"; + private static final String TRACE_FILENAME_CLIENTS = "ime_trace_clients.winscope"; + private static final String TRACE_FILENAME_IMS = "ime_trace_service.winscope"; + private static final String TRACE_FILENAME_IMMS = "ime_trace_managerservice.winscope"; private static final int BUFFER_CAPACITY = 4096 * 1024; // Needed for winscope to auto-detect the dump type. Explained further in diff --git a/core/java/android/view/AttachedSurfaceControl.java b/core/java/android/view/AttachedSurfaceControl.java index bcc5b56459bb..69af2a5ce7fb 100644 --- a/core/java/android/view/AttachedSurfaceControl.java +++ b/core/java/android/view/AttachedSurfaceControl.java @@ -18,6 +18,7 @@ package android.view; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UiThread; +import android.hardware.HardwareBuffer; /** * Provides an interface to the root-Surface of a View Hierarchy or Window. This @@ -53,4 +54,74 @@ public interface AttachedSurfaceControl { * to the View hierarchy you may need to call {@link android.view.View#invalidate} */ boolean applyTransactionOnDraw(@NonNull SurfaceControl.Transaction t); + + /** + * The transform hint can be used by a buffer producer to pre-rotate the rendering such that the + * final transformation in the system composer is identity. This can be very useful when used in + * conjunction with the h/w composer HAL in situations where it cannot handle rotations or + * handle them with an additional power cost. + * + * The transform hint should be used with ASurfaceControl APIs when submitting buffers. + * Example usage: + * + * 1. After a configuration change, before dequeuing a buffer, the buffer producer queries the + * function for the transform hint. + * + * 2. The desired buffer width and height is rotated by the transform hint. + * + * 3. The producer dequeues a buffer of the new pre-rotated size. + * + * 4. The producer renders to the buffer such that the image is already transformed, that is + * applying the transform hint to the rendering. + * + * 5. The producer applies the inverse transform hint to the buffer it just rendered. + * + * 6. The producer queues the pre-transformed buffer with the buffer transform. + * + * 7. The composer combines the buffer transform with the display transform. If the buffer + * transform happens to cancel out the display transform then no rotation is needed and there + * will be no performance penalties. + * + * Note, when using ANativeWindow APIs in conjunction with a NativeActivity Surface or + * SurfaceView Surface, the buffer producer will already have access to the transform hint and + * no additional work is needed. + * + * @see HardwareBuffer + */ + default @SurfaceControl.BufferTransform int getBufferTransformHint() { + return SurfaceControl.BUFFER_TRANSFORM_IDENTITY; + } + + /** + * Buffer transform hint change listener. + * @see #getBufferTransformHint + */ + @UiThread + interface OnBufferTransformHintChangedListener { + /** + * @param hint new surface transform hint + * @see #getBufferTransformHint + */ + void onBufferTransformHintChanged(@SurfaceControl.BufferTransform int hint); + } + + /** + * Registers a {@link OnBufferTransformHintChangedListener} to receive notifications about when + * the transform hint changes. + * + * @see #getBufferTransformHint + * @see #removeOnBufferTransformHintChangedListener + */ + default void addOnBufferTransformHintChangedListener( + @NonNull OnBufferTransformHintChangedListener listener) { + } + + /** + * Unregisters a {@link OnBufferTransformHintChangedListener}. + * + * @see #addOnBufferTransformHintChangedListener + */ + default void removeOnBufferTransformHintChangedListener( + @NonNull OnBufferTransformHintChangedListener listener) { + } } diff --git a/core/java/android/view/BatchedInputEventReceiver.java b/core/java/android/view/BatchedInputEventReceiver.java index 7023e4bd0134..1ed12f74ba2c 100644 --- a/core/java/android/view/BatchedInputEventReceiver.java +++ b/core/java/android/view/BatchedInputEventReceiver.java @@ -17,6 +17,7 @@ package android.view; import android.compat.annotation.UnsupportedAppUsage; +import android.os.Handler; import android.os.Looper; /** @@ -27,6 +28,13 @@ public class BatchedInputEventReceiver extends InputEventReceiver { private Choreographer mChoreographer; private boolean mBatchingEnabled; private boolean mBatchedInputScheduled; + private final Handler mHandler; + private final Runnable mConsumeBatchedInputEvents = new Runnable() { + @Override + public void run() { + consumeBatchedInputEvents(-1); + } + }; @UnsupportedAppUsage public BatchedInputEventReceiver( @@ -34,6 +42,7 @@ public class BatchedInputEventReceiver extends InputEventReceiver { super(inputChannel, looper); mChoreographer = choreographer; mBatchingEnabled = true; + mHandler = new Handler(looper); } @Override @@ -57,10 +66,15 @@ public class BatchedInputEventReceiver extends InputEventReceiver { * @hide */ public void setBatchingEnabled(boolean batchingEnabled) { + if (mBatchingEnabled == batchingEnabled) { + return; + } + mBatchingEnabled = batchingEnabled; + mHandler.removeCallbacks(mConsumeBatchedInputEvents); if (!batchingEnabled) { unscheduleBatchedInput(); - consumeBatchedInputEvents(-1); + mHandler.post(mConsumeBatchedInputEvents); } } diff --git a/core/java/android/view/DisplayCutout.java b/core/java/android/view/DisplayCutout.java index b101d1178b8a..0632dbc6b691 100644 --- a/core/java/android/view/DisplayCutout.java +++ b/core/java/android/view/DisplayCutout.java @@ -31,6 +31,7 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.res.Resources; +import android.content.res.TypedArray; import android.graphics.Insets; import android.graphics.Matrix; import android.graphics.Path; @@ -39,6 +40,7 @@ import android.os.Parcel; import android.os.Parcelable; import android.os.SystemProperties; import android.text.TextUtils; +import android.util.DisplayUtils; import android.util.Pair; import android.util.RotationUtils; import android.util.proto.ProtoOutputStream; @@ -873,6 +875,110 @@ public final class DisplayCutout { false /* copyArguments */); } + /** + * Gets the display cutout by the given display unique id. + * + * Loads the default config {@link R.string#config_mainBuiltInDisplayCutout) if + * {@link R.array#config_displayUniqueIdArray} is not set. + */ + private static String getDisplayCutoutPath(Resources res, String displayUniqueId) { + final int index = DisplayUtils.getDisplayUniqueIdConfigIndex(res, displayUniqueId); + final String[] array = res.getStringArray(R.array.config_displayCutoutPathArray); + if (index >= 0 && index < array.length) { + return array[index]; + } + return res.getString(R.string.config_mainBuiltInDisplayCutout); + } + + /** + * Gets the display cutout approximation rect by the given display unique id. + * + * Loads the default config {@link R.string#config_mainBuiltInDisplayCutoutRectApproximation} if + * {@link R.array#config_displayUniqueIdArray} is not set. + */ + private static String getDisplayCutoutApproximationRect(Resources res, String displayUniqueId) { + final int index = DisplayUtils.getDisplayUniqueIdConfigIndex(res, displayUniqueId); + final String[] array = res.getStringArray( + R.array.config_displayCutoutApproximationRectArray); + if (index >= 0 && index < array.length) { + return array[index]; + } + return res.getString(R.string.config_mainBuiltInDisplayCutoutRectApproximation); + } + + /** + * Gets whether to mask a built-in display cutout of a display which is determined by the + * given display unique id. + * + * Loads the default config {@link R.bool#config_maskMainBuiltInDisplayCutout} if + * {@link R.array#config_displayUniqueIdArray} is not set. + * + * @hide + */ + public static boolean getMaskBuiltInDisplayCutout(Resources res, String displayUniqueId) { + final int index = DisplayUtils.getDisplayUniqueIdConfigIndex(res, displayUniqueId); + final TypedArray array = res.obtainTypedArray(R.array.config_maskBuiltInDisplayCutoutArray); + boolean maskCutout; + if (index >= 0 && index < array.length()) { + maskCutout = array.getBoolean(index, false); + } else { + maskCutout = res.getBoolean(R.bool.config_maskMainBuiltInDisplayCutout); + } + array.recycle(); + return maskCutout; + } + + /** + * Gets whether to fill a built-in display cutout of a display which is determined by the + * given display unique id. + * + * Loads the default config{@link R.bool#config_fillMainBuiltInDisplayCutout} if + * {@link R.array#config_displayUniqueIdArray} is not set. + * + * @hide + */ + public static boolean getFillBuiltInDisplayCutout(Resources res, String displayUniqueId) { + final int index = DisplayUtils.getDisplayUniqueIdConfigIndex(res, displayUniqueId); + final TypedArray array = res.obtainTypedArray(R.array.config_fillBuiltInDisplayCutoutArray); + boolean fillCutout; + if (index >= 0 && index < array.length()) { + fillCutout = array.getBoolean(index, false); + } else { + fillCutout = res.getBoolean(R.bool.config_fillMainBuiltInDisplayCutout); + } + array.recycle(); + return fillCutout; + } + + /** + * Gets the waterfall cutout by the given display unique id. + * + * Loads the default waterfall dimens if {@link R.array#config_displayUniqueIdArray} is not set. + * {@link R.dimen#waterfall_display_left_edge_size}, + * {@link R.dimen#waterfall_display_top_edge_size}, + * {@link R.dimen#waterfall_display_right_edge_size}, + * {@link R.dimen#waterfall_display_bottom_edge_size} + */ + private static Insets getWaterfallInsets(Resources res, String displayUniqueId) { + Insets insets; + final int index = DisplayUtils.getDisplayUniqueIdConfigIndex(res, displayUniqueId); + final TypedArray array = res.obtainTypedArray(R.array.config_waterfallCutoutArray); + if (index >= 0 && index < array.length() && array.getResourceId(index, 0) > 0) { + final int resourceId = array.getResourceId(index, 0); + final TypedArray waterfall = res.obtainTypedArray(resourceId); + insets = Insets.of( + waterfall.getDimensionPixelSize(0 /* waterfall left edge size */, 0), + waterfall.getDimensionPixelSize(1 /* waterfall top edge size */, 0), + waterfall.getDimensionPixelSize(2 /* waterfall right edge size */, 0), + waterfall.getDimensionPixelSize(3 /* waterfall bottom edge size */, 0)); + waterfall.recycle(); + } else { + insets = loadWaterfallInset(res); + } + array.recycle(); + return insets; + } + /** * Creates the display cutout according to * @android:string/config_mainBuiltInDisplayCutoutRectApproximation, which is the closest @@ -880,12 +986,12 @@ public final class DisplayCutout { * * @hide */ - public static DisplayCutout fromResourcesRectApproximation(Resources res, int displayWidth, - int displayHeight) { - return pathAndDisplayCutoutFromSpec(res.getString(R.string.config_mainBuiltInDisplayCutout), - res.getString(R.string.config_mainBuiltInDisplayCutoutRectApproximation), + public static DisplayCutout fromResourcesRectApproximation(Resources res, + String displayUniqueId, int displayWidth, int displayHeight) { + return pathAndDisplayCutoutFromSpec(getDisplayCutoutPath(res, displayUniqueId), + getDisplayCutoutApproximationRect(res, displayUniqueId), displayWidth, displayHeight, DENSITY_DEVICE_STABLE / (float) DENSITY_DEFAULT, - loadWaterfallInset(res)).second; + getWaterfallInsets(res, displayUniqueId)).second; } /** @@ -893,11 +999,11 @@ public final class DisplayCutout { * * @hide */ - public static Path pathFromResources(Resources res, int displayWidth, int displayHeight) { - return pathAndDisplayCutoutFromSpec( - res.getString(R.string.config_mainBuiltInDisplayCutout), null, + public static Path pathFromResources(Resources res, String displayUniqueId, int displayWidth, + int displayHeight) { + return pathAndDisplayCutoutFromSpec(getDisplayCutoutPath(res, displayUniqueId), null, displayWidth, displayHeight, DENSITY_DEVICE_STABLE / (float) DENSITY_DEFAULT, - loadWaterfallInset(res)).first; + getWaterfallInsets(res, displayUniqueId)).first; } /** diff --git a/core/java/android/view/IRecentsAnimationRunner.aidl b/core/java/android/view/IRecentsAnimationRunner.aidl index 811175566a90..c7fd38092ec7 100644 --- a/core/java/android/view/IRecentsAnimationRunner.aidl +++ b/core/java/android/view/IRecentsAnimationRunner.aidl @@ -35,15 +35,17 @@ oneway interface IRecentsAnimationRunner { * wallpaper not drawing in time, or the handler not finishing the animation within a predefined * amount of time. * - * @param taskSnapshot If the snapshot is null, the animation will be cancelled and the leash - * will be inactive immediately. Otherwise, the contents of the task will be - * replaced with {@param taskSnapshot}, such that the runner's leash is - * still active. As soon as the runner doesn't need the leash anymore, it - * must call {@link IRecentsAnimationController#cleanupScreenshot). + * @param taskIds Indicates tasks with cancelling snapshot. + * @param taskSnapshots If the snapshots is null, the animation will be cancelled and the leash + * will be inactive immediately. Otherwise, the contents of the tasks will + * be replaced with {@param taskSnapshots}, such that the runner's leash is + * still active. As soon as the runner doesn't need the leash anymore, it + * must call {@link IRecentsAnimationController#cleanupScreenshot). * * @see {@link RecentsAnimationController#cleanupScreenshot} */ - void onAnimationCanceled(in @nullable TaskSnapshot taskSnapshot) = 1; + void onAnimationCanceled(in @nullable int[] taskIds, + in @nullable TaskSnapshot[] taskSnapshots) = 1; /** * Called when the system is ready for the handler to start animating all the visible tasks. @@ -61,5 +63,5 @@ oneway interface IRecentsAnimationRunner { * Called when the task of an activity that has been started while the recents animation * was running becomes ready for control. */ - void onTaskAppeared(in RemoteAnimationTarget app) = 3; + void onTasksAppeared(in RemoteAnimationTarget[] app) = 3; } diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl index 9000fd00e851..b64d25a5b72c 100644 --- a/core/java/android/view/IWindowManager.aidl +++ b/core/java/android/view/IWindowManager.aidl @@ -53,12 +53,14 @@ import android.view.IWindowSessionCallback; import android.view.KeyEvent; import android.view.InputEvent; import android.view.InsetsState; +import android.view.InsetsVisibilities; import android.view.MagnificationSpec; import android.view.MotionEvent; import android.view.InputChannel; import android.view.InputDevice; import android.view.IInputFilter; import android.view.AppTransitionAnimationSpec; +import android.view.TaskTransitionSpec; import android.view.WindowContentFrameStats; import android.view.WindowManager; import android.view.SurfaceControl; @@ -344,6 +346,14 @@ interface IWindowManager */ Bitmap screenshotWallpaper(); + /** + * Mirrors the wallpaper for the given display. + * + * @param displayId ID of the display for the wallpaper. + * @return A SurfaceControl for the parent of the mirrored wallpaper. + */ + SurfaceControl mirrorWallpaperSurface(int displayId); + /** * Registers a wallpaper visibility listener. * @return Current visibility. @@ -721,14 +731,15 @@ interface IWindowManager int displayId, in IDisplayWindowInsetsController displayWindowInsetsController); /** - * Called when a remote process modifies insets on a display window container. + * Called when a remote process updates the requested visibilities of insets on a display window + * container. */ - void modifyDisplayWindowInsets(int displayId, in InsetsState state); + void updateDisplayWindowRequestedVisibilities(int displayId, in InsetsVisibilities vis); /** * Called to get the expected window insets. * - * @return {@code true} if system bars are always comsumed. + * @return {@code true} if system bars are always consumed. */ boolean getWindowInsets(in WindowManager.LayoutParams attrs, int displayId, out InsetsState outInsetsState); @@ -884,4 +895,24 @@ interface IWindowManager void unregisterCrossWindowBlurEnabledListener(ICrossWindowBlurEnabledListener listener); boolean isTaskSnapshotSupported(); + + /** + * Returns the preferred display ID to show software keyboard. + * + * @see android.window.WindowProviderService#getLaunchedDisplayId + */ + int getImeDisplayId(); + + /** + * Customized the task transition animation with a task transition spec. + * + * @param spec the spec that will be used to customize the task animations + */ + void setTaskTransitionSpec(in TaskTransitionSpec spec); + + /** + * Clears any task transition spec that has been previously set and + * reverts to using the default task transition with no spec changes. + */ + void clearTaskTransitionSpec(); } diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl index 7bad5cbfbdc3..9da50889e43f 100644 --- a/core/java/android/view/IWindowSession.aidl +++ b/core/java/android/view/IWindowSession.aidl @@ -32,6 +32,7 @@ import android.view.MotionEvent; import android.view.WindowManager; import android.view.InsetsSourceControl; import android.view.InsetsState; +import android.view.InsetsVisibilities; import android.view.Surface; import android.view.SurfaceControl; import android.view.SurfaceControl.Transaction; @@ -46,12 +47,12 @@ import java.util.List; */ interface IWindowSession { int addToDisplay(IWindow window, in WindowManager.LayoutParams attrs, - in int viewVisibility, in int layerStackId, in InsetsState requestedVisibility, + in int viewVisibility, in int layerStackId, in InsetsVisibilities requestedVisibilities, out InputChannel outInputChannel, out InsetsState insetsState, out InsetsSourceControl[] activeControls); int addToDisplayAsUser(IWindow window, in WindowManager.LayoutParams attrs, in int viewVisibility, in int layerStackId, in int userId, - in InsetsState requestedVisibility, out InputChannel outInputChannel, + in InsetsVisibilities requestedVisibilities, out InputChannel outInputChannel, out InsetsState insetsState, out InsetsSourceControl[] activeControls); int addToDisplayWithoutInputChannel(IWindow window, in WindowManager.LayoutParams attrs, in int viewVisibility, in int layerStackId, out InsetsState insetsState); @@ -173,6 +174,11 @@ interface IWindowSession { IBinder performDrag(IWindow window, int flags, in SurfaceControl surface, int touchSource, float touchX, float touchY, float thumbCenterX, float thumbCenterY, in ClipData data); + /** + * Drops the content of the current drag operation for accessibility + */ + boolean dropForAccessibility(IWindow window, int x, int y); + /** * Report the result of a drop action targeted to the given window. * consumed is 'true' when the drop was accepted by a valid recipient, @@ -285,10 +291,9 @@ interface IWindowSession { oneway void updateTapExcludeRegion(IWindow window, in Region region); /** - * Called when the client has changed the local insets state, and now the server should reflect - * that new state. + * Updates the requested visibilities of insets. */ - oneway void insetsModified(IWindow window, in InsetsState state); + oneway void updateRequestedVisibilities(IWindow window, in InsetsVisibilities visibilities); /** * Called when the system gesture exclusion has changed. diff --git a/core/java/android/view/ImeInsetsSourceConsumer.java b/core/java/android/view/ImeInsetsSourceConsumer.java index 06861046f2c7..d609fb8eb234 100644 --- a/core/java/android/view/ImeInsetsSourceConsumer.java +++ b/core/java/android/view/ImeInsetsSourceConsumer.java @@ -124,6 +124,11 @@ public final class ImeInsetsSourceConsumer extends InsetsSourceConsumer { public void setControl(@Nullable InsetsSourceControl control, int[] showTypes, int[] hideTypes) { super.setControl(control, showTypes, hideTypes); + // TODO(b/204524304): clean-up how to deal with the timing issues of hiding IME: + // 1) Already requested show IME, in the meantime of WM callback the control but got null + // control when relayout comes first + // 2) Make sure no regression on some implicit request IME visibility calls (e.g. + // toggleSoftInput) if (control == null && !mIsRequestedVisibleAwaitingControl) { hide(); removeSurface(); diff --git a/core/java/android/view/InputWindowHandle.java b/core/java/android/view/InputWindowHandle.java index 5a34a92a4b1a..139bff4b0118 100644 --- a/core/java/android/view/InputWindowHandle.java +++ b/core/java/android/view/InputWindowHandle.java @@ -19,9 +19,10 @@ package android.view; import static android.view.Display.INVALID_DISPLAY; import android.annotation.Nullable; +import android.graphics.Matrix; import android.graphics.Region; +import android.gui.TouchOcclusionMode; import android.os.IBinder; -import android.os.TouchOcclusionMode; import java.lang.ref.WeakReference; @@ -43,6 +44,17 @@ public final class InputWindowHandle { // channel and the server input channel will both contain this token. public IBinder token; + /** + * The {@link IWindow} handle if InputWindowHandle is associated with a window, null otherwise. + */ + @Nullable + private IBinder windowToken; + /** + * Used to cache IWindow from the windowToken so we don't need to convert every time getWindow + * is called. + */ + private IWindow window; + // The window name. public String name; @@ -122,6 +134,12 @@ public final class InputWindowHandle { */ public boolean replaceTouchableRegionWithCrop; + /** + * The transform that should be applied to the Window to get it from screen coordinates to + * window coordinates + */ + public Matrix transform; + private native void nativeDispose(); public InputWindowHandle(InputApplicationHandle inputApplicationHandle, int displayId) { @@ -136,6 +154,9 @@ public final class InputWindowHandle { .append(frameRight).append(",").append(frameBottom).append("]") .append(", touchableRegion=").append(touchableRegion) .append(", visible=").append(visible) + .append(", scaleFactor=").append(scaleFactor) + .append(", transform=").append(transform) + .append(", windowToken=").append(windowToken) .toString(); } @@ -167,4 +188,17 @@ public final class InputWindowHandle { public void setTouchableRegionCrop(@Nullable SurfaceControl bounds) { touchableRegionSurfaceControl = new WeakReference<>(bounds); } + + public void setWindowToken(IWindow iwindow) { + windowToken = iwindow.asBinder(); + window = iwindow; + } + + public IWindow getWindow() { + if (window != null) { + return window; + } + window = IWindow.Stub.asInterface(windowToken); + return window; + } } diff --git a/core/java/android/view/InsetsAnimationControlCallbacks.java b/core/java/android/view/InsetsAnimationControlCallbacks.java index 3431c3ecc310..04bb6091672b 100644 --- a/core/java/android/view/InsetsAnimationControlCallbacks.java +++ b/core/java/android/view/InsetsAnimationControlCallbacks.java @@ -20,7 +20,8 @@ import android.view.WindowInsets.Type.InsetsType; import android.view.WindowInsetsAnimation.Bounds; /** - * Provide an interface to let InsetsAnimationControlImpl call back into its owner. + * Provide an interface to let InsetsAnimationControlImpl and InsetsResizeAnimationRunner call back + * into its owner. * @hide */ public interface InsetsAnimationControlCallbacks { @@ -34,10 +35,9 @@ public interface InsetsAnimationControlCallbacks { *

    • Dispatch {@link WindowInsetsAnimationControlListener#onReady}
    • *
    */ - void startAnimation(InsetsAnimationControlImpl controller, - WindowInsetsAnimationControlListener listener, int types, - WindowInsetsAnimation animation, - Bounds bounds); + + void startAnimation(T runner, WindowInsetsAnimationControlListener listener, int types, + WindowInsetsAnimation animation, Bounds bounds); /** * Schedule the apply by posting the animation callback. diff --git a/core/java/android/view/InsetsAnimationControlImpl.java b/core/java/android/view/InsetsAnimationControlImpl.java index 17b3020001d4..805727c871b2 100644 --- a/core/java/android/view/InsetsAnimationControlImpl.java +++ b/core/java/android/view/InsetsAnimationControlImpl.java @@ -69,7 +69,7 @@ import java.util.Objects; * @hide */ @VisibleForTesting -public class InsetsAnimationControlImpl implements WindowInsetsAnimationController, +public class InsetsAnimationControlImpl implements InternalInsetsAnimationController, InsetsAnimationControlRunner { private static final String TAG = "InsetsAnimationCtrlImpl"; @@ -105,7 +105,7 @@ public class InsetsAnimationControlImpl implements WindowInsetsAnimationControll private float mCurrentAlpha = 1.0f; private float mPendingAlpha = 1.0f; @VisibleForTesting(visibility = PACKAGE) - public boolean mReadyDispatched; + private boolean mReadyDispatched; private Boolean mPerceptible; @VisibleForTesting @@ -169,6 +169,11 @@ public class InsetsAnimationControlImpl implements WindowInsetsAnimationControll return mHasZeroInsetsIme; } + @Override + public void setReadyDispatched(boolean dispatched) { + mReadyDispatched = dispatched; + } + @Override public Insets getHiddenStateInsets() { return mHiddenInsets; @@ -279,8 +284,8 @@ public class InsetsAnimationControlImpl implements WindowInsetsAnimationControll mShownOnFinish, mCurrentAlpha, mCurrentInsets)); mController.notifyFinished(this, mShownOnFinish); releaseLeashes(); + if (DEBUG) Log.d(TAG, "Animation finished abruptly."); } - if (DEBUG) Log.d(TAG, "Animation finished abruptly."); return mFinished; } diff --git a/core/java/android/view/InsetsAnimationThreadControlRunner.java b/core/java/android/view/InsetsAnimationThreadControlRunner.java index 691e638f3669..fc97541bd34d 100644 --- a/core/java/android/view/InsetsAnimationThreadControlRunner.java +++ b/core/java/android/view/InsetsAnimationThreadControlRunner.java @@ -54,8 +54,8 @@ public class InsetsAnimationThreadControlRunner implements InsetsAnimationContro @Override @UiThread - public void startAnimation(InsetsAnimationControlImpl controller, - WindowInsetsAnimationControlListener listener, int types, + public + void startAnimation(T runner, WindowInsetsAnimationControlListener listener, int types, WindowInsetsAnimation animation, Bounds bounds) { // Animation will be started in constructor already. } diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java index 6f915c9182d2..9bf71ec80998 100644 --- a/core/java/android/view/InsetsController.java +++ b/core/java/android/view/InsetsController.java @@ -107,9 +107,12 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation boolean hasControl); /** - * Called when insets have been modified by the client and should be reported back to WM. + * Called when the requested visibilities of insets have been modified by the client. + * The visibilities should be reported back to WM. + * + * @param visibilities A collection of the requested visibilities. */ - void onInsetsModified(InsetsState insetsState); + void updateRequestedVisibilities(InsetsVisibilities visibilities); /** * @return Whether the host has any callbacks it wants to synchronize the animations with. @@ -202,6 +205,9 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation private static final int ANIMATION_DURATION_FADE_IN_MS = 500; private static final int ANIMATION_DURATION_FADE_OUT_MS = 1500; + /** Visible for WindowManagerWrapper */ + public static final int ANIMATION_DURATION_RESIZE = 300; + private static final int ANIMATION_DELAY_DIM_MS = 500; private static final int ANIMATION_DURATION_SYNC_IME_MS = 285; @@ -232,6 +238,9 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation private static final Interpolator FAST_OUT_LINEAR_IN_INTERPOLATOR = new PathInterpolator(0.4f, 0f, 1f, 1f); + /** Visible for WindowManagerWrapper */ + public static final Interpolator RESIZE_INTERPOLATOR = new LinearInterpolator(); + /** The amount IME will move up/down when animating in floating mode. */ private static final int FLOATING_IME_BOTTOM_INSET_DP = -80; @@ -285,9 +294,13 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation @VisibleForTesting public static final int ANIMATION_TYPE_USER = 2; + /** Running animation will resize insets */ + @VisibleForTesting + public static final int ANIMATION_TYPE_RESIZE = 3; + @Retention(RetentionPolicy.SOURCE) @IntDef(value = {ANIMATION_TYPE_NONE, ANIMATION_TYPE_SHOW, ANIMATION_TYPE_HIDE, - ANIMATION_TYPE_USER}) + ANIMATION_TYPE_USER, ANIMATION_TYPE_RESIZE}) @interface AnimationType { } @@ -317,7 +330,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation private final boolean mDisable; private final int mFloatingImeBottomInset; - private ThreadLocal mSfAnimationHandlerThreadLocal = + private final ThreadLocal mSfAnimationHandlerThreadLocal = new ThreadLocal() { @Override protected AnimationHandler initialValue() { @@ -536,10 +549,8 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation /** The state dispatched from server */ private final InsetsState mLastDispatchedState = new InsetsState(); - // TODO: Use other class to represent the requested visibility of each type, because the - // display frame and the frame in each source are not used. /** The requested visibilities sent to server */ - private final InsetsState mRequestedState = new InsetsState(); + private final InsetsVisibilities mRequestedVisibilities = new InsetsVisibilities(); private final Rect mFrame = new Rect(); private final BiFunction mConsumerCreator; @@ -549,7 +560,6 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation private final SparseArray mTmpControlArray = new SparseArray<>(); private final ArrayList mRunningAnimations = new ArrayList<>(); - private final ArrayList mTmpFinishedControls = new ArrayList<>(); private final ArraySet mRequestedVisibilityChanged = new ArraySet<>(); private WindowInsets mLastInsets; @@ -569,7 +579,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation private int mCaptionInsetsHeight = 0; private boolean mAnimationsDisabled; - private Runnable mPendingControlTimeout = this::abortPendingImeControlRequest; + private final Runnable mPendingControlTimeout = this::abortPendingImeControlRequest; private final ArrayList mControllableInsetsChangedListeners = new ArrayList<>(); @@ -579,7 +589,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation /** Set of inset types which cannot be controlled by the user animation */ private @InsetsType int mDisabledUserAnimationInsetsTypes; - private Runnable mInvokeControllableInsetsChangedListeners = + private final Runnable mInvokeControllableInsetsChangedListeners = this::invokeControllableInsetsChangedListeners; public InsetsController(Host host) { @@ -607,23 +617,23 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation } final List runningAnimations = new ArrayList<>(); + final List finishedAnimations = new ArrayList<>(); final InsetsState state = new InsetsState(mState, true /* copySources */); for (int i = mRunningAnimations.size() - 1; i >= 0; i--) { RunningAnimation runningAnimation = mRunningAnimations.get(i); if (DEBUG) Log.d(TAG, "Running animation type: " + runningAnimation.type); - InsetsAnimationControlRunner runner = runningAnimation.runner; - if (runner instanceof InsetsAnimationControlImpl) { - InsetsAnimationControlImpl control = (InsetsAnimationControlImpl) runner; + final InsetsAnimationControlRunner runner = runningAnimation.runner; + if (runner instanceof WindowInsetsAnimationController) { // Keep track of running animation to be dispatched. Aggregate it here such that // if it gets finished within applyChangeInsets we still dispatch it to // onProgress. if (runningAnimation.startDispatched) { - runningAnimations.add(control.getAnimation()); + runningAnimations.add(runner.getAnimation()); } - if (control.applyChangeInsets(state)) { - mTmpFinishedControls.add(control); + if (((InternalInsetsAnimationController) runner).applyChangeInsets(state)) { + finishedAnimations.add(runner.getAnimation()); } } } @@ -641,10 +651,9 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation } } - for (int i = mTmpFinishedControls.size() - 1; i >= 0; i--) { - dispatchAnimationEnd(mTmpFinishedControls.get(i).getAnimation()); + for (int i = finishedAnimations.size() - 1; i >= 0; i--) { + dispatchAnimationEnd(finishedAnimations.get(i)); } - mTmpFinishedControls.clear(); }; } @@ -690,15 +699,13 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation true /* excludeInvisibleIme */)) { if (DEBUG) Log.d(TAG, "onStateChanged, notifyInsetsChanged"); mHost.notifyInsetsChanged(); + startResizingAnimationIfNeeded(lastState); } return true; } private void updateState(InsetsState newState) { - mState.setDisplayFrame(newState.getDisplayFrame()); - mState.setDisplayCutout(newState.getDisplayCutout()); - mState.setRoundedCorners(newState.getRoundedCorners()); - mState.setPrivacyIndicatorBounds(newState.getPrivacyIndicatorBounds()); + mState.set(newState, 0 /* types */); @InsetsType int disabledUserAnimationTypes = 0; @InsetsType int[] cancelledUserAnimationTypes = {0}; for (@InternalInsetsType int type = 0; type < InsetsState.SIZE; type++) { @@ -763,6 +770,39 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation return false; } + private void startResizingAnimationIfNeeded(InsetsState fromState) { + if (!fromState.getDisplayFrame().equals(mState.getDisplayFrame())) { + return; + } + @InsetsType int types = 0; + InsetsState toState = null; + final ArraySet internalTypes = InsetsState.toInternalType(Type.systemBars()); + for (int i = internalTypes.size() - 1; i >= 0; i--) { + final @InternalInsetsType int type = internalTypes.valueAt(i); + final InsetsSource fromSource = fromState.peekSource(type); + final InsetsSource toSource = mState.peekSource(type); + if (fromSource != null && toSource != null + && fromSource.isVisible() && toSource.isVisible() + && !fromSource.getFrame().equals(toSource.getFrame()) + && (Rect.intersects(mFrame, fromSource.getFrame()) + || Rect.intersects(mFrame, toSource.getFrame()))) { + types |= InsetsState.toPublicType(toSource.getType()); + if (toState == null) { + toState = new InsetsState(); + } + toState.addSource(new InsetsSource(toSource)); + } + } + if (types == 0) { + return; + } + cancelExistingControllers(types); + final InsetsAnimationControlRunner runner = new InsetsResizeAnimationRunner( + mFrame, fromState, toState, RESIZE_INTERPOLATOR, ANIMATION_DURATION_RESIZE, types, + this); + mRunningAnimations.add(new RunningAnimation(runner, runner.getAnimationType())); + } + /** * @see InsetsState#calculateInsets */ @@ -784,7 +824,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation /** * @see InsetsState#calculateVisibleInsets(Rect, int) */ - public Rect calculateVisibleInsets(@SoftInputModeFlags int softInputMode) { + public Insets calculateVisibleInsets(@SoftInputModeFlags int softInputMode) { return mState.calculateVisibleInsets(mFrame, softInputMode); } @@ -801,7 +841,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation } } - boolean requestedStateStale = false; + boolean requestedVisibilityStale = false; final int[] showTypes = new int[1]; final int[] hideTypes = new int[1]; @@ -822,20 +862,20 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation final InsetsSourceConsumer consumer = getSourceConsumer(type); consumer.setControl(control, showTypes, hideTypes); - if (!requestedStateStale) { + if (!requestedVisibilityStale) { final boolean requestedVisible = consumer.isRequestedVisible(); // We might have changed our requested visibilities while we don't have the control, // so we need to update our requested state once we have control. Otherwise, our // requested state at the server side might be incorrect. final boolean requestedVisibilityChanged = - requestedVisible != mRequestedState.getSourceOrDefaultVisibility(type); + requestedVisible != mRequestedVisibilities.getVisibility(type); // The IME client visibility will be reset by insets source provider while updating // control, so if IME is requested visible, we need to send the request to server. final boolean imeRequestedVisible = type == ITYPE_IME && requestedVisible; - requestedStateStale = requestedVisibilityChanged || imeRequestedVisible; + requestedVisibilityStale = requestedVisibilityChanged || imeRequestedVisible; } } @@ -861,7 +901,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation } // InsetsSourceConsumer#setControl might change the requested visibility. - updateRequestedVisibility(); + updateRequestedVisibilities(); } @Override @@ -1015,7 +1055,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation if (types == 0) { // nothing to animate. listener.onCancelled(null); - updateRequestedVisibility(); + updateRequestedVisibilities(); if (DEBUG) Log.d(TAG, "no types to animate in controlAnimationUnchecked"); return; } @@ -1051,7 +1091,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation } }); } - updateRequestedVisibility(); + updateRequestedVisibilities(); Trace.asyncTraceEnd(TRACE_TAG_VIEW, "IC.showRequestFromApi", 0); return; } @@ -1059,7 +1099,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation if (typesReady == 0) { if (DEBUG) Log.d(TAG, "No types ready. onCancelled()"); listener.onCancelled(null); - updateRequestedVisibility(); + updateRequestedVisibilities(); return; } @@ -1091,7 +1131,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation } else { hideDirectly(types, false /* animationFinished */, animationType, fromIme); } - updateRequestedVisibility(); + updateRequestedVisibilities(); } /** @@ -1226,6 +1266,11 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation public void notifyFinished(InsetsAnimationControlRunner runner, boolean shown) { cancelAnimation(runner, false /* invokeCallback */); if (DEBUG) Log.d(TAG, "notifyFinished. shown: " + shown); + if (runner.getAnimationType() == ANIMATION_TYPE_RESIZE) { + // The resize animation doesn't show or hide the insets. We shouldn't change the + // requested visibility. + return; + } if (shown) { showDirectly(runner.getTypes(), true /* fromIme */); } else { @@ -1348,7 +1393,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation /** * Sends the requested visibilities to window manager if any of them is changed. */ - private void updateRequestedVisibility() { + private void updateRequestedVisibilities() { boolean changed = false; for (int i = mRequestedVisibilityChanged.size() - 1; i >= 0; i--) { final InsetsSourceConsumer consumer = mRequestedVisibilityChanged.valueAt(i); @@ -1357,8 +1402,8 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation continue; } final boolean requestedVisible = consumer.isRequestedVisible(); - if (requestedVisible != mRequestedState.getSourceOrDefaultVisibility(type)) { - mRequestedState.getSource(type).setVisible(requestedVisible); + if (mRequestedVisibilities.getVisibility(type) != requestedVisible) { + mRequestedVisibilities.setVisibility(type, requestedVisible); changed = true; } } @@ -1366,11 +1411,11 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation if (!changed) { return; } - mHost.onInsetsModified(mRequestedState); + mHost.updateRequestedVisibilities(mRequestedVisibilities); } - InsetsState getRequestedVisibility() { - return mRequestedState; + InsetsVisibilities getRequestedVisibilities() { + return mRequestedVisibilities; } @VisibleForTesting @@ -1425,7 +1470,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation for (int i = internalTypes.size() - 1; i >= 0; i--) { getSourceConsumer(internalTypes.valueAt(i)).hide(animationFinished, animationType); } - updateRequestedVisibility(); + updateRequestedVisibilities(); if (fromIme) { Trace.asyncTraceEnd(TRACE_TAG_VIEW, "IC.hideRequestFromIme", 0); @@ -1441,7 +1486,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation for (int i = internalTypes.size() - 1; i >= 0; i--) { getSourceConsumer(internalTypes.valueAt(i)).show(false /* fromIme */); } - updateRequestedVisibility(); + updateRequestedVisibilities(); if (fromIme) { Trace.asyncTraceEnd(TRACE_TAG_VIEW, "IC.showRequestFromIme", 0); @@ -1473,12 +1518,12 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation @VisibleForTesting @Override - public void startAnimation(InsetsAnimationControlImpl controller, - WindowInsetsAnimationControlListener listener, int types, + public + void startAnimation(T runner, WindowInsetsAnimationControlListener listener, int types, WindowInsetsAnimation animation, Bounds bounds) { mHost.dispatchWindowInsetsAnimationPrepare(animation); mHost.addOnPreDrawRunnable(() -> { - if (controller.isCancelled()) { + if (runner.isCancelled()) { if (WARN) Log.w(TAG, "startAnimation canceled before preDraw"); return; } @@ -1486,15 +1531,15 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation "InsetsAnimation: " + WindowInsets.Type.toString(types), types); for (int i = mRunningAnimations.size() - 1; i >= 0; i--) { RunningAnimation runningAnimation = mRunningAnimations.get(i); - if (runningAnimation.runner == controller) { + if (runningAnimation.runner == runner) { runningAnimation.startDispatched = true; } } Trace.asyncTraceEnd(TRACE_TAG_VIEW, "IC.pendingAnim", 0); mHost.dispatchWindowInsetsAnimationStart(animation, bounds); mStartingAnimation = true; - controller.mReadyDispatched = true; - listener.onReady(controller, types); + runner.setReadyDispatched(true); + listener.onReady(runner, types); mStartingAnimation = false; }); } diff --git a/core/java/android/view/InsetsResizeAnimationRunner.java b/core/java/android/view/InsetsResizeAnimationRunner.java new file mode 100644 index 000000000000..edcfc95fe4e4 --- /dev/null +++ b/core/java/android/view/InsetsResizeAnimationRunner.java @@ -0,0 +1,238 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 static android.view.InsetsAnimationControlImplProto.CURRENT_ALPHA; +import static android.view.InsetsAnimationControlImplProto.IS_CANCELLED; +import static android.view.InsetsAnimationControlImplProto.IS_FINISHED; +import static android.view.InsetsAnimationControlImplProto.PENDING_ALPHA; +import static android.view.InsetsAnimationControlImplProto.PENDING_FRACTION; +import static android.view.InsetsAnimationControlImplProto.PENDING_INSETS; +import static android.view.InsetsAnimationControlImplProto.SHOWN_ON_FINISH; +import static android.view.InsetsAnimationControlImplProto.TMP_MATRIX; +import static android.view.InsetsController.ANIMATION_TYPE_RESIZE; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.ValueAnimator; +import android.graphics.Insets; +import android.graphics.Rect; +import android.util.SparseArray; +import android.util.proto.ProtoOutputStream; +import android.view.InsetsState.InternalInsetsType; +import android.view.WindowInsets.Type.InsetsType; +import android.view.WindowInsetsAnimation.Bounds; +import android.view.animation.Interpolator; + +/** + * Runs a fake animation of resizing insets to produce insets animation callbacks. + * @hide + */ +public class InsetsResizeAnimationRunner implements InsetsAnimationControlRunner, + InternalInsetsAnimationController, WindowInsetsAnimationControlListener { + + private final InsetsState mFromState; + private final InsetsState mToState; + private final @InsetsType int mTypes; + private final WindowInsetsAnimation mAnimation; + private final InsetsAnimationControlCallbacks mController; + private ValueAnimator mAnimator; + private boolean mCancelled; + private boolean mFinished; + + public InsetsResizeAnimationRunner(Rect frame, InsetsState fromState, InsetsState toState, + Interpolator interpolator, long duration, @InsetsType int types, + InsetsAnimationControlCallbacks controller) { + mFromState = fromState; + mToState = toState; + mTypes = types; + mController = controller; + mAnimation = new WindowInsetsAnimation(types, interpolator, duration); + mAnimation.setAlpha(1f); + final Insets fromInsets = fromState.calculateInsets( + frame, types, false /* ignoreVisibility */); + final Insets toInsets = toState.calculateInsets( + frame, types, false /* ignoreVisibility */); + controller.startAnimation(this, this, types, mAnimation, + new Bounds(Insets.min(fromInsets, toInsets), Insets.max(fromInsets, toInsets))); + } + + @Override + public int getTypes() { + return mTypes; + } + + @Override + public int getControllingTypes() { + return mTypes; + } + + @Override + public WindowInsetsAnimation getAnimation() { + return mAnimation; + } + + @Override + public int getAnimationType() { + return ANIMATION_TYPE_RESIZE; + } + + @Override + public void cancel() { + if (mCancelled || mFinished) { + return; + } + mCancelled = true; + if (mAnimator != null) { + mAnimator.cancel(); + } + } + + @Override + public boolean isCancelled() { + return mCancelled; + } + + @Override + public void onReady(WindowInsetsAnimationController controller, int types) { + if (mCancelled) { + return; + } + mAnimator = ValueAnimator.ofFloat(0f, 1f); + mAnimator.setDuration(mAnimation.getDurationMillis()); + mAnimator.addUpdateListener(animation -> { + mAnimation.setFraction(animation.getAnimatedFraction()); + mController.scheduleApplyChangeInsets(InsetsResizeAnimationRunner.this); + }); + mAnimator.addListener(new AnimatorListenerAdapter() { + + @Override + public void onAnimationEnd(Animator animation) { + mFinished = true; + mController.scheduleApplyChangeInsets(InsetsResizeAnimationRunner.this); + } + }); + mAnimator.start(); + } + + @Override + public boolean applyChangeInsets(InsetsState outState) { + if (mCancelled) { + return false; + } + final float fraction = mAnimation.getInterpolatedFraction(); + for (@InternalInsetsType int type = 0; type < InsetsState.SIZE; type++) { + final InsetsSource fromSource = mFromState.peekSource(type); + final InsetsSource toSource = mToState.peekSource(type); + if (fromSource == null || toSource == null) { + continue; + } + final Rect fromFrame = fromSource.getFrame(); + final Rect toFrame = toSource.getFrame(); + final Rect frame = new Rect( + (int) (fromFrame.left + fraction * (toFrame.left - fromFrame.left)), + (int) (fromFrame.top + fraction * (toFrame.top - fromFrame.top)), + (int) (fromFrame.right + fraction * (toFrame.right - fromFrame.right)), + (int) (fromFrame.bottom + fraction * (toFrame.bottom - fromFrame.bottom))); + final InsetsSource source = new InsetsSource(type); + source.setFrame(frame); + source.setVisible(toSource.isVisible()); + outState.addSource(source); + } + if (mFinished) { + mController.notifyFinished(this, true /* shown */); + } + return mFinished; + } + + @Override + public void dumpDebug(ProtoOutputStream proto, long fieldId) { + final long token = proto.start(fieldId); + proto.write(IS_CANCELLED, mCancelled); + proto.write(IS_FINISHED, mFinished); + proto.write(TMP_MATRIX, "null"); + proto.write(PENDING_INSETS, "null"); + proto.write(PENDING_FRACTION, mAnimation.getInterpolatedFraction()); + proto.write(SHOWN_ON_FINISH, true); + proto.write(CURRENT_ALPHA, 1f); + proto.write(PENDING_ALPHA, 1f); + proto.end(token); + } + + @Override + public Insets getHiddenStateInsets() { + return Insets.NONE; + } + + @Override + public Insets getShownStateInsets() { + return Insets.NONE; + } + + @Override + public Insets getCurrentInsets() { + return Insets.NONE; + } + + @Override + public float getCurrentFraction() { + return 0; + } + + @Override + public float getCurrentAlpha() { + return 0; + } + + @Override + public void setInsetsAndAlpha(Insets insets, float alpha, float fraction) { + } + + @Override + public void finish(boolean shown) { + } + + @Override + public boolean isFinished() { + return false; + } + + @Override + public void notifyControlRevoked(int types) { + } + + @Override + public void updateSurfacePosition(SparseArray controls) { + } + + @Override + public boolean hasZeroInsetsIme() { + return false; + } + + @Override + public void setReadyDispatched(boolean dispatched) { + } + + @Override + public void onFinished(WindowInsetsAnimationController controller) { + } + + @Override + public void onCancelled(WindowInsetsAnimationController controller) { + } +} diff --git a/core/java/android/view/InsetsSourceControl.java b/core/java/android/view/InsetsSourceControl.java index 1506ee4c2c7a..9d98a3e4b0e1 100644 --- a/core/java/android/view/InsetsSourceControl.java +++ b/core/java/android/view/InsetsSourceControl.java @@ -185,6 +185,15 @@ public class InsetsSourceControl implements Parcelable { return result; } + @Override + public String toString() { + return "InsetsSourceControl: {" + + "type=" + InsetsState.typeToString(mType) + + ", mSurfacePosition=" + mSurfacePosition + + ", mInsetsHint=" + mInsetsHint + + "}"; + } + public void dump(String prefix, PrintWriter pw) { pw.print(prefix); pw.print("InsetsSourceControl type="); pw.print(InsetsState.typeToString(mType)); diff --git a/core/java/android/view/InsetsState.java b/core/java/android/view/InsetsState.java index 37101b757e66..75b69cb12d32 100644 --- a/core/java/android/view/InsetsState.java +++ b/core/java/android/view/InsetsState.java @@ -301,7 +301,7 @@ public class InsetsState implements Parcelable { return mPrivacyIndicatorBounds.inset(insetLeft, insetTop, insetRight, insetBottom); } - public Rect calculateInsets(Rect frame, @InsetsType int types, boolean ignoreVisibility) { + public Insets calculateInsets(Rect frame, @InsetsType int types, boolean ignoreVisibility) { Insets insets = Insets.NONE; for (int type = FIRST_TYPE; type <= LAST_TYPE; type++) { InsetsSource source = mSources[type]; @@ -314,10 +314,10 @@ public class InsetsState implements Parcelable { } insets = Insets.max(source.calculateInsets(frame, ignoreVisibility), insets); } - return insets.toRect(); + return insets; } - public Rect calculateVisibleInsets(Rect frame, @SoftInputModeFlags int softInputMode) { + public Insets calculateVisibleInsets(Rect frame, @SoftInputModeFlags int softInputMode) { Insets insets = Insets.NONE; for (int type = FIRST_TYPE; type <= LAST_TYPE; type++) { InsetsSource source = mSources[type]; @@ -332,7 +332,7 @@ public class InsetsState implements Parcelable { } insets = Insets.max(source.calculateVisibleInsets(frame), insets); } - return insets.toRect(); + return insets; } /** @@ -878,16 +878,5 @@ public class InsetsState implements Parcelable { + ", mSources= { " + joiner + " }"; } - - public @NonNull String toSourceVisibilityString() { - StringJoiner joiner = new StringJoiner(", "); - for (int i = 0; i < SIZE; i++) { - InsetsSource source = mSources[i]; - if (source != null) { - joiner.add(typeToString(i) + ": " + (source.isVisible() ? "visible" : "invisible")); - } - } - return joiner.toString(); - } } diff --git a/core/java/android/view/InsetsVisibilities.aidl b/core/java/android/view/InsetsVisibilities.aidl new file mode 100644 index 000000000000..bd573ea7bc35 --- /dev/null +++ b/core/java/android/view/InsetsVisibilities.aidl @@ -0,0 +1,19 @@ +/** + * Copyright (c) 2021, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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; + +parcelable InsetsVisibilities; diff --git a/core/java/android/view/InsetsVisibilities.java b/core/java/android/view/InsetsVisibilities.java new file mode 100644 index 000000000000..7d259fb91634 --- /dev/null +++ b/core/java/android/view/InsetsVisibilities.java @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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.NonNull; +import android.os.Parcel; +import android.os.Parcelable; + +import java.util.Arrays; +import java.util.StringJoiner; + +/** + * A collection of visibilities of insets. This is used for carrying the requested visibilities. + * @hide + */ +public class InsetsVisibilities implements Parcelable { + + private static final int UNSPECIFIED = 0; + private static final int VISIBLE = 1; + private static final int INVISIBLE = -1; + + private final int[] mVisibilities = new int[InsetsState.SIZE]; + + public InsetsVisibilities() { + } + + public InsetsVisibilities(InsetsVisibilities other) { + set(other); + } + + public InsetsVisibilities(Parcel in) { + in.readIntArray(mVisibilities); + } + + /** + * Copies from another {@link InsetsVisibilities}. + * + * @param other an instance of {@link InsetsVisibilities}. + */ + public void set(InsetsVisibilities other) { + System.arraycopy(other.mVisibilities, InsetsState.FIRST_TYPE, mVisibilities, + InsetsState.FIRST_TYPE, InsetsState.SIZE); + } + + /** + * Sets a visibility to a type. + * + * @param type The {@link @InsetsState.InternalInsetsType}. + * @param visible {@code true} represents visible; {@code false} represents invisible. + */ + public void setVisibility(@InsetsState.InternalInsetsType int type, boolean visible) { + mVisibilities[type] = visible ? VISIBLE : INVISIBLE; + } + + /** + * Returns the specified insets visibility of the type. If it has never been specified, + * this returns the default visibility. + * + * @param type The {@link @InsetsState.InternalInsetsType}. + * @return The specified visibility or the default one if it is not specified. + */ + public boolean getVisibility(@InsetsState.InternalInsetsType int type) { + final int visibility = mVisibilities[type]; + return visibility == UNSPECIFIED + ? InsetsState.getDefaultVisibility(type) + : visibility == VISIBLE; + } + + @Override + public String toString() { + StringJoiner joiner = new StringJoiner(", "); + for (int type = InsetsState.FIRST_TYPE; type <= InsetsState.LAST_TYPE; type++) { + final int visibility = mVisibilities[type]; + if (visibility != UNSPECIFIED) { + joiner.add(InsetsState.typeToString(type) + ": " + + (visibility == VISIBLE ? "visible" : "invisible")); + } + } + return joiner.toString(); + } + + @Override + public int hashCode() { + return Arrays.hashCode(mVisibilities); + } + + @Override + public boolean equals(Object other) { + if (!(other instanceof InsetsVisibilities)) { + return false; + } + return Arrays.equals(mVisibilities, ((InsetsVisibilities) other).mVisibilities); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeIntArray(mVisibilities); + } + + public void readFromParcel(@NonNull Parcel in) { + in.readIntArray(mVisibilities); + } + + public static final @NonNull Creator CREATOR = + new Creator() { + + public InsetsVisibilities createFromParcel(Parcel in) { + return new InsetsVisibilities(in); + } + + public InsetsVisibilities[] newArray(int size) { + return new InsetsVisibilities[size]; + } + }; +} diff --git a/core/java/android/view/InternalInsetsAnimationController.java b/core/java/android/view/InternalInsetsAnimationController.java new file mode 100644 index 000000000000..d7f3e20b80c5 --- /dev/null +++ b/core/java/android/view/InternalInsetsAnimationController.java @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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; + +/** + * An internal interface which provides methods that will be only used by the framework. + * @hide + */ +public interface InternalInsetsAnimationController extends WindowInsetsAnimationController { + + /** + * Flags whether {@link WindowInsetsAnimationControlListener#onReady( + * WindowInsetsAnimationController, int)} has been invoked. + * @hide + */ + void setReadyDispatched(boolean dispatched); + + /** + * Returns the {@link InsetsState} based on the current animation progress. + * + * @param outState the insets state which matches the current animation progress. + * @return {@code true} if the animation has been finished; {@code false} otherwise. + * @hide + */ + boolean applyChangeInsets(InsetsState outState); +} + diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java index 69ff64f3d6a5..80ffd40b564e 100644 --- a/core/java/android/view/MotionEvent.java +++ b/core/java/android/view/MotionEvent.java @@ -1860,7 +1860,7 @@ public final class MotionEvent extends InputEvent implements Parcelable { float x, float y, float pressure, float size, int metaState, float xPrecision, float yPrecision, int deviceId, int edgeFlags) { return obtain(downTime, eventTime, action, x, y, pressure, size, metaState, - xPrecision, yPrecision, deviceId, edgeFlags, InputDevice.SOURCE_UNKNOWN, + xPrecision, yPrecision, deviceId, edgeFlags, InputDevice.SOURCE_CLASS_POINTER, DEFAULT_DISPLAY); } @@ -4007,6 +4007,22 @@ public final class MotionEvent extends InputEvent implements Parcelable { */ public float orientation; + /** + * The movement of x position of a motion event. + * + * @see MotionEvent#AXIS_RELATIVE_X + * @hide + */ + public float relativeX; + + /** + * The movement of y position of a motion event. + * + * @see MotionEvent#AXIS_RELATIVE_Y + * @hide + */ + public float relativeY; + /** * Clears the contents of this object. * Resets all axes to zero. @@ -4023,6 +4039,8 @@ public final class MotionEvent extends InputEvent implements Parcelable { toolMajor = 0; toolMinor = 0; orientation = 0; + relativeX = 0; + relativeY = 0; } /** @@ -4053,6 +4071,8 @@ public final class MotionEvent extends InputEvent implements Parcelable { toolMajor = other.toolMajor; toolMinor = other.toolMinor; orientation = other.orientation; + relativeX = other.relativeX; + relativeY = other.relativeY; } /** @@ -4084,6 +4104,10 @@ public final class MotionEvent extends InputEvent implements Parcelable { return toolMinor; case AXIS_ORIENTATION: return orientation; + case AXIS_RELATIVE_X: + return relativeX; + case AXIS_RELATIVE_Y: + return relativeY; default: { if (axis < 0 || axis > 63) { throw new IllegalArgumentException("Axis out of range."); @@ -4137,6 +4161,12 @@ public final class MotionEvent extends InputEvent implements Parcelable { case AXIS_ORIENTATION: orientation = value; break; + case AXIS_RELATIVE_X: + relativeX = value; + break; + case AXIS_RELATIVE_Y: + relativeY = value; + break; default: { if (axis < 0 || axis > 63) { throw new IllegalArgumentException("Axis out of range."); diff --git a/core/java/android/view/RemoteAnimationAdapter.java b/core/java/android/view/RemoteAnimationAdapter.java index a78036fba094..e1cc60491f72 100644 --- a/core/java/android/view/RemoteAnimationAdapter.java +++ b/core/java/android/view/RemoteAnimationAdapter.java @@ -17,6 +17,7 @@ package android.view; import android.app.ActivityOptions; +import android.app.IApplicationThread; import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; import android.os.Parcel; @@ -58,6 +59,9 @@ public class RemoteAnimationAdapter implements Parcelable { private int mCallingPid; private int mCallingUid; + /** @see #getCallingApplication */ + private IApplicationThread mCallingApplication; + /** * @param runner The interface that gets notified when we actually need to start the animation. * @param duration The duration of the animation. @@ -81,11 +85,19 @@ public class RemoteAnimationAdapter implements Parcelable { this(runner, duration, statusBarTransitionDelay, false /* changeNeedsSnapshot */); } + @UnsupportedAppUsage + public RemoteAnimationAdapter(IRemoteAnimationRunner runner, long duration, + long statusBarTransitionDelay, IApplicationThread callingApplication) { + this(runner, duration, statusBarTransitionDelay, false /* changeNeedsSnapshot */); + mCallingApplication = callingApplication; + } + public RemoteAnimationAdapter(Parcel in) { mRunner = IRemoteAnimationRunner.Stub.asInterface(in.readStrongBinder()); mDuration = in.readLong(); mStatusBarTransitionDelay = in.readLong(); mChangeNeedsSnapshot = in.readBoolean(); + mCallingApplication = IApplicationThread.Stub.asInterface(in.readStrongBinder()); } public IRemoteAnimationRunner getRunner() { @@ -126,6 +138,15 @@ public class RemoteAnimationAdapter implements Parcelable { return mCallingUid; } + /** + * Gets the ApplicationThread that will run the animation. Instead it is intended to pass the + * calling information among client processes (eg. shell + launcher) through one-way binder + * calls (where binder itself doesn't track calling information). + */ + public IApplicationThread getCallingApplication() { + return mCallingApplication; + } + @Override public int describeContents() { return 0; @@ -137,6 +158,7 @@ public class RemoteAnimationAdapter implements Parcelable { dest.writeLong(mDuration); dest.writeLong(mStatusBarTransitionDelay); dest.writeBoolean(mChangeNeedsSnapshot); + dest.writeStrongInterface(mCallingApplication); } public static final @android.annotation.NonNull Creator CREATOR diff --git a/core/java/android/view/RemoteAnimationTarget.java b/core/java/android/view/RemoteAnimationTarget.java index cdc099b8e2ea..2dac81c66d2a 100644 --- a/core/java/android/view/RemoteAnimationTarget.java +++ b/core/java/android/view/RemoteAnimationTarget.java @@ -129,7 +129,11 @@ public class RemoteAnimationTarget implements Parcelable { * The index of the element in the tree in prefix order. This should be used for z-layering * to preserve original z-layer order in the hierarchy tree assuming no "boosting" needs to * happen. + * @deprecated WindowManager may set a z-order different from the prefix order, and has set the + * correct layer for the animation leash already, so this should not be used for + * layer any more. */ + @Deprecated @UnsupportedAppUsage public final int prefixOrderIndex; @@ -196,20 +200,36 @@ public class RemoteAnimationTarget implements Parcelable { */ public ActivityManager.RunningTaskInfo taskInfo; + /** + * {@code true} if picture-in-picture permission is granted in {@link android.app.AppOpsManager} + */ + @UnsupportedAppUsage + public boolean allowEnterPip; + /** * The {@link android.view.WindowManager.LayoutParams.WindowType} of this window. It's only used * for non-app window. */ public final @WindowManager.LayoutParams.WindowType int windowType; + /** + * {@code true} if its parent is also a {@link RemoteAnimationTarget} in the same transition. + * + * For example, when a TaskFragment is resizing while one of its children is open/close, both + * windows will be animation targets. This value will be {@code true} for the child, so that + * the handler can choose to handle it differently. + */ + public boolean hasAnimatingParent; + public RemoteAnimationTarget(int taskId, int mode, SurfaceControl leash, boolean isTranslucent, Rect clipRect, Rect contentInsets, int prefixOrderIndex, Point position, Rect localBounds, Rect screenSpaceBounds, WindowConfiguration windowConfig, boolean isNotInRecents, - SurfaceControl startLeash, Rect startBounds, ActivityManager.RunningTaskInfo taskInfo) { + SurfaceControl startLeash, Rect startBounds, ActivityManager.RunningTaskInfo taskInfo, + boolean allowEnterPip) { this(taskId, mode, leash, isTranslucent, clipRect, contentInsets, prefixOrderIndex, position, localBounds, screenSpaceBounds, windowConfig, isNotInRecents, startLeash, - startBounds, taskInfo, INVALID_WINDOW_TYPE); + startBounds, taskInfo, allowEnterPip, INVALID_WINDOW_TYPE); } public RemoteAnimationTarget(int taskId, int mode, SurfaceControl leash, boolean isTranslucent, @@ -217,7 +237,7 @@ public class RemoteAnimationTarget implements Parcelable { Rect localBounds, Rect screenSpaceBounds, WindowConfiguration windowConfig, boolean isNotInRecents, SurfaceControl startLeash, Rect startBounds, - ActivityManager.RunningTaskInfo taskInfo, + ActivityManager.RunningTaskInfo taskInfo, boolean allowEnterPip, @WindowManager.LayoutParams.WindowType int windowType) { this.mode = mode; this.taskId = taskId; @@ -226,7 +246,7 @@ public class RemoteAnimationTarget implements Parcelable { this.clipRect = new Rect(clipRect); this.contentInsets = new Rect(contentInsets); this.prefixOrderIndex = prefixOrderIndex; - this.position = new Point(position); + this.position = position == null ? new Point() : new Point(position); this.localBounds = new Rect(localBounds); this.sourceContainerBounds = new Rect(screenSpaceBounds); this.screenSpaceBounds = new Rect(screenSpaceBounds); @@ -235,6 +255,7 @@ public class RemoteAnimationTarget implements Parcelable { this.startLeash = startLeash; this.startBounds = startBounds == null ? null : new Rect(startBounds); this.taskInfo = taskInfo; + this.allowEnterPip = allowEnterPip; this.windowType = windowType; } @@ -255,7 +276,9 @@ public class RemoteAnimationTarget implements Parcelable { startLeash = in.readTypedObject(SurfaceControl.CREATOR); startBounds = in.readTypedObject(Rect.CREATOR); taskInfo = in.readTypedObject(ActivityManager.RunningTaskInfo.CREATOR); + allowEnterPip = in.readBoolean(); windowType = in.readInt(); + hasAnimatingParent = in.readBoolean(); } @Override @@ -281,7 +304,9 @@ public class RemoteAnimationTarget implements Parcelable { dest.writeTypedObject(startLeash, 0 /* flags */); dest.writeTypedObject(startBounds, 0 /* flags */); dest.writeTypedObject(taskInfo, 0 /* flags */); + dest.writeBoolean(allowEnterPip); dest.writeInt(windowType); + dest.writeBoolean(hasAnimatingParent); } public void dump(PrintWriter pw, String prefix) { @@ -299,7 +324,9 @@ public class RemoteAnimationTarget implements Parcelable { pw.print(prefix); pw.print("windowConfiguration="); pw.println(windowConfiguration); pw.print(prefix); pw.print("leash="); pw.println(leash); pw.print(prefix); pw.print("taskInfo="); pw.println(taskInfo); + pw.print(prefix); pw.print("allowEnterPip="); pw.println(allowEnterPip); pw.print(prefix); pw.print("windowType="); pw.print(windowType); + pw.print(prefix); pw.print("hasAnimatingParent="); pw.print(hasAnimatingParent); } public void dumpDebug(ProtoOutputStream proto, long fieldId) { diff --git a/core/java/android/view/RoundedCorners.java b/core/java/android/view/RoundedCorners.java index 623d9692ac80..6079d8e3f118 100644 --- a/core/java/android/view/RoundedCorners.java +++ b/core/java/android/view/RoundedCorners.java @@ -27,9 +27,11 @@ import static android.view.Surface.ROTATION_90; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.res.Resources; +import android.content.res.TypedArray; import android.graphics.Point; import android.os.Parcel; import android.os.Parcelable; +import android.util.DisplayUtils; import android.util.Pair; import android.view.RoundedCorner.Position; @@ -94,8 +96,8 @@ public class RoundedCorners implements Parcelable { * @android:dimen/rounded_corner_radius_top and @android:dimen/rounded_corner_radius_bottom */ public static RoundedCorners fromResources( - Resources res, int displayWidth, int displayHeight) { - return fromRadii(loadRoundedCornerRadii(res), displayWidth, displayHeight); + Resources res, String displayUniqueId, int displayWidth, int displayHeight) { + return fromRadii(loadRoundedCornerRadii(res, displayUniqueId), displayWidth, displayHeight); } /** @@ -140,14 +142,16 @@ public class RoundedCorners implements Parcelable { * Loads the rounded corner radii from resources. * * @param res + * @param displayUniqueId the display unique id. * @return a Pair of radius. The first is the top rounded corner radius and second is the * bottom corner radius. */ @Nullable - private static Pair loadRoundedCornerRadii(Resources res) { - final int radiusDefault = res.getDimensionPixelSize(R.dimen.rounded_corner_radius); - final int radiusTop = res.getDimensionPixelSize(R.dimen.rounded_corner_radius_top); - final int radiusBottom = res.getDimensionPixelSize(R.dimen.rounded_corner_radius_bottom); + private static Pair loadRoundedCornerRadii( + Resources res, String displayUniqueId) { + final int radiusDefault = getRoundedCornerRadius(res, displayUniqueId); + final int radiusTop = getRoundedCornerTopRadius(res, displayUniqueId); + final int radiusBottom = getRoundedCornerBottomRadius(res, displayUniqueId); if (radiusDefault == 0 && radiusTop == 0 && radiusBottom == 0) { return null; } @@ -157,6 +161,164 @@ public class RoundedCorners implements Parcelable { return radii; } + /** + * Gets the default rounded corner radius of a display which is determined by the + * given display unique id. + * + * Loads the default dimen{@link R.dimen#rounded_corner_radius} if + * {@link R.array#config_displayUniqueIdArray} is not set. + * + * @hide + */ + public static int getRoundedCornerRadius(Resources res, String displayUniqueId) { + final int index = DisplayUtils.getDisplayUniqueIdConfigIndex(res, displayUniqueId); + final TypedArray array = res.obtainTypedArray(R.array.config_roundedCornerRadiusArray); + int radius; + if (index >= 0 && index < array.length()) { + radius = array.getDimensionPixelSize(index, 0); + } else { + radius = res.getDimensionPixelSize(R.dimen.rounded_corner_radius); + } + array.recycle(); + return radius; + } + + /** + * Gets the top rounded corner radius of a display which is determined by the + * given display unique id. + * + * Loads the default dimen{@link R.dimen#rounded_corner_radius_top} if + * {@link R.array#config_displayUniqueIdArray} is not set. + * + * @hide + */ + public static int getRoundedCornerTopRadius(Resources res, String displayUniqueId) { + final int index = DisplayUtils.getDisplayUniqueIdConfigIndex(res, displayUniqueId); + final TypedArray array = res.obtainTypedArray(R.array.config_roundedCornerTopRadiusArray); + int radius; + if (index >= 0 && index < array.length()) { + radius = array.getDimensionPixelSize(index, 0); + } else { + radius = res.getDimensionPixelSize(R.dimen.rounded_corner_radius_top); + } + array.recycle(); + return radius; + } + + /** + * Gets the bottom rounded corner radius of a display which is determined by the + * given display unique id. + * + * Loads the default dimen{@link R.dimen#rounded_corner_radius_bottom} if + * {@link R.array#config_displayUniqueIdArray} is not set. + * + * @hide + */ + public static int getRoundedCornerBottomRadius(Resources res, String displayUniqueId) { + final int index = DisplayUtils.getDisplayUniqueIdConfigIndex(res, displayUniqueId); + final TypedArray array = res.obtainTypedArray( + R.array.config_roundedCornerBottomRadiusArray); + int radius; + if (index >= 0 && index < array.length()) { + radius = array.getDimensionPixelSize(index, 0); + } else { + radius = res.getDimensionPixelSize(R.dimen.rounded_corner_radius_bottom); + } + array.recycle(); + return radius; + } + + /** + * Gets the rounded corner radius adjustment of a display which is determined by the + * given display unique id. + * + * Loads the default dimen{@link R.dimen#rounded_corner_radius_adjustment} if + * {@link R.array#config_displayUniqueIdArray} is not set. + * + * @hide + */ + public static int getRoundedCornerRadiusAdjustment(Resources res, String displayUniqueId) { + final int index = DisplayUtils.getDisplayUniqueIdConfigIndex(res, displayUniqueId); + final TypedArray array = res.obtainTypedArray( + R.array.config_roundedCornerRadiusAdjustmentArray); + int radius; + if (index >= 0 && index < array.length()) { + radius = array.getDimensionPixelSize(index, 0); + } else { + radius = res.getDimensionPixelSize(R.dimen.rounded_corner_radius_adjustment); + } + array.recycle(); + return radius; + } + + /** + * Gets the rounded corner top radius adjustment of a display which is determined by the + * given display unique id. + * + * Loads the default dimen{@link R.dimen#rounded_corner_radius_top_adjustment} if + * {@link R.array#config_displayUniqueIdArray} is not set. + * + * @hide + */ + public static int getRoundedCornerRadiusTopAdjustment(Resources res, String displayUniqueId) { + final int index = DisplayUtils.getDisplayUniqueIdConfigIndex(res, displayUniqueId); + final TypedArray array = res.obtainTypedArray( + R.array.config_roundedCornerTopRadiusAdjustmentArray); + int radius; + if (index >= 0 && index < array.length()) { + radius = array.getDimensionPixelSize(index, 0); + } else { + radius = res.getDimensionPixelSize(R.dimen.rounded_corner_radius_top_adjustment); + } + array.recycle(); + return radius; + } + + /** + * Gets the rounded corner bottom radius adjustment of a display which is determined by the + * given display unique id. + * + * Loads the default dimen{@link R.dimen#rounded_corner_radius_bottom_adjustment} if + * {@link R.array#config_displayUniqueIdArray} is not set. + * + * @hide + */ + public static int getRoundedCornerRadiusBottomAdjustment( + Resources res, String displayUniqueId) { + final int index = DisplayUtils.getDisplayUniqueIdConfigIndex(res, displayUniqueId); + final TypedArray array = res.obtainTypedArray( + R.array.config_roundedCornerBottomRadiusAdjustmentArray); + int radius; + if (index >= 0 && index < array.length()) { + radius = array.getDimensionPixelSize(index, 0); + } else { + radius = res.getDimensionPixelSize(R.dimen.rounded_corner_radius_bottom_adjustment); + } + array.recycle(); + return radius; + } + + /** + * Gets whether a built-in display is round. + * + * Loads the default config{@link R.bool#config_mainBuiltInDisplayIsRound} if + * {@link R.array#config_displayUniqueIdArray} is not set. + * + * @hide + */ + public static boolean getBuiltInDisplayIsRound(Resources res, String displayUniqueId) { + final int index = DisplayUtils.getDisplayUniqueIdConfigIndex(res, displayUniqueId); + final TypedArray array = res.obtainTypedArray(R.array.config_builtInDisplayIsRoundArray); + boolean isRound; + if (index >= 0 && index < array.length()) { + isRound = array.getBoolean(index, false); + } else { + isRound = res.getBoolean(R.bool.config_mainBuiltInDisplayIsRound); + } + array.recycle(); + return isRound; + } + /** * Insets the reference frame of the rounded corners. * diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java index fa7330fb84eb..904aa73f6ac4 100644 --- a/core/java/android/view/Surface.java +++ b/core/java/android/view/Surface.java @@ -29,6 +29,7 @@ import android.graphics.Canvas; import android.graphics.ColorSpace; import android.graphics.HardwareRenderer; import android.graphics.Matrix; +import android.graphics.Point; import android.graphics.RecordingCanvas; import android.graphics.Rect; import android.graphics.RenderNode; @@ -411,6 +412,20 @@ public class Surface implements Parcelable { } } + /** + * Returns the default size of this Surface provided by the consumer of the surface. + * Should only be used by the producer of the surface. + * + * @hide + */ + @NonNull + public Point getDefaultSize() { + synchronized (mLock) { + checkNotReleasedLocked(); + return new Point(nativeGetWidth(mNativeObject), nativeGetHeight(mNativeObject)); + } + } + /** * Gets a {@link Canvas} for drawing into this surface. * diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java index b4e0de2cf7cf..9d79ed9e3441 100644 --- a/core/java/android/view/SurfaceControl.java +++ b/core/java/android/view/SurfaceControl.java @@ -23,6 +23,7 @@ import static android.graphics.Matrix.MSKEW_Y; import static android.graphics.Matrix.MTRANS_X; import static android.graphics.Matrix.MTRANS_Y; import static android.view.SurfaceControlProto.HASH_CODE; +import static android.view.SurfaceControlProto.LAYER_ID; import static android.view.SurfaceControlProto.NAME; import android.annotation.FloatRange; @@ -41,6 +42,7 @@ import android.graphics.PixelFormat; import android.graphics.Point; import android.graphics.Rect; import android.graphics.Region; +import android.gui.DropInputMode; import android.hardware.HardwareBuffer; import android.hardware.display.DeviceProductInfo; import android.hardware.display.DisplayedContentSample; @@ -150,13 +152,15 @@ public final class SurfaceControl implements Parcelable { float childRelativeTop, float childRelativeRight, float childRelativeBottom); private static native void nativeSetTrustedOverlay(long transactionObj, long nativeObject, boolean isTrustedOverlay); - + private static native void nativeSetDropInputMode( + long transactionObj, long nativeObject, int flags); private static native boolean nativeClearContentFrameStats(long nativeObject); private static native boolean nativeGetContentFrameStats(long nativeObject, WindowContentFrameStats outStats); private static native boolean nativeClearAnimationFrameStats(); private static native boolean nativeGetAnimationFrameStats(WindowAnimationFrameStats outStats); private static native long[] nativeGetPhysicalDisplayIds(); + private static native long nativeGetPrimaryPhysicalDisplayId(); private static native IBinder nativeGetPhysicalDisplayToken(long physicalDisplayId); private static native IBinder nativeCreateDisplay(String name, boolean secure); private static native void nativeDestroyDisplay(IBinder displayToken); @@ -164,6 +168,8 @@ public final class SurfaceControl implements Parcelable { IBinder displayToken, long nativeSurfaceObject); private static native void nativeSetDisplayLayerStack(long transactionObj, IBinder displayToken, int layerStack); + private static native void nativeSetDisplayFlags(long transactionObj, + IBinder displayToken, int flags); private static native void nativeSetDisplayProjection(long transactionObj, IBinder displayToken, int orientation, int l, int t, int r, int b, @@ -235,8 +241,80 @@ public final class SurfaceControl implements Parcelable { private static native void nativeRemoveJankDataListener(long nativeListener); private static native long nativeCreateJankDataListenerWrapper(OnJankDataListener listener); private static native int nativeGetGPUContextPriority(); - private static native void nativeSetTransformHint(long nativeObject, int transformHint); + private static native void nativeSetTransformHint(long nativeObject, + @SurfaceControl.BufferTransform int transformHint); private static native int nativeGetTransformHint(long nativeObject); + private static native int nativeGetLayerId(long nativeObject); + + /** + * Transforms that can be applied to buffers as they are displayed to a window. + * + * Supported transforms are any combination of horizontal mirror, vertical mirror, and + * clock-wise 90 degree rotation, in that order. Rotations of 180 and 270 degrees are made up + * of those basic transforms. + * Mirrors {@code ANativeWindowTransform} definitions. + * @hide + */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = {"BUFFER_TRANSFORM_"}, + value = {BUFFER_TRANSFORM_IDENTITY, BUFFER_TRANSFORM_MIRROR_HORIZONTAL, + BUFFER_TRANSFORM_MIRROR_VERTICAL, BUFFER_TRANSFORM_ROTATE_90, + BUFFER_TRANSFORM_ROTATE_180, BUFFER_TRANSFORM_ROTATE_270, + BUFFER_TRANSFORM_MIRROR_HORIZONTAL | BUFFER_TRANSFORM_ROTATE_90, + BUFFER_TRANSFORM_MIRROR_VERTICAL | BUFFER_TRANSFORM_ROTATE_90}) + public @interface BufferTransform { + } + + /** + * Identity transform. + * + * These transforms that can be applied to buffers as they are displayed to a window. + * @see HardwareBuffer + * + * Supported transforms are any combination of horizontal mirror, vertical mirror, and + * clock-wise 90 degree rotation, in that order. Rotations of 180 and 270 degrees are + * made up of those basic transforms. + */ + public static final int BUFFER_TRANSFORM_IDENTITY = 0x00; + /** + * Mirror horizontally. Can be combined with {@link #BUFFER_TRANSFORM_MIRROR_VERTICAL} + * and {@link #BUFFER_TRANSFORM_ROTATE_90}. + */ + public static final int BUFFER_TRANSFORM_MIRROR_HORIZONTAL = 0x01; + /** + * Mirror vertically. Can be combined with {@link #BUFFER_TRANSFORM_MIRROR_HORIZONTAL} + * and {@link #BUFFER_TRANSFORM_ROTATE_90}. + */ + public static final int BUFFER_TRANSFORM_MIRROR_VERTICAL = 0x02; + /** + * Rotate 90 degrees clock-wise. Can be combined with {@link + * #BUFFER_TRANSFORM_MIRROR_HORIZONTAL} and {@link #BUFFER_TRANSFORM_MIRROR_VERTICAL}. + */ + public static final int BUFFER_TRANSFORM_ROTATE_90 = 0x04; + /** + * Rotate 180 degrees clock-wise. Cannot be combined with other transforms. + */ + public static final int BUFFER_TRANSFORM_ROTATE_180 = + BUFFER_TRANSFORM_MIRROR_HORIZONTAL | BUFFER_TRANSFORM_MIRROR_VERTICAL; + /** + * Rotate 270 degrees clock-wise. Cannot be combined with other transforms. + */ + public static final int BUFFER_TRANSFORM_ROTATE_270 = + BUFFER_TRANSFORM_ROTATE_180 | BUFFER_TRANSFORM_ROTATE_90; + + /** + * @hide + */ + public static @BufferTransform int rotationToBufferTransform(@Surface.Rotation int rotation) { + switch (rotation) { + case Surface.ROTATION_0: return BUFFER_TRANSFORM_IDENTITY; + case Surface.ROTATION_90: return BUFFER_TRANSFORM_ROTATE_90; + case Surface.ROTATION_180: return BUFFER_TRANSFORM_ROTATE_180; + case Surface.ROTATION_270: return BUFFER_TRANSFORM_ROTATE_270; + } + Log.e(TAG, "Trying to convert unknown rotation=" + rotation); + return BUFFER_TRANSFORM_IDENTITY; + } @Nullable @GuardedBy("mLock") @@ -352,8 +430,6 @@ public final class SurfaceControl implements Parcelable { @GuardedBy("mLock") private int mHeight; - private int mTransformHint; - private WeakReference mLocalOwnerView; static GlobalTransactionWrapper sGlobalTransaction; @@ -550,6 +626,15 @@ public final class SurfaceControl implements Parcelable { */ private static final int SURFACE_OPAQUE = 0x02; + /* flags used with setDisplayFlags() (keep in sync with DisplayDevice.h) */ + + /** + * DisplayDevice flag: This display's transform is sent to inputflinger and used for input + * dispatch. This flag is used to disambiguate displays which share a layerstack. + * @hide + */ + public static final int DISPLAY_RECEIVES_INPUT = 0x01; + /* built-in physical display ids (keep in sync with ISurfaceComposer.h) * these are different from the logical display ids used elsewhere in the framework */ @@ -1530,6 +1615,7 @@ public final class SurfaceControl implements Parcelable { final long token = proto.start(fieldId); proto.write(HASH_CODE, System.identityHashCode(this)); proto.write(NAME, mName); + proto.write(LAYER_ID, getLayerId()); proto.end(token); } @@ -2268,6 +2354,15 @@ public final class SurfaceControl implements Parcelable { return nativeGetPhysicalDisplayIds(); } + /** + * Exposed to identify the correct display to apply the primary display orientation. Avoid using + * for any other purpose. + * @hide + */ + public static long getPrimaryPhysicalDisplayId() { + return nativeGetPrimaryPhysicalDisplayId(); + } + /** * @hide */ @@ -3169,6 +3264,17 @@ public final class SurfaceControl implements Parcelable { return this; } + /** + * @hide + */ + public Transaction setDisplayFlags(IBinder displayToken, int flags) { + if (displayToken == null) { + throw new IllegalArgumentException("displayToken must not be null"); + } + nativeSetDisplayFlags(mNativeObject, displayToken, flags); + return this; + } + /** * @hide */ @@ -3429,7 +3535,18 @@ public final class SurfaceControl implements Parcelable { return this; } - /** + /** + * Sets the input event drop mode on this SurfaceControl and its children. The caller must + * hold the ACCESS_SURFACE_FLINGER permission. See {@code InputEventDropMode}. + * @hide + */ + public Transaction setDropInputMode(SurfaceControl sc, @DropInputMode int mode) { + checkPreconditions(sc); + nativeSetDropInputMode(mNativeObject, sc.mNativeObject, mode); + return this; + } + + /** * Merge the other transaction into this transaction, clearing the * other transaction as if it had been applied. * @@ -3616,7 +3733,7 @@ public final class SurfaceControl implements Parcelable { /** * @hide */ - public int getTransformHint() { + public @SurfaceControl.BufferTransform int getTransformHint() { checkNotReleased(); return nativeGetTransformHint(mNativeObject); } @@ -3630,7 +3747,18 @@ public final class SurfaceControl implements Parcelable { * with the same size. * @hide */ - public void setTransformHint(@Surface.Rotation int transformHint) { + public void setTransformHint(@SurfaceControl.BufferTransform int transformHint) { nativeSetTransformHint(mNativeObject, transformHint); } + + /** + * @hide + */ + public int getLayerId() { + if (mNativeObject != 0) { + return nativeGetLayerId(mNativeObject); + } + + return -1; + } } diff --git a/core/java/android/view/SurfaceControlViewHost.java b/core/java/android/view/SurfaceControlViewHost.java index 11b161ad3cb2..a6c5042db275 100644 --- a/core/java/android/view/SurfaceControlViewHost.java +++ b/core/java/android/view/SurfaceControlViewHost.java @@ -292,11 +292,18 @@ public class SurfaceControlViewHost { */ @TestApi public void relayout(WindowManager.LayoutParams attrs) { + relayout(attrs, SurfaceControl.Transaction::apply); + } + + /** + * Forces relayout and draw and allows to set a custom callback when it is finished + * @hide + */ + public void relayout(WindowManager.LayoutParams attrs, + WindowlessWindowManager.ResizeCompleteCallback callback) { mViewRoot.setLayoutParams(attrs, false); mViewRoot.setReportNextDraw(); - mWm.setCompletionCallback(mViewRoot.mWindow.asBinder(), (SurfaceControl.Transaction t) -> { - t.apply(); - }); + mWm.setCompletionCallback(mViewRoot.mWindow.asBinder(), callback); } /** diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java index af61104774cb..49a55a43b7ab 100644 --- a/core/java/android/view/SurfaceView.java +++ b/core/java/android/view/SurfaceView.java @@ -138,20 +138,9 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall private boolean mDisableBackgroundLayer = false; /** - * We use this lock in SOME cases when reading or writing SurfaceControl, - * but use the following model so that the RenderThread can run locklessly - * in the position up-date case. - * - * 1. UI Thread can read from mSurfaceControl (use in Transactions) without - * holding the lock. - * 2. UI Thread will hold the lock when writing to mSurfaceControl (calling release - * or remove). - * 3. Render thread will also hold the lock when writing to mSurfaceControl (e.g. - * calling release from positionLost). - * 3. RenderNode.PositionUpdateListener::positionChanged will only be called - * when the UI thread is paused (blocked on the Render thread). - * 4. positionChanged thus will not be required to hold the lock as the - * UI thread is blocked, and the other writer is the RT itself. + * We use this lock to protect access to mSurfaceControl and + * SurfaceViewPositionUpdateListener#mPositionChangedTransaction. Both are accessed on the UI + * thread and the render thread. */ final Object mSurfaceControlLock = new Object(); final Rect mTmpRect = new Rect(); @@ -162,8 +151,6 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) boolean mIsCreating = false; - private volatile boolean mRtHandlingPositionUpdates = false; - private volatile boolean mRtReleaseSurfaces = false; private final ViewTreeObserver.OnScrollChangedListener mScrollChangedListener = this::updateSurface; @@ -214,7 +201,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) final Rect mSurfaceFrame = new Rect(); int mLastSurfaceWidth = -1, mLastSurfaceHeight = -1; - int mTransformHint = 0; + @SurfaceControl.BufferTransform int mTransformHint = 0; private boolean mGlobalListenersAdded; private boolean mAttachedToWindow; @@ -929,13 +916,14 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall mBlastBufferQueue = null; } - if (mRtHandlingPositionUpdates) { - mRtReleaseSurfaces = true; - return; + ViewRootImpl viewRoot = getViewRootImpl(); + Transaction transaction = new Transaction(); + releaseSurfaces(transaction); + if (viewRoot != null) { + viewRoot.applyTransactionOnDraw(transaction); + } else { + transaction.apply(); } - - releaseSurfaces(mTmpTransaction); - mTmpTransaction.apply(); } } @@ -963,9 +951,12 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall // When the listener is updated, we will get at least a single position update call so we can // guarantee any changes we post will be applied. private void replacePositionUpdateListener(int surfaceWidth, int surfaceHeight, - @Nullable Transaction geometryTransaction) { + Transaction geometryTransaction) { if (mPositionListener != null) { mRenderNode.removePositionUpdateListener(mPositionListener); + synchronized (mSurfaceControlLock) { + geometryTransaction = mPositionListener.getTransaction().merge(geometryTransaction); + } } mPositionListener = new SurfaceViewPositionUpdateListener(surfaceWidth, surfaceHeight, geometryTransaction); @@ -973,7 +964,8 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall } private boolean performSurfaceTransaction(ViewRootImpl viewRoot, Translator translator, - boolean creating, boolean sizeChanged, boolean hintChanged) { + boolean creating, boolean sizeChanged, boolean hintChanged, + Transaction geometryTransaction) { boolean realSizeChanged = false; mSurfaceLock.lock(); @@ -994,9 +986,9 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall mParentSurfaceSequenceId = viewRoot.getSurfaceSequenceId(); if (mViewVisibility) { - mTmpTransaction.show(mSurfaceControl); + geometryTransaction.show(mSurfaceControl); } else { - mTmpTransaction.hide(mSurfaceControl); + geometryTransaction.hide(mSurfaceControl); } if (mSurfacePackage != null) { @@ -1011,10 +1003,6 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall mSurfaceAlpha = alpha; } - // While creating the surface, we will set it's initial - // geometry. Outside of that though, we should generally - // leave it to the RenderThread. - Transaction geometryTransaction = new Transaction(); geometryTransaction.setCornerRadius(mSurfaceControl, mCornerRadius); if ((sizeChanged || hintChanged) && !creating) { setBufferSize(geometryTransaction); @@ -1037,20 +1025,18 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall mSurfaceHeight); } - boolean applyChangesOnRenderThread = - sizeChanged && !creating && isHardwareAccelerated(); if (isHardwareAccelerated()) { // This will consume the passed in transaction and the transaction will be // applied on a render worker thread. replacePositionUpdateListener(mSurfaceWidth, mSurfaceHeight, - applyChangesOnRenderThread ? geometryTransaction : null); + geometryTransaction); } if (DEBUG_POSITION) { Log.d(TAG, String.format( - "%d updateSurfacePosition %s" + "%d performSurfaceTransaction %s " + "position = [%d, %d, %d, %d] surfaceSize = %dx%d", System.identityHashCode(this), - applyChangesOnRenderThread ? "RenderWorker" : "UiThread", + isHardwareAccelerated() ? "RenderWorker" : "UI Thread", mScreenRect.left, mScreenRect.top, mScreenRect.right, mScreenRect.bottom, mSurfaceWidth, mSurfaceHeight)); } @@ -1124,7 +1110,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall || mWindowSpaceTop != mLocation[1]; final boolean layoutSizeChanged = getWidth() != mScreenRect.width() || getHeight() != mScreenRect.height(); - final boolean hintChanged = (viewRoot.getSurfaceTransformHint() != mTransformHint) + final boolean hintChanged = (viewRoot.getBufferTransformHint() != mTransformHint) && mRequestedVisible; if (creating || formatChanged || sizeChanged || visibleChanged || @@ -1150,7 +1136,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall mSurfaceHeight = myHeight; mFormat = mRequestedFormat; mLastWindowVisibility = mWindowVisibility; - mTransformHint = viewRoot.getSurfaceTransformHint(); + mTransformHint = viewRoot.getBufferTransformHint(); mScreenRect.left = mWindowSpaceLeft; mScreenRect.top = mWindowSpaceTop; @@ -1162,12 +1148,14 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall final Rect surfaceInsets = viewRoot.mWindowAttributes.surfaceInsets; mScreenRect.offset(surfaceInsets.left, surfaceInsets.top); - + // Collect all geometry changes and apply these changes on the RenderThread worker + // via the RenderNode.PositionUpdateListener. + final Transaction geometryTransaction = new Transaction(); if (creating) { updateOpaqueFlag(); final String name = "SurfaceView[" + viewRoot.getTitle().toString() + "]"; if (mUseBlastAdapter) { - createBlastSurfaceControls(viewRoot, name); + createBlastSurfaceControls(viewRoot, name, geometryTransaction); } else { mDeferredDestroySurfaceControl = createSurfaceControls(viewRoot, name); } @@ -1176,7 +1164,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall } final boolean realSizeChanged = performSurfaceTransaction(viewRoot, - translator, creating, sizeChanged, hintChanged); + translator, creating, sizeChanged, hintChanged, geometryTransaction); final boolean redrawNeeded = sizeChanged || creating || hintChanged || (mVisible && !mDrawFinished); @@ -1343,7 +1331,8 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall // is still alive, the old buffers will continue to be presented until replaced by buffers from // the new adapter. This means we do not need to track the old surface control and destroy it // after the client has drawn to avoid any flickers. - private void createBlastSurfaceControls(ViewRootImpl viewRoot, String name) { + private void createBlastSurfaceControls(ViewRootImpl viewRoot, String name, + Transaction geometryTransaction) { if (mSurfaceControl == null) { mSurfaceControl = new SurfaceControl.Builder(mSurfaceSession) .setName(name) @@ -1382,10 +1371,11 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall if (mBlastBufferQueue != null) { mBlastBufferQueue.destroy(); } - mTransformHint = viewRoot.getSurfaceTransformHint(); + mTransformHint = viewRoot.getBufferTransformHint(); mBlastSurfaceControl.setTransformHint(mTransformHint); - mBlastBufferQueue = new BLASTBufferQueue(name, mBlastSurfaceControl, mSurfaceWidth, - mSurfaceHeight, mFormat); + mBlastBufferQueue = new BLASTBufferQueue(name); + mBlastBufferQueue.update(mBlastSurfaceControl, mSurfaceWidth, mSurfaceHeight, mFormat, + geometryTransaction); } private void onDrawFinished() { @@ -1484,54 +1474,49 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall @Override public void positionChanged(long frameNumber, int left, int top, int right, int bottom) { - if (mSurfaceControl == null) { - return; - } - - // TODO: This is teensy bit racey in that a brand new SurfaceView moving on - // its 2nd frame if RenderThread is running slowly could potentially see - // this as false, enter the branch, get pre-empted, then this comes along - // and reports a new position, then the UI thread resumes and reports - // its position. This could therefore be de-sync'd in that interval, but - // the synchronization would violate the rule that RT must never block - // on the UI thread which would open up potential deadlocks. The risk of - // a single-frame desync is therefore preferable for now. synchronized(mSurfaceControlLock) { - mRtHandlingPositionUpdates = true; - } - if (mRTLastReportedPosition.left == left - && mRTLastReportedPosition.top == top - && mRTLastReportedPosition.right == right - && mRTLastReportedPosition.bottom == bottom - && mRTLastReportedSurfaceSize.x == mRtSurfaceWidth - && mRTLastReportedSurfaceSize.y == mRtSurfaceHeight - && !mPendingTransaction) { - return; - } - try { - if (DEBUG_POSITION) { - Log.d(TAG, String.format( - "%d updateSurfacePosition RenderWorker, frameNr = %d, " - + "position = [%d, %d, %d, %d] surfaceSize = %dx%d", - System.identityHashCode(SurfaceView.this), frameNumber, - left, top, right, bottom, mRtSurfaceWidth, mRtSurfaceHeight)); + if (mSurfaceControl == null) { + return; } - mRTLastReportedPosition.set(left, top, right, bottom); - mRTLastReportedSurfaceSize.set(mRtSurfaceWidth, mRtSurfaceHeight); - onSetSurfacePositionAndScaleRT(mPositionChangedTransaction, mSurfaceControl, - mRTLastReportedPosition.left /*positionLeft*/, - mRTLastReportedPosition.top /*positionTop*/, - mRTLastReportedPosition.width() / (float) mRtSurfaceWidth /*postScaleX*/, - mRTLastReportedPosition.height() / (float) mRtSurfaceHeight /*postScaleY*/); - if (mViewVisibility) { - mPositionChangedTransaction.show(mSurfaceControl); + if (mRTLastReportedPosition.left == left + && mRTLastReportedPosition.top == top + && mRTLastReportedPosition.right == right + && mRTLastReportedPosition.bottom == bottom + && mRTLastReportedSurfaceSize.x == mRtSurfaceWidth + && mRTLastReportedSurfaceSize.y == mRtSurfaceHeight + && !mPendingTransaction) { + return; + } + try { + if (DEBUG_POSITION) { + Log.d(TAG, String.format( + "%d updateSurfacePosition RenderWorker, frameNr = %d, " + + "position = [%d, %d, %d, %d] surfaceSize = %dx%d", + System.identityHashCode(SurfaceView.this), frameNumber, + left, top, right, bottom, mRtSurfaceWidth, mRtSurfaceHeight)); + } + mRTLastReportedPosition.set(left, top, right, bottom); + mRTLastReportedSurfaceSize.set(mRtSurfaceWidth, mRtSurfaceHeight); + onSetSurfacePositionAndScaleRT(mPositionChangedTransaction, mSurfaceControl, + mRTLastReportedPosition.left /*positionLeft*/, + mRTLastReportedPosition.top /*positionTop*/, + mRTLastReportedPosition.width() + / (float) mRtSurfaceWidth /*postScaleX*/, + mRTLastReportedPosition.height() + / (float) mRtSurfaceHeight /*postScaleY*/); + if (mViewVisibility) { + mPositionChangedTransaction.show(mSurfaceControl); + } + final ViewRootImpl viewRoot = getViewRootImpl(); + if (viewRoot != null) { + applyChildSurfaceTransaction_renderWorker(mPositionChangedTransaction, + viewRoot.mSurface, frameNumber); + } + applyOrMergeTransaction(mPositionChangedTransaction, frameNumber); + mPendingTransaction = false; + } catch (Exception ex) { + Log.e(TAG, "Exception from repositionChild", ex); } - applyChildSurfaceTransaction_renderWorker(mPositionChangedTransaction, - getViewRootImpl().mSurface, frameNumber); - applyOrMergeTransaction(mPositionChangedTransaction, frameNumber); - mPendingTransaction = false; - } catch (Exception ex) { - Log.e(TAG, "Exception from repositionChild", ex); } } @@ -1548,36 +1533,35 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall @Override public void positionLost(long frameNumber) { - if (DEBUG) { + if (DEBUG_POSITION) { Log.d(TAG, String.format("%d windowPositionLost, frameNr = %d", System.identityHashCode(this), frameNumber)); } mRTLastReportedPosition.setEmpty(); mRTLastReportedSurfaceSize.set(-1, -1); - if (mPendingTransaction) { - Log.w(TAG, System.identityHashCode(SurfaceView.this) - + "Pending transaction cleared."); - mPositionChangedTransaction.clear(); - mPendingTransaction = false; - } - if (mSurfaceControl == null) { - return; - } /** * positionLost can be called while UI thread is un-paused so we * need to hold the lock here. */ synchronized (mSurfaceControlLock) { - mRtTransaction.hide(mSurfaceControl); - if (mRtReleaseSurfaces) { - mRtReleaseSurfaces = false; - releaseSurfaces(mRtTransaction); + if (mPendingTransaction) { + Log.w(TAG, System.identityHashCode(SurfaceView.this) + + "Pending transaction cleared."); + mPositionChangedTransaction.clear(); + mPendingTransaction = false; + } + if (mSurfaceControl == null) { + return; } + mRtTransaction.hide(mSurfaceControl); applyOrMergeTransaction(mRtTransaction, frameNumber); - mRtHandlingPositionUpdates = false; } } + + public Transaction getTransaction() { + return mPositionChangedTransaction; + } } private SurfaceViewPositionUpdateListener mPositionListener = null; @@ -1624,12 +1608,21 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall * @hide */ public void setResizeBackgroundColor(int bgColor) { + setResizeBackgroundColor(mTmpTransaction, bgColor); + mTmpTransaction.apply(); + } + + /** + * Version of {@link #setResizeBackgroundColor(int)} that allows you to provide + * {@link SurfaceControl.Transaction}. + * @hide + */ + public void setResizeBackgroundColor(@NonNull SurfaceControl.Transaction t, int bgColor) { if (mBackgroundControl == null) { return; } - mBackgroundColor = bgColor; - updateBackgroundColor(mTmpTransaction).apply(); + updateBackgroundColor(t); } @UnsupportedAppUsage @@ -1662,6 +1655,11 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall @Override public void setFixedSize(int width, int height) { if (mRequestedWidth != width || mRequestedHeight != height) { + if (DEBUG_POSITION) { + Log.d(TAG, String.format("%d setFixedSize %dx%d -> %dx%d", + System.identityHashCode(this), mRequestedWidth, mRequestedHeight, width, + height)); + } mRequestedWidth = width; mRequestedHeight = height; requestLayout(); @@ -1671,6 +1669,10 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall @Override public void setSizeFromLayout() { if (mRequestedWidth != -1 || mRequestedHeight != -1) { + if (DEBUG_POSITION) { + Log.d(TAG, String.format("%d setSizeFromLayout was %dx%d", + System.identityHashCode(this), mRequestedWidth, mRequestedHeight)); + } mRequestedWidth = mRequestedHeight = -1; requestLayout(); } @@ -1898,18 +1900,45 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall * @param p The SurfacePackage to embed. */ public void setChildSurfacePackage(@NonNull SurfaceControlViewHost.SurfacePackage p) { + setChildSurfacePackage(p, false /* applyTransactionOnDraw */); + } + + /** + * Similar to setChildSurfacePackage, but using the BLAST queue so the transaction can be + * synchronized with the ViewRootImpl frame. + * @hide + */ + public void setChildSurfacePackageOnDraw( + @NonNull SurfaceControlViewHost.SurfacePackage p) { + setChildSurfacePackage(p, true /* applyTransactionOnDraw */); + } + + /** + * @param applyTransactionOnDraw Whether to apply transaction at onDraw or immediately. + */ + private void setChildSurfacePackage( + @NonNull SurfaceControlViewHost.SurfacePackage p, boolean applyTransactionOnDraw) { final SurfaceControl lastSc = mSurfacePackage != null ? mSurfacePackage.getSurfaceControl() : null; if (mSurfaceControl != null && lastSc != null) { - mTmpTransaction.reparent(lastSc, null).apply(); + mTmpTransaction.reparent(lastSc, null); mSurfacePackage.release(); + applyTransaction(applyTransactionOnDraw); } else if (mSurfaceControl != null) { reparentSurfacePackage(mTmpTransaction, p); - mTmpTransaction.apply(); + applyTransaction(applyTransactionOnDraw); } mSurfacePackage = p; } + private void applyTransaction(boolean applyTransactionOnDraw) { + if (applyTransactionOnDraw) { + getViewRootImpl().applyTransactionOnDraw(mTmpTransaction); + } else { + mTmpTransaction.apply(); + } + } + private void reparentSurfacePackage(SurfaceControl.Transaction t, SurfaceControlViewHost.SurfacePackage p) { final SurfaceControl sc = p.getSurfaceControl(); diff --git a/core/java/android/view/TaskTransitionSpec.aidl b/core/java/android/view/TaskTransitionSpec.aidl new file mode 100644 index 000000000000..08af15c3f933 --- /dev/null +++ b/core/java/android/view/TaskTransitionSpec.aidl @@ -0,0 +1,20 @@ +/* +** Copyright 2021, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT 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; + +/** @hide */ +parcelable TaskTransitionSpec; diff --git a/core/java/android/view/TaskTransitionSpec.java b/core/java/android/view/TaskTransitionSpec.java new file mode 100644 index 000000000000..5f498a19f196 --- /dev/null +++ b/core/java/android/view/TaskTransitionSpec.java @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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.os.Parcel; +import android.os.Parcelable; +import android.util.ArraySet; + +import java.util.Set; + +/** + * Holds information about how to execute task transition animations. + * + * This class is intended to be used with IWindowManager.setTaskTransitionSpec methods when + * we want more customization over the way default task transitions are executed. + * + * @hide + */ +public class TaskTransitionSpec implements Parcelable { + /** + * The background color to use during task animations (override the default background color) + */ + public final int backgroundColor; + + /** + * TEMPORARY FIELD (b/202383002) + * TODO: Remove once we use surfaceflinger rounded corners on tasks rather than taskbar overlays + * or when shell transitions are fully enabled + * + * A set of {@InsetsState.InternalInsetsType}s we want to use as the source to set the bounds + * of the task during the animation. Used to make sure that task animate above the taskbar. + * Will also be used to crop to the frame size of the inset source to the inset size to prevent + * the taskbar rounded corners overlay from being invisible during task transition animation. + */ + public final Set animationBoundInsets; + + public TaskTransitionSpec( + int backgroundColor, Set animationBoundInsets) { + this.backgroundColor = backgroundColor; + this.animationBoundInsets = animationBoundInsets; + } + + public TaskTransitionSpec(Parcel in) { + this.backgroundColor = in.readInt(); + + int animationBoundInsetsSize = in.readInt(); + this.animationBoundInsets = new ArraySet<>(animationBoundInsetsSize); + for (int i = 0; i < animationBoundInsetsSize; i++) { + this.animationBoundInsets.add(in.readInt()); + } + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(backgroundColor); + + dest.writeInt(animationBoundInsets.size()); + for (int insetType : animationBoundInsets) { + dest.writeInt(insetType); + } + } + + public static final @android.annotation.NonNull Parcelable.Creator + CREATOR = new Parcelable.Creator() { + public TaskTransitionSpec createFromParcel(Parcel in) { + return new TaskTransitionSpec(in); + } + + public TaskTransitionSpec[] newArray(int size) { + return new TaskTransitionSpec[size]; + } + }; +} diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 0f4556fa02c4..79e52995ade3 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -3515,6 +3515,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * 1 PFLAG4_ALLOW_CLICK_WHEN_DISABLED * 1 PFLAG4_DETACHED * 1 PFLAG4_HAS_TRANSLATION_TRANSIENT_STATE + * 1 PFLAG4_DRAG_A11Y_STARTED * |-------|-------|-------|-------| */ @@ -3586,6 +3587,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback, */ private static final int PFLAG4_HAS_TRANSLATION_TRANSIENT_STATE = 0x000004000; + /** + * Indicates that the view has started a drag with {@link AccessibilityAction#ACTION_DRAG_START} + */ + private static final int PFLAG4_DRAG_A11Y_STARTED = 0x000008000; + /* End of masks for mPrivateFlags4 */ /** @hide */ @@ -5035,6 +5041,14 @@ public class View implements Drawable.Callback, KeyEvent.Callback, */ public static final int DRAG_FLAG_OPAQUE = 1 << 9; + /** + * Flag indicating that the drag was initiated with + * {@link AccessibilityNodeInfo.AccessibilityAction#ACTION_DRAG_START}. When + * {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, int)} is called, this + * is used by the system to perform a drag without animations. + */ + public static final int DRAG_FLAG_ACCESSIBILITY_ACTION = 1 << 10; + /** * Vertical scroll factor cached by {@link #getVerticalScrollFactor}. */ @@ -10376,8 +10390,17 @@ public class View implements Drawable.Callback, KeyEvent.Callback, if (mTouchDelegate != null) { info.setTouchDelegateInfo(mTouchDelegate.getTouchDelegateInfo()); } + + if (startedSystemDragForAccessibility()) { + info.addAction(AccessibilityAction.ACTION_DRAG_CANCEL); + } + + if (canAcceptAccessibilityDrop()) { + info.addAction(AccessibilityAction.ACTION_DRAG_DROP); + } } + /** * Adds extra data to an {@link AccessibilityNodeInfo} based on an explicit request for the * additional data. @@ -14214,9 +14237,45 @@ public class View implements Drawable.Callback, KeyEvent.Callback, return true; } } + + if (action == R.id.accessibilityActionDragDrop) { + if (!canAcceptAccessibilityDrop()) { + return false; + } + try { + if (mAttachInfo != null && mAttachInfo.mSession != null) { + final int[] location = new int[2]; + getLocationInWindow(location); + final int centerX = location[0] + getWidth() / 2; + final int centerY = location[1] + getHeight() / 2; + return mAttachInfo.mSession.dropForAccessibility(mAttachInfo.mWindow, + centerX, centerY); + } + } catch (RemoteException e) { + Log.e(VIEW_LOG_TAG, "Unable to drop for accessibility", e); + } + return false; + } else if (action == R.id.accessibilityActionDragCancel) { + if (!startedSystemDragForAccessibility()) { + return false; + } + if (mAttachInfo != null && mAttachInfo.mDragToken != null) { + cancelDragAndDrop(); + return true; + } + return false; + } return false; } + private boolean canAcceptAccessibilityDrop() { + if (!canAcceptDrag()) { + return false; + } + ListenerInfo li = mListenerInfo; + return (li != null) && (li.mOnDragListener != null || li.mOnReceiveContentListener != null); + } + private boolean traverseAtGranularity(int granularity, boolean forward, boolean extendSelection) { CharSequence text = getIterableTextForAccessibility(); @@ -20215,7 +20274,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, */ @CallSuper protected void onAttachedToWindow() { - if ((mPrivateFlags & PFLAG_REQUEST_TRANSPARENT_REGIONS) != 0) { + if (mParent != null && (mPrivateFlags & PFLAG_REQUEST_TRANSPARENT_REGIONS) != 0) { mParent.requestTransparentRegion(this); } @@ -24989,7 +25048,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, View parent = this; - while (parent.mParent != null && parent.mParent instanceof View) { + while (parent.mParent instanceof View) { parent = (View) parent.mParent; } @@ -26637,6 +26696,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, *
  • {@link #DRAG_FLAG_GLOBAL_URI_READ}
  • *
  • {@link #DRAG_FLAG_GLOBAL_URI_WRITE}
  • *
  • {@link #DRAG_FLAG_OPAQUE}
  • + *
  • {@link #DRAG_FLAG_ACCESSIBILITY_ACTION}
  • * * @return {@code true} if the method completes successfully, or * {@code false} if it fails anywhere. Returning {@code false} means the system was unable to @@ -26660,6 +26720,37 @@ public class View implements Drawable.Callback, KeyEvent.Callback, data.prepareToLeaveProcess((flags & View.DRAG_FLAG_GLOBAL) != 0); } + Rect bounds = new Rect(); + getBoundsOnScreen(bounds, true); + + Point lastTouchPoint = new Point(); + mAttachInfo.mViewRootImpl.getLastTouchPoint(lastTouchPoint); + final ViewRootImpl root = mAttachInfo.mViewRootImpl; + + // Skip surface logic since shadows and animation are not required during the a11y drag + final boolean a11yEnabled = AccessibilityManager.getInstance(mContext).isEnabled(); + if (a11yEnabled && (flags & View.DRAG_FLAG_ACCESSIBILITY_ACTION) != 0) { + try { + IBinder token = mAttachInfo.mSession.performDrag( + mAttachInfo.mWindow, flags, null, + mAttachInfo.mViewRootImpl.getLastTouchSource(), + 0f, 0f, 0f, 0f, data); + if (ViewDebug.DEBUG_DRAG) { + Log.d(VIEW_LOG_TAG, "startDragAndDrop via a11y action returned " + token); + } + if (token != null) { + root.setLocalDragState(myLocalState); + mAttachInfo.mDragToken = token; + mAttachInfo.mViewRootImpl.setDragStartedViewForAccessibility(this); + setAccessibilityDragStarted(true); + } + return token != null; + } catch (Exception e) { + Log.e(VIEW_LOG_TAG, "Unable to initiate a11y drag", e); + return false; + } + } + Point shadowSize = new Point(); Point shadowTouchPoint = new Point(); shadowBuilder.onProvideShadowMetrics(shadowSize, shadowTouchPoint); @@ -26684,7 +26775,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, + " shadowX=" + shadowTouchPoint.x + " shadowY=" + shadowTouchPoint.y); } - final ViewRootImpl root = mAttachInfo.mViewRootImpl; final SurfaceSession session = new SurfaceSession(); final SurfaceControl surfaceControl = new SurfaceControl.Builder(session) .setName("drag surface") @@ -26707,12 +26797,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback, surface.unlockCanvasAndPost(canvas); } - // repurpose 'shadowSize' for the last touch point - root.getLastTouchPoint(shadowSize); - - token = mAttachInfo.mSession.performDrag( - mAttachInfo.mWindow, flags, surfaceControl, root.getLastTouchSource(), - shadowSize.x, shadowSize.y, shadowTouchPoint.x, shadowTouchPoint.y, data); + token = mAttachInfo.mSession.performDrag(mAttachInfo.mWindow, flags, surfaceControl, + root.getLastTouchSource(), lastTouchPoint.x, lastTouchPoint.y, + shadowTouchPoint.x, shadowTouchPoint.y, data); if (ViewDebug.DEBUG_DRAG) { Log.d(VIEW_LOG_TAG, "performDrag returned " + token); } @@ -26724,6 +26811,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback, mAttachInfo.mDragToken = token; // Cache the local state object for delivery with DragEvents root.setLocalDragState(myLocalState); + if (a11yEnabled) { + // Set for AccessibilityEvents + mAttachInfo.mViewRootImpl.setDragStartedViewForAccessibility(this); + } } return token != null; } catch (Exception e) { @@ -26737,6 +26828,24 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } } + void setAccessibilityDragStarted(boolean started) { + int pflags4 = mPrivateFlags4; + if (started) { + pflags4 |= PFLAG4_DRAG_A11Y_STARTED; + } else { + pflags4 &= ~PFLAG4_DRAG_A11Y_STARTED; + } + + if (pflags4 != mPrivateFlags4) { + mPrivateFlags4 = pflags4; + sendWindowContentChangedAccessibilityEvent(CONTENT_CHANGE_TYPE_UNDEFINED); + } + } + + private boolean startedSystemDragForAccessibility() { + return (mPrivateFlags4 & PFLAG4_DRAG_A11Y_STARTED) != 0; + } + /** * Cancels an ongoing drag and drop operation. *

    @@ -26954,6 +27063,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } switch (event.mAction) { + case DragEvent.ACTION_DRAG_STARTED: { + if (result && li != null && li.mOnDragListener != null) { + sendWindowContentChangedAccessibilityEvent( + AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); + } + } break; case DragEvent.ACTION_DRAG_ENTERED: { mPrivateFlags2 |= View.PFLAG2_DRAG_HOVERED; refreshDrawableState(); @@ -26962,7 +27077,16 @@ public class View implements Drawable.Callback, KeyEvent.Callback, mPrivateFlags2 &= ~View.PFLAG2_DRAG_HOVERED; refreshDrawableState(); } break; + case DragEvent.ACTION_DROP: { + if (result && li != null && (li.mOnDragListener != null + || li.mOnReceiveContentListener != null)) { + sendWindowContentChangedAccessibilityEvent( + AccessibilityEvent.CONTENT_CHANGE_TYPE_DRAG_DROPPED); + } + } break; case DragEvent.ACTION_DRAG_ENDED: { + sendWindowContentChangedAccessibilityEvent( + AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); mPrivateFlags2 &= ~View.DRAG_MASK; refreshDrawableState(); } break; @@ -26975,6 +27099,15 @@ public class View implements Drawable.Callback, KeyEvent.Callback, return (mPrivateFlags2 & PFLAG2_DRAG_CAN_ACCEPT) != 0; } + void sendWindowContentChangedAccessibilityEvent(int changeType) { + if (AccessibilityManager.getInstance(mContext).isEnabled()) { + AccessibilityEvent event = AccessibilityEvent.obtain(); + event.setEventType(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED); + event.setContentChangeTypes(changeType); + sendAccessibilityEventUnchecked(event); + } + } + /** * This needs to be a better API (NOT ON VIEW) before it is exposed. If * it is ever exposed at all. diff --git a/core/java/android/view/ViewConfiguration.java b/core/java/android/view/ViewConfiguration.java index 0a3d0da6da1e..4b18d3a02282 100644 --- a/core/java/android/view/ViewConfiguration.java +++ b/core/java/android/view/ViewConfiguration.java @@ -433,9 +433,8 @@ public class ViewConfiguration { mAmbiguousGestureMultiplier = Math.max(1.0f, multiplierValue.getFloat()); // Size of the screen in bytes, in ARGB_8888 format - final WindowManager windowManager = context.getSystemService(WindowManager.class); - final Rect maxWindowBounds = windowManager.getMaximumWindowMetrics().getBounds(); - mMaximumDrawingCacheSize = 4 * maxWindowBounds.width() * maxWindowBounds.height(); + final Rect maxBounds = config.windowConfiguration.getMaxBounds(); + mMaximumDrawingCacheSize = 4 * maxBounds.width() * maxBounds.height(); mOverscrollDistance = (int) (sizeAndDensity * OVERSCROLL_DISTANCE + 0.5f); mOverflingDistance = (int) (sizeAndDensity * OVERFLING_DISTANCE + 0.5f); diff --git a/core/java/android/view/ViewParent.java b/core/java/android/view/ViewParent.java index 775c15e77d5d..49f5229d3c09 100644 --- a/core/java/android/view/ViewParent.java +++ b/core/java/android/view/ViewParent.java @@ -412,6 +412,9 @@ public interface ViewParent { *

  • {@link AccessibilityEvent#CONTENT_CHANGE_TYPE_SUBTREE} *
  • {@link AccessibilityEvent#CONTENT_CHANGE_TYPE_TEXT} *
  • {@link AccessibilityEvent#CONTENT_CHANGE_TYPE_UNDEFINED} + *
  • {@link AccessibilityEvent#CONTENT_CHANGE_TYPE_DRAG_STARTED} + *
  • {@link AccessibilityEvent#CONTENT_CHANGE_TYPE_DRAG_CANCELLED} + *
  • {@link AccessibilityEvent#CONTENT_CHANGE_TYPE_DRAG_DROPPED} * */ public void notifySubtreeAccessibilityStateChanged( diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 6152f5dd939b..6aa85a6cc1d4 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -215,6 +215,7 @@ import java.util.List; import java.util.Objects; import java.util.Queue; import java.util.concurrent.CountDownLatch; +import java.util.function.Consumer; /** * The top of a view hierarchy, implementing the needed protocol between View @@ -292,12 +293,31 @@ public final class ViewRootImpl implements ViewParent, */ private static final int SCROLL_CAPTURE_REQUEST_TIMEOUT_MILLIS = 2500; + /** + * If set to {@code true}, the new logic to layout system bars as normal window and to use + * layout result to get insets will be applied. Otherwise, the old hard-coded window logic will + * be applied. + */ + private static final String USE_FLEXIBLE_INSETS = "persist.debug.flexible_insets"; + + /** + * A flag to indicate to use the new generalized insets window logic, or the old hard-coded + * insets window layout logic. + * {@hide} + */ + public static final boolean INSETS_LAYOUT_GENERALIZATION = + SystemProperties.getBoolean(USE_FLEXIBLE_INSETS, false); + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) static final ThreadLocal sRunQueues = new ThreadLocal(); static final ArrayList sFirstDrawHandlers = new ArrayList<>(); static boolean sFirstDrawComplete = false; + private ArrayList mTransformHintListeners = + new ArrayList<>(); + private @SurfaceControl.BufferTransform + int mPreviousTransformHint = SurfaceControl.BUFFER_TRANSFORM_IDENTITY; /** * Callback for notifying about global configuration changes. */ @@ -634,6 +654,7 @@ public final class ViewRootImpl implements ViewParent, /* Drag/drop */ ClipDescription mDragDescription; View mCurrentDragView; + View mStartedDragViewForA11y; volatile Object mLocalDragState; final PointF mDragPoint = new PointF(); final PointF mLastTouchPoint = new PointF(); @@ -738,6 +759,8 @@ public final class ViewRootImpl implements ViewParent, */ private boolean mNextDrawUseBlastSync = false; + private Consumer mBLASTDrawConsumer; + /** * Wait for the blast sync transaction complete callback before drawing and queuing up more * frames. This will prevent out of order buffers submissions when WM has requested to @@ -745,6 +768,12 @@ public final class ViewRootImpl implements ViewParent, */ private boolean mWaitForBlastSyncComplete = false; + /** + * Keeps track of the last frame number that was attempted to draw. Should only be accessed on + * the RenderThread. + */ + private long mRtLastAttemptedDrawFrameNum = 0; + /** * Keeps track of whether a traverse was triggered while the UI thread was paused. This can * occur when the client is waiting on another process to submit the transaction that @@ -861,6 +890,13 @@ public final class ViewRootImpl implements ViewParent, } } + /** Remove a static config callback. */ + public static void removeConfigCallback(ConfigChangedCallback callback) { + synchronized (sConfigCallbacks) { + sConfigCallbacks.remove(callback); + } + } + /** Add activity config callback to be notified about override config changes. */ public void setActivityConfigCallback(ActivityConfigCallback callback) { mActivityConfigCallback = callback; @@ -1114,7 +1150,7 @@ public final class ViewRootImpl implements ViewParent, controlInsetsForCompatibility(mWindowAttributes); res = mWindowSession.addToDisplayAsUser(mWindow, mWindowAttributes, getHostVisibility(), mDisplay.getDisplayId(), userId, - mInsetsController.getRequestedVisibility(), inputChannel, mTempInsets, + mInsetsController.getRequestedVisibilities(), inputChannel, mTempInsets, mTempControls); if (mTranslator != null) { mTranslator.translateInsetsStateInScreenToAppWindow(mTempInsets); @@ -2472,7 +2508,7 @@ public final class ViewRootImpl implements ViewParent, mAttachInfo.mContentInsets.set(mLastWindowInsets.getSystemWindowInsets().toRect()); mAttachInfo.mStableInsets.set(mLastWindowInsets.getStableInsets().toRect()); mAttachInfo.mVisibleInsets.set(mInsetsController.calculateVisibleInsets( - mWindowAttributes.softInputMode)); + mWindowAttributes.softInputMode).toRect()); } return mLastWindowInsets; } @@ -2522,6 +2558,14 @@ public final class ViewRootImpl implements ViewParent, || lp.type == TYPE_VOLUME_OVERLAY; } + private Rect getWindowBoundsInsetSystemBars() { + final Rect bounds = new Rect( + mContext.getResources().getConfiguration().windowConfiguration.getBounds()); + bounds.inset(mInsetsController.getState().calculateInsets( + bounds, Type.systemBars(), false /* ignoreVisibility */)); + return bounds; + } + int dipToPx(int dip) { final DisplayMetrics displayMetrics = mContext.getResources().getDisplayMetrics(); return (int) (displayMetrics.density * dip + 0.5f); @@ -2608,8 +2652,9 @@ public final class ViewRootImpl implements ViewParent, || lp.height == ViewGroup.LayoutParams.WRAP_CONTENT) { // For wrap content, we have to remeasure later on anyways. Use size consistent with // below so we get best use of the measure cache. - desiredWindowWidth = dipToPx(config.screenWidthDp); - desiredWindowHeight = dipToPx(config.screenHeightDp); + final Rect bounds = getWindowBoundsInsetSystemBars(); + desiredWindowWidth = bounds.width(); + desiredWindowHeight = bounds.height(); } else { // After addToDisplay, the frame contains the frameHint from window manager, which // for most windows is going to be the same size as the result of relayoutWindow. @@ -2686,9 +2731,9 @@ public final class ViewRootImpl implements ViewParent, desiredWindowWidth = size.x; desiredWindowHeight = size.y; } else { - Configuration config = res.getConfiguration(); - desiredWindowWidth = dipToPx(config.screenWidthDp); - desiredWindowHeight = dipToPx(config.screenHeightDp); + final Rect bounds = getWindowBoundsInsetSystemBars(); + desiredWindowWidth = bounds.width(); + desiredWindowHeight = bounds.height(); } } } @@ -3318,6 +3363,9 @@ public final class ViewRootImpl implements ViewParent, } boolean cancelDraw = mAttachInfo.mTreeObserver.dispatchOnPreDraw() || !isViewVisible; + if (mBLASTDrawConsumer != null) { + mNextDrawUseBlastSync = true; + } if (!cancelDraw) { if (mPendingTransitions != null && mPendingTransitions.size() > 0) { @@ -4012,68 +4060,112 @@ public final class ViewRootImpl implements ViewParent, } /** - * The callback will run on the render thread. + * Only call this on the UI Thread. + */ + void clearBlastSync() { + mNextDrawUseBlastSync = false; + mWaitForBlastSyncComplete = false; + if (DEBUG_BLAST) { + Log.d(mTag, "Scheduling a traversal=" + mRequestedTraverseWhilePaused + + " due to a previous skipped traversal."); + } + if (mRequestedTraverseWhilePaused) { + mRequestedTraverseWhilePaused = false; + scheduleTraversals(); + } + } + + /** + * @hide */ - private HardwareRenderer.FrameCompleteCallback createFrameCompleteCallback(Handler handler, - boolean reportNextDraw, ArrayList commitCallbacks) { - return frameNr -> { + public boolean isHardwareEnabled() { + return mAttachInfo.mThreadedRenderer != null && mAttachInfo.mThreadedRenderer.isEnabled(); + } + + private boolean addFrameCompleteCallbackIfNeeded(boolean reportNextDraw) { + if (!isHardwareEnabled()) { + return false; + } + + if (!mNextDrawUseBlastSync && !reportNextDraw) { + return false; + } + + if (DEBUG_BLAST) { + Log.d(mTag, "Creating frameCompleteCallback"); + } + + mAttachInfo.mThreadedRenderer.setFrameCompleteCallback(() -> { + long frameNr = mBlastBufferQueue.getLastAcquiredFrameNum(); if (DEBUG_BLAST) { - Log.d(mTag, "Received frameCompleteCallback frameNum=" + frameNr); + Log.d(mTag, "Received frameCompleteCallback " + + " lastAcquiredFrameNum=" + frameNr + + " lastAttemptedDrawFrameNum=" + mRtLastAttemptedDrawFrameNum); + } + + boolean frameWasNotDrawn = frameNr != mRtLastAttemptedDrawFrameNum; + // If frame wasn't drawn, clear out the next transaction so it doesn't affect the next + // draw attempt. The next transaction and transaction complete callback were only set + // for the current draw attempt. + if (frameWasNotDrawn) { + mBlastBufferQueue.setNextTransaction(null); + mBlastBufferQueue.setTransactionCompleteCallback(mRtLastAttemptedDrawFrameNum, + null); } - handler.postAtFrontOfQueue(() -> { + mHandler.postAtFrontOfQueue(() -> { if (mNextDrawUseBlastSync) { // We don't need to synchronize mRtBLASTSyncTransaction here since we're // guaranteed that this is called after onFrameDraw and mNextDrawUseBlastSync // is only true when the UI thread is paused. Therefore, no one should be // modifying this object until the next vsync. mSurfaceChangedTransaction.merge(mRtBLASTSyncTransaction); + if (mBLASTDrawConsumer != null) { + mBLASTDrawConsumer.accept(mSurfaceChangedTransaction); + } + mBLASTDrawConsumer = null; } if (reportNextDraw) { - // TODO: Use the frame number pendingDrawFinished(); } - if (commitCallbacks != null) { - for (int i = 0; i < commitCallbacks.size(); i++) { - commitCallbacks.get(i).run(); - } + + if (frameWasNotDrawn) { + clearBlastSync(); } }); - }; - } - - /** - * @hide - */ - public boolean isHardwareEnabled() { - return mAttachInfo.mThreadedRenderer != null && mAttachInfo.mThreadedRenderer.isEnabled(); + }); + return true; } - private boolean addFrameCompleteCallbackIfNeeded() { + private void addFrameCommitCallbackIfNeeded() { if (!isHardwareEnabled()) { - return false; + return; } ArrayList commitCallbacks = mAttachInfo.mTreeObserver .captureFrameCommitCallbacks(); - final boolean needFrameCompleteCallback = - mNextDrawUseBlastSync || mReportNextDraw - || (commitCallbacks != null && commitCallbacks.size() > 0); - if (needFrameCompleteCallback) { - if (DEBUG_BLAST) { - Log.d(mTag, "Creating frameCompleteCallback" - + " mNextDrawUseBlastSync=" + mNextDrawUseBlastSync - + " mReportNextDraw=" + mReportNextDraw - + " commitCallbacks size=" - + (commitCallbacks == null ? 0 : commitCallbacks.size())); - } - mAttachInfo.mThreadedRenderer.setFrameCompleteCallback( - createFrameCompleteCallback(mAttachInfo.mHandler, mReportNextDraw, - commitCallbacks)); - return true; + final boolean needFrameCommitCallback = + (commitCallbacks != null && commitCallbacks.size() > 0); + if (!needFrameCommitCallback) { + return; } - return false; + + if (DEBUG_DRAW) { + Log.d(mTag, "Creating frameCommitCallback" + + " commitCallbacks size=" + commitCallbacks.size()); + } + mAttachInfo.mThreadedRenderer.setFrameCommitCallback(didProduceBuffer -> { + if (DEBUG_DRAW) { + Log.d(mTag, "Received frameCommitCallback didProduceBuffer=" + didProduceBuffer); + } + + mHandler.postAtFrontOfQueue(() -> { + for (int i = 0; i < commitCallbacks.size(); i++) { + commitCallbacks.get(i).run(); + } + }); + }); } private void addFrameCallbackIfNeeded() { @@ -4103,6 +4195,8 @@ public final class ViewRootImpl implements ViewParent, + " Creating transactionCompleteCallback=" + nextDrawUseBlastSync); } + mRtLastAttemptedDrawFrameNum = frame; + if (needsCallbackForBlur) { mBlurRegionAggregator .dispatchBlurTransactionIfNeeded(frame, blurRegionsForFrame, hasBlurUpdates); @@ -4125,24 +4219,8 @@ public final class ViewRootImpl implements ViewParent, if (DEBUG_BLAST) { Log.d(mTag, "Received transactionCompleteCallback frameNum=" + frame); } - mHandler.postAtFrontOfQueue(() -> { - mNextDrawUseBlastSync = false; - mWaitForBlastSyncComplete = false; - if (DEBUG_BLAST) { - Log.d(mTag, "Scheduling a traversal=" + mRequestedTraverseWhilePaused - + " due to a previous skipped traversal."); - } - if (mRequestedTraverseWhilePaused) { - mRequestedTraverseWhilePaused = false; - scheduleTraversals(); - } - }); + mHandler.postAtFrontOfQueue(this::clearBlastSync); }); - } else if (reportNextDraw) { - // If we need to report next draw, wait for adapter to flush its shadow queue - // by processing previously queued buffers so that we can submit the - // transaction a timely manner. - mBlastBufferQueue.flushShadowQueue(); } }; registerRtFrameCallback(frameDrawingCallback); @@ -4162,8 +4240,9 @@ public final class ViewRootImpl implements ViewParent, mIsDrawing = true; Trace.traceBegin(Trace.TRACE_TAG_VIEW, "draw"); - boolean usingAsyncReport = addFrameCompleteCallbackIfNeeded(); addFrameCallbackIfNeeded(); + addFrameCommitCallbackIfNeeded(); + boolean usingAsyncReport = addFrameCompleteCallbackIfNeeded(mReportNextDraw); try { boolean canUseAsync = draw(fullRedrawNeeded); @@ -4272,6 +4351,14 @@ public final class ViewRootImpl implements ViewParent, try { if (!isContentCaptureEnabled()) return; + // Initial dispatch of window bounds to content capture + if (mAttachInfo.mContentCaptureManager != null) { + MainContentCaptureSession session = + mAttachInfo.mContentCaptureManager.getMainContentCaptureSession(); + session.notifyWindowBoundsChanged(session.getId(), + getConfiguration().windowConfiguration.getBounds()); + } + // Content capture is a go! rootView.dispatchInitialProvideContentCaptureStructure(); } finally { @@ -7573,6 +7660,11 @@ public final class ViewRootImpl implements ViewParent, if (what == DragEvent.ACTION_DRAG_STARTED) { mCurrentDragView = null; // Start the current-recipient tracking mDragDescription = event.mClipDescription; + if (mStartedDragViewForA11y != null) { + // Send a drag started a11y event + mStartedDragViewForA11y.sendWindowContentChangedAccessibilityEvent( + AccessibilityEvent.CONTENT_CHANGE_TYPE_DRAG_STARTED); + } } else { if (what == DragEvent.ACTION_DRAG_ENDED) { mDragDescription = null; @@ -7647,6 +7739,16 @@ public final class ViewRootImpl implements ViewParent, // When the drag operation ends, reset drag-related state if (what == DragEvent.ACTION_DRAG_ENDED) { + if (mStartedDragViewForA11y != null) { + // If the drag failed, send a cancelled event from the source. Otherwise, + // the View that accepted the drop sends CONTENT_CHANGE_TYPE_DRAG_DROPPED + if (!event.getResult()) { + mStartedDragViewForA11y.sendWindowContentChangedAccessibilityEvent( + AccessibilityEvent.CONTENT_CHANGE_TYPE_DRAG_CANCELLED); + } + mStartedDragViewForA11y.setAccessibilityDragStarted(false); + } + mStartedDragViewForA11y = null; mCurrentDragView = null; setLocalDragState(null); mAttachInfo.mDragToken = null; @@ -7726,6 +7828,13 @@ public final class ViewRootImpl implements ViewParent, mCurrentDragView = newDragTarget; } + /** Sets the view that started drag and drop for the purpose of sending AccessibilityEvents */ + void setDragStartedViewForAccessibility(View view) { + if (mStartedDragViewForA11y == null) { + mStartedDragViewForA11y = view; + } + } + private AudioManager getAudioManager() { if (mView == null) { throw new IllegalStateException("getAudioManager called when there is no mView"); @@ -7804,6 +7913,14 @@ public final class ViewRootImpl implements ViewParent, insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0, frameNumber, mTmpFrames, mPendingMergedConfiguration, mSurfaceControl, mTempInsets, mTempControls, mSurfaceSize); + + if (mAttachInfo.mContentCaptureManager != null) { + MainContentCaptureSession mainSession = mAttachInfo.mContentCaptureManager + .getMainContentCaptureSession(); + mainSession.notifyWindowBoundsChanged(mainSession.getId(), + getConfiguration().windowConfiguration.getBounds()); + } + mPendingBackDropFrame.set(mTmpFrames.backdropFrame); if (mSurfaceControl.isValid()) { if (!useBLAST()) { @@ -7824,6 +7941,11 @@ public final class ViewRootImpl implements ViewParent, } mAttachInfo.mThreadedRenderer.setSurfaceControl(mSurfaceControl); } + int transformHint = mSurfaceControl.getTransformHint(); + if (mPreviousTransformHint != transformHint) { + mPreviousTransformHint = transformHint; + dispatchTransformHintChanged(transformHint); + } } else { destroySurface(); } @@ -8298,7 +8420,7 @@ public final class ViewRootImpl implements ViewParent, if (mTranslator != null) { mTranslator.translateInsetsStateInScreenToAppWindow(insetsState); } - if (insetsState != null && insetsState.getSource(ITYPE_IME).isVisible()) { + if (insetsState != null && insetsState.getSourceOrDefaultVisibility(ITYPE_IME)) { ImeTracing.getInstance().triggerClientDump("ViewRootImpl#dispatchInsetsChanged", getInsetsController().getHost().getInputMethodManager(), null /* icProto */); } @@ -8323,7 +8445,7 @@ public final class ViewRootImpl implements ViewParent, mTranslator.translateInsetsStateInScreenToAppWindow(insetsState); mTranslator.translateSourceControlsInScreenToAppWindow(activeControls); } - if (insetsState != null && insetsState.getSource(ITYPE_IME).isVisible()) { + if (insetsState != null && insetsState.getSourceOrDefaultVisibility(ITYPE_IME)) { ImeTracing.getInstance().triggerClientDump("ViewRootImpl#dispatchInsetsControlChanged", getInsetsController().getHost().getInputMethodManager(), null /* icProto */); } @@ -9934,7 +10056,10 @@ public final class ViewRootImpl implements ViewParent, if (!mUseMTRenderer) { return; } - mWindowDrawCountDown = new CountDownLatch(mWindowCallbacks.size()); + // Only wait if it will report next draw. + if (mReportNextDraw) { + mWindowDrawCountDown = new CountDownLatch(mWindowCallbacks.size()); + } for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) { mWindowCallbacks.get(i).onRequestDraw(mReportNextDraw); } @@ -10440,13 +10565,78 @@ public final class ViewRootImpl implements ViewParent, @Override public boolean applyTransactionOnDraw(@NonNull SurfaceControl.Transaction t) { - registerRtFrameCallback(frame -> { - mergeWithNextTransaction(t, frame); - }); + if (mRemoved || !isHardwareEnabled()) { + t.apply(); + } else { + registerRtFrameCallback(frame -> mergeWithNextTransaction(t, frame)); + } return true; } - int getSurfaceTransformHint() { + @Override + public @SurfaceControl.BufferTransform int getBufferTransformHint() { return mSurfaceControl.getTransformHint(); } + + @Override + public void addOnBufferTransformHintChangedListener( + OnBufferTransformHintChangedListener listener) { + Objects.requireNonNull(listener); + if (mTransformHintListeners.contains(listener)) { + throw new IllegalArgumentException( + "attempt to call addOnBufferTransformHintChangedListener() " + + "with a previously registered listener"); + } + mTransformHintListeners.add(listener); + } + + @Override + public void removeOnBufferTransformHintChangedListener( + OnBufferTransformHintChangedListener listener) { + Objects.requireNonNull(listener); + mTransformHintListeners.remove(listener); + } + + private void dispatchTransformHintChanged(@SurfaceControl.BufferTransform int hint) { + if (mTransformHintListeners.isEmpty()) { + return; + } + ArrayList listeners = + (ArrayList) mTransformHintListeners.clone(); + for (int i = 0; i < listeners.size(); i++) { + OnBufferTransformHintChangedListener listener = listeners.get(i); + listener.onBufferTransformHintChanged(hint); + } + } + + /** + * Redirect the next draw of this ViewRoot (from the UI thread perspective) + * to the passed in consumer. This can be used to create P2P synchronization + * between ViewRoot's however it comes with many caveats. + * + * 1. You MUST consume the transaction, by either applying it immediately or + * merging it in to another transaction. The threading model doesn't + * allow you to hold in the passed transaction. + * 2. If you merge it in to another transaction, this ViewRootImpl will be + * paused until you finally apply that transaction and it receives + * the callback from SF. If you lose track of the transaction you will + * ANR the app. + * 3. Only one person can consume the transaction at a time, if you already + * have a pending consumer for this frame, the function will return false + * 4. Someone else may have requested to consume the next frame, in which case + * this function will return false and you will not receive a callback. + * 5. This function does not trigger drawing so even if it returns true you + * may not receive a callback unless there is some other UI thread work + * to trigger drawing. If it returns true, and a draw occurs, the callback + * will be called (Though again watch out for the null transaction case!) + * 6. This function must be called on the UI thread. The consumer will likewise + * be called on the UI thread. + */ + public boolean consumeNextDraw(Consumer consume) { + if (mBLASTDrawConsumer != null) { + return false; + } + mBLASTDrawConsumer = consume; + return true; + } } diff --git a/core/java/android/view/ViewRootInsetsControllerHost.java b/core/java/android/view/ViewRootInsetsControllerHost.java index ce882da1a6da..efffa2b05a1e 100644 --- a/core/java/android/view/ViewRootInsetsControllerHost.java +++ b/core/java/android/view/ViewRootInsetsControllerHost.java @@ -149,10 +149,10 @@ public class ViewRootInsetsControllerHost implements InsetsController.Host { } @Override - public void onInsetsModified(InsetsState insetsState) { + public void updateRequestedVisibilities(InsetsVisibilities vis) { try { if (mViewRoot.mAdded) { - mViewRoot.mWindowSession.insetsModified(mViewRoot.mWindow, insetsState); + mViewRoot.mWindowSession.updateRequestedVisibilities(mViewRoot.mWindow, vis); } } catch (RemoteException e) { Log.e(TAG, "Failed to call insetsModified", e); diff --git a/core/java/android/view/WindowInfo.java b/core/java/android/view/WindowInfo.java index 57dfc62b4f8f..1edbbba09eef 100644 --- a/core/java/android/view/WindowInfo.java +++ b/core/java/android/view/WindowInfo.java @@ -16,6 +16,7 @@ package android.view; +import android.app.ActivityTaskManager; import android.graphics.Region; import android.os.IBinder; import android.os.Parcel; @@ -51,6 +52,7 @@ public class WindowInfo implements Parcelable { public boolean inPictureInPicture; public boolean hasFlagWatchOutsideTouch; public int displayId = Display.INVALID_DISPLAY; + public int taskId = ActivityTaskManager.INVALID_TASK_ID; private WindowInfo() { /* do nothing - hide constructor */ @@ -67,6 +69,7 @@ public class WindowInfo implements Parcelable { public static WindowInfo obtain(WindowInfo other) { WindowInfo window = obtain(); window.displayId = other.displayId; + window.taskId = other.taskId; window.type = other.type; window.layer = other.layer; window.token = other.token; @@ -103,6 +106,7 @@ public class WindowInfo implements Parcelable { @Override public void writeToParcel(Parcel parcel, int flags) { parcel.writeInt(displayId); + parcel.writeInt(taskId); parcel.writeInt(type); parcel.writeInt(layer); parcel.writeStrongBinder(token); @@ -129,6 +133,7 @@ public class WindowInfo implements Parcelable { builder.append("WindowInfo["); builder.append("title=").append(title); builder.append(", displayId=").append(displayId); + builder.append(", taskId=").append(taskId); builder.append(", type=").append(type); builder.append(", layer=").append(layer); builder.append(", token=").append(token); @@ -146,6 +151,7 @@ public class WindowInfo implements Parcelable { private void initFromParcel(Parcel parcel) { displayId = parcel.readInt(); + taskId = parcel.readInt(); type = parcel.readInt(); layer = parcel.readInt(); token = parcel.readStrongBinder(); @@ -169,6 +175,7 @@ public class WindowInfo implements Parcelable { private void clear() { displayId = Display.INVALID_DISPLAY; + taskId = ActivityTaskManager.INVALID_TASK_ID; type = 0; layer = 0; token = null; diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java index 55beae0f7b3d..27c5ac2887c1 100644 --- a/core/java/android/view/WindowManager.java +++ b/core/java/android/view/WindowManager.java @@ -97,6 +97,7 @@ import android.content.ClipData; import android.content.Context; import android.content.pm.ActivityInfo; import android.content.res.Configuration; +import android.graphics.Insets; import android.graphics.PixelFormat; import android.graphics.Point; import android.graphics.Rect; @@ -318,6 +319,25 @@ public interface WindowManager extends ViewManager { */ int TRANSIT_OLD_TASK_CHANGE_WINDOWING_MODE = 27; + /** + * A window in a new task fragment is being opened. + * @hide + */ + int TRANSIT_OLD_TASK_FRAGMENT_OPEN = 28; + + /** + * A window in the top-most activity of task fragment is being closed to reveal the activity + * below. + * @hide + */ + int TRANSIT_OLD_TASK_FRAGMENT_CLOSE = 29; + + /** + * A window of task fragment is changing bounds. + * @hide + */ + int TRANSIT_OLD_TASK_FRAGMENT_CHANGE = 30; + /** * @hide */ @@ -343,7 +363,10 @@ public interface WindowManager extends ViewManager { TRANSIT_OLD_TRANSLUCENT_ACTIVITY_OPEN, TRANSIT_OLD_TRANSLUCENT_ACTIVITY_CLOSE, TRANSIT_OLD_CRASHING_ACTIVITY_CLOSE, - TRANSIT_OLD_TASK_CHANGE_WINDOWING_MODE + TRANSIT_OLD_TASK_CHANGE_WINDOWING_MODE, + TRANSIT_OLD_TASK_FRAGMENT_OPEN, + TRANSIT_OLD_TASK_FRAGMENT_CLOSE, + TRANSIT_OLD_TASK_FRAGMENT_CHANGE }) @Retention(RetentionPolicy.SOURCE) @interface TransitionOldType {} @@ -380,8 +403,11 @@ public interface WindowManager extends ViewManager { int TRANSIT_CHANGE = 6; /** * The keyguard was visible and has been dismissed. + * @deprecated use {@link #TRANSIT_TO_BACK} + {@link #TRANSIT_FLAG_KEYGUARD_GOING_AWAY} for + * keyguard going away with Shell transition. * @hide */ + @Deprecated int TRANSIT_KEYGUARD_GOING_AWAY = 7; /** * A window is appearing above a locked keyguard. @@ -393,6 +419,16 @@ public interface WindowManager extends ViewManager { * @hide */ int TRANSIT_KEYGUARD_UNOCCLUDE = 9; + /** + * A window is starting to enter PiP. + * @hide + */ + int TRANSIT_PIP = 10; + /** + * The screen is turning on. + * @hide + */ + int TRANSIT_WAKE = 11; /** * The first slot for custom transition types. Callers (like Shell) can make use of custom * transition types for dealing with special cases. These types are effectively ignored by @@ -402,7 +438,7 @@ public interface WindowManager extends ViewManager { * implementation. * @hide */ - int TRANSIT_FIRST_CUSTOM = 10; + int TRANSIT_FIRST_CUSTOM = 12; /** * @hide @@ -418,6 +454,8 @@ public interface WindowManager extends ViewManager { TRANSIT_KEYGUARD_GOING_AWAY, TRANSIT_KEYGUARD_OCCLUDE, TRANSIT_KEYGUARD_UNOCCLUDE, + TRANSIT_PIP, + TRANSIT_WAKE, TRANSIT_FIRST_CUSTOM }) @Retention(RetentionPolicy.SOURCE) @@ -466,6 +504,19 @@ public interface WindowManager extends ViewManager { */ int TRANSIT_FLAG_KEYGUARD_LOCKED = 0x40; + /** + * Transition flag: Indicates that this transition is for recents animation. + * TODO(b/188669821): Remove once special-case logic moves to shell. + * @hide + */ + int TRANSIT_FLAG_IS_RECENTS = 0x80; + + /** + * Transition flag: Indicates that keyguard should go away with this transition. + * @hide + */ + int TRANSIT_FLAG_KEYGUARD_GOING_AWAY = 0x100; + /** * @hide */ @@ -476,7 +527,9 @@ public interface WindowManager extends ViewManager { TRANSIT_FLAG_KEYGUARD_GOING_AWAY_SUBTLE_ANIMATION, TRANSIT_FLAG_APP_CRASHED, TRANSIT_FLAG_OPEN_BEHIND, - TRANSIT_FLAG_KEYGUARD_LOCKED + TRANSIT_FLAG_KEYGUARD_LOCKED, + TRANSIT_FLAG_IS_RECENTS, + TRANSIT_FLAG_KEYGUARD_GOING_AWAY }) @Retention(RetentionPolicy.SOURCE) @interface TransitionFlags {} @@ -922,6 +975,8 @@ public interface WindowManager extends ViewManager { case TRANSIT_KEYGUARD_GOING_AWAY: return "KEYGUARD_GOING_AWAY"; case TRANSIT_KEYGUARD_OCCLUDE: return "KEYGUARD_OCCLUDE"; case TRANSIT_KEYGUARD_UNOCCLUDE: return "KEYGUARD_UNOCCLUDE"; + case TRANSIT_PIP: return "PIP"; + case TRANSIT_WAKE: return "WAKE"; case TRANSIT_FIRST_CUSTOM: return "FIRST_CUSTOM"; default: if (type > TRANSIT_FIRST_CUSTOM) { @@ -2370,6 +2425,20 @@ public interface WindowManager extends ViewManager { */ public static final int PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY = 0x00100000; + /** + * Flag to indicate that this window will be excluded while computing the magnifiable region + * on the un-scaled screen coordinate, which could avoid the cutout on the magnification + * border. It should be used for unmagnifiable overlays. + * + *

    + * Note unlike {@link #PRIVATE_FLAG_NOT_MAGNIFIABLE}, this flag doesn't affect the ability + * of magnification. If you want to the window to be unmagnifiable and doesn't lead to the + * cutout, you need to combine both of them. + *

    + * @hide + */ + public static final int PRIVATE_FLAG_EXCLUDE_FROM_SCREEN_MAGNIFICATION = 0x00200000; + /** * Flag to prevent the window from being magnified by the accessibility magnifier. * @@ -2481,6 +2550,7 @@ 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_EXCLUDE_FROM_SCREEN_MAGNIFICATION, PRIVATE_FLAG_NOT_MAGNIFIABLE, PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION, PRIVATE_FLAG_COLOR_SPACE_AGNOSTIC, @@ -2561,6 +2631,10 @@ public interface WindowManager extends ViewManager { mask = PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY, equals = PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY, name = "IS_ROUNDED_CORNERS_OVERLAY"), + @ViewDebug.FlagToString( + mask = PRIVATE_FLAG_EXCLUDE_FROM_SCREEN_MAGNIFICATION, + equals = PRIVATE_FLAG_EXCLUDE_FROM_SCREEN_MAGNIFICATION, + name = "EXCLUDE_FROM_SCREEN_MAGNIFICATION"), @ViewDebug.FlagToString( mask = PRIVATE_FLAG_NOT_MAGNIFIABLE, equals = PRIVATE_FLAG_NOT_MAGNIFIABLE, @@ -3467,6 +3541,30 @@ public interface WindowManager extends ViewManager { */ public @InsetsState.InternalInsetsType int[] providesInsetsTypes; + /** + * If specified, the insets provided by this window will be our window frame minus the + * insets specified by providedInternalInsets. + * + * @hide + */ + public Insets providedInternalInsets = Insets.NONE; + + /** + * If specified, the insets provided by this window for the IME will be our window frame + * minus the insets specified by providedInternalImeInsets. + * + * @hide + */ + public Insets providedInternalImeInsets = Insets.NONE; + + /** + * {@link LayoutParams} to be applied to the window when layout with a assigned rotation. + * This will make layout during rotation change smoothly. + * + * @hide + */ + public LayoutParams[] paramsForRotation; + /** * Specifies types of insets that this window should avoid overlapping during layout. * @@ -3566,6 +3664,18 @@ public interface WindowManager extends ViewManager { return mFitInsetsIgnoringVisibility; } + private void checkNonRecursiveParams() { + if (paramsForRotation == null) { + return; + } + for (int i = paramsForRotation.length - 1; i >= 0; i--) { + if (paramsForRotation[i].paramsForRotation != null) { + throw new IllegalArgumentException( + "Params cannot contain params recursively."); + } + } + } + public LayoutParams() { super(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); type = TYPE_APPLICATION; @@ -3820,6 +3930,15 @@ public interface WindowManager extends ViewManager { } else { out.writeInt(0); } + providedInternalInsets.writeToParcel(out, 0 /* parcelableFlags */); + providedInternalImeInsets.writeToParcel(out, 0 /* parcelableFlags */); + if (paramsForRotation != null) { + checkNonRecursiveParams(); + out.writeInt(paramsForRotation.length); + out.writeTypedArray(paramsForRotation, 0 /* parcelableFlags */); + } else { + out.writeInt(0); + } } public static final @android.annotation.NonNull Parcelable.Creator CREATOR @@ -3891,6 +4010,13 @@ public interface WindowManager extends ViewManager { providesInsetsTypes = new int[insetsTypesLength]; in.readIntArray(providesInsetsTypes); } + providedInternalInsets = Insets.CREATOR.createFromParcel(in); + providedInternalImeInsets = Insets.CREATOR.createFromParcel(in); + int paramsForRotationLength = in.readInt(); + if (paramsForRotationLength > 0) { + paramsForRotation = new LayoutParams[paramsForRotationLength]; + in.readTypedArray(paramsForRotation, LayoutParams.CREATOR); + } } @SuppressWarnings({"PointlessBitwiseExpression"}) @@ -4187,6 +4313,22 @@ public interface WindowManager extends ViewManager { changes |= LAYOUT_CHANGED; } + if (!providedInternalInsets.equals(o.providedInternalInsets)) { + providedInternalInsets = o.providedInternalInsets; + changes |= LAYOUT_CHANGED; + } + + if (!providedInternalImeInsets.equals(o.providedInternalImeInsets)) { + providedInternalImeInsets = o.providedInternalImeInsets; + changes |= LAYOUT_CHANGED; + } + + if (!Arrays.equals(paramsForRotation, o.paramsForRotation)) { + paramsForRotation = o.paramsForRotation; + checkNonRecursiveParams(); + changes |= LAYOUT_CHANGED; + } + return changes; } @@ -4382,6 +4524,22 @@ public interface WindowManager extends ViewManager { sb.append(InsetsState.typeToString(providesInsetsTypes[i])); } } + if (!providedInternalInsets.equals(Insets.NONE)) { + sb.append(" providedInternalInsets="); + sb.append(providedInternalInsets); + } + if (!providedInternalImeInsets.equals(Insets.NONE)) { + sb.append(" providedInternalImeInsets="); + sb.append(providedInternalImeInsets); + } + if (paramsForRotation != null && paramsForRotation.length != 0) { + sb.append(System.lineSeparator()); + sb.append(prefix).append(" paramsForRotation="); + for (int i = 0; i < paramsForRotation.length; ++i) { + if (i > 0) sb.append(' '); + sb.append(paramsForRotation[i].toString()); + } + } sb.append('}'); return sb.toString(); @@ -4596,6 +4754,16 @@ public interface WindowManager extends ViewManager { return Integer.toString(inputFeature); } } + + /** + * True if the window should consume all pointer events itself, regardless of whether they + * are inside of the window. If the window is modal, its touchable region will expand to the + * size of its task. + * @hide + */ + public boolean isModal() { + return (flags & (FLAG_NOT_TOUCH_MODAL | FLAG_NOT_FOCUSABLE)) == 0; + } } /** diff --git a/core/java/android/view/WindowManagerGlobal.java b/core/java/android/view/WindowManagerGlobal.java index 18013e815d13..c92a3a086a8b 100644 --- a/core/java/android/view/WindowManagerGlobal.java +++ b/core/java/android/view/WindowManagerGlobal.java @@ -18,6 +18,7 @@ package android.view; import android.animation.ValueAnimator; import android.annotation.NonNull; +import android.annotation.Nullable; import android.app.ActivityManager; import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentCallbacks2; @@ -709,6 +710,16 @@ public final class WindowManagerGlobal { } } } + + /** @hide */ + @Nullable + public SurfaceControl mirrorWallpaperSurface(int displayId) { + try { + return getWindowManagerService().mirrorWallpaperSurface(displayId); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } } final class WindowLeaked extends AndroidRuntimeException { diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java index 2908cbea2133..3ad4e353f0cb 100644 --- a/core/java/android/view/WindowManagerImpl.java +++ b/core/java/android/view/WindowManagerImpl.java @@ -19,9 +19,12 @@ package android.view; import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN; import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION; import static android.view.View.SYSTEM_UI_FLAG_VISIBLE; +import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW; import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR; import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN; +import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW; import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING; +import static android.window.WindowProviderService.isWindowProviderService; import android.annotation.CallbackExecutor; import android.annotation.NonNull; @@ -36,7 +39,9 @@ import android.graphics.Region; import android.os.Bundle; import android.os.IBinder; import android.os.RemoteException; +import android.os.StrictMode; import android.window.WindowContext; +import android.window.WindowProvider; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.os.IResultReceiver; @@ -147,6 +152,7 @@ public final class WindowManagerImpl implements WindowManager { throw new IllegalArgumentException("Params must be WindowManager.LayoutParams"); } final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params; + assertWindowContextTypeMatches(wparams.type); // Only use the default token if we don't have a parent window and a token. if (mDefaultToken != null && mParentWindow == null && wparams.token == null) { wparams.token = mDefaultToken; @@ -154,6 +160,34 @@ public final class WindowManagerImpl implements WindowManager { wparams.mWindowContextToken = mWindowContextToken; } + private void assertWindowContextTypeMatches(@LayoutParams.WindowType int windowType) { + if (!(mContext instanceof WindowProvider)) { + return; + } + // Don't need to check sub-window type because sub window should be allowed to be attached + // to the parent window. + if (windowType >= FIRST_SUB_WINDOW && windowType <= LAST_SUB_WINDOW) { + return; + } + final WindowProvider windowProvider = (WindowProvider) mContext; + if (windowProvider.getWindowType() == windowType) { + return; + } + IllegalArgumentException exception = new IllegalArgumentException("Window type mismatch." + + " Window Context's window type is " + windowProvider.getWindowType() + + ", while LayoutParams' type is set to " + windowType + "." + + " Please create another Window Context via" + + " createWindowContext(getDisplay(), " + windowType + ", null)" + + " to add window with type:" + windowType); + if (!isWindowProviderService(windowProvider.getWindowContextOptions())) { + throw exception; + } + // Throw IncorrectCorrectViolation if the Window Context is allowed to provide multiple + // window types. Usually it's because the Window Context is a WindowProviderService. + StrictMode.onIncorrectContextUsed("WindowContext's window type must" + + " match type in WindowManager.LayoutParams", exception); + } + @Override public void removeView(View view) { mGlobal.removeView(view, false); diff --git a/core/java/android/view/WindowManagerPolicyConstants.java b/core/java/android/view/WindowManagerPolicyConstants.java index bbef3e6aeefa..94f633314b4e 100644 --- a/core/java/android/view/WindowManagerPolicyConstants.java +++ b/core/java/android/view/WindowManagerPolicyConstants.java @@ -209,4 +209,44 @@ public interface WindowManagerPolicyConstants { return Integer.toString(why); } } + + /** + * How much to multiply the policy's type layer, to reserve room + * for multiple windows of the same type and Z-ordering adjustment + * with TYPE_LAYER_OFFSET. + */ + int TYPE_LAYER_MULTIPLIER = 10000; + + /** + * Offset from TYPE_LAYER_MULTIPLIER for moving a group of windows above + * or below others in the same layer. + */ + int TYPE_LAYER_OFFSET = 1000; + + /** + * How much to increment the layer for each window, to reserve room + * for effect surfaces between them. + */ + int WINDOW_LAYER_MULTIPLIER = 5; + + /** + * Animation thumbnail is as far as possible below the window above + * the thumbnail (or in other words as far as possible above the window + * below it). + */ + int LAYER_OFFSET_THUMBNAIL = WINDOW_LAYER_MULTIPLIER - 1; + + // TODO(b/207185041): Remove this divider workaround after we full remove leagacy split and + // make app pair split only have single root then we can just attach the + // divider to the single root task in shell. + int SPLIT_DIVIDER_LAYER = TYPE_LAYER_MULTIPLIER * 3; + int WATERMARK_LAYER = TYPE_LAYER_MULTIPLIER * 100; + int STRICT_MODE_LAYER = TYPE_LAYER_MULTIPLIER * 101; + int WINDOW_FREEZE_LAYER = TYPE_LAYER_MULTIPLIER * 200; + + /** + * Layers for screen rotation animation. We put these layers above + * WINDOW_FREEZE_LAYER so that screen freeze will cover all windows. + */ + int SCREEN_FREEZE_LAYER_BASE = WINDOW_FREEZE_LAYER + TYPE_LAYER_MULTIPLIER; } diff --git a/core/java/android/view/WindowlessWindowManager.java b/core/java/android/view/WindowlessWindowManager.java index ae54f51f35d1..ffb7efa67243 100644 --- a/core/java/android/view/WindowlessWindowManager.java +++ b/core/java/android/view/WindowlessWindowManager.java @@ -135,7 +135,7 @@ public class WindowlessWindowManager implements IWindowSession { */ @Override public int addToDisplay(IWindow window, WindowManager.LayoutParams attrs, - int viewVisibility, int displayId, InsetsState requestedVisibility, + int viewVisibility, int displayId, InsetsVisibilities requestedVisibilities, InputChannel outInputChannel, InsetsState outInsetsState, InsetsSourceControl[] outActiveControls) { final SurfaceControl.Builder b = new SurfaceControl.Builder(mSurfaceSession) @@ -181,10 +181,10 @@ public class WindowlessWindowManager implements IWindowSession { */ @Override public int addToDisplayAsUser(IWindow window, WindowManager.LayoutParams attrs, - int viewVisibility, int displayId, int userId, InsetsState requestedVisibility, + int viewVisibility, int displayId, int userId, InsetsVisibilities requestedVisibilities, InputChannel outInputChannel, InsetsState outInsetsState, InsetsSourceControl[] outActiveControls) { - return addToDisplay(window, attrs, viewVisibility, displayId, requestedVisibility, + return addToDisplay(window, attrs, viewVisibility, displayId, requestedVisibilities, outInputChannel, outInsetsState, outActiveControls); } @@ -454,7 +454,7 @@ public class WindowlessWindowManager implements IWindowSession { } @Override - public void insetsModified(android.view.IWindow window, android.view.InsetsState state) { + public void updateRequestedVisibilities(IWindow window, InsetsVisibilities visibilities) { } @Override @@ -498,4 +498,9 @@ public class WindowlessWindowManager implements IWindowSession { public void generateDisplayHash(IWindow window, Rect boundsInWindow, String hashAlgorithm, RemoteCallback callback) { } + + @Override + public boolean dropForAccessibility(IWindow window, int x, int y) { + return false; + } } diff --git a/core/java/android/view/accessibility/AccessibilityEvent.java b/core/java/android/view/accessibility/AccessibilityEvent.java index f6d6fde6435f..3b65ffd35730 100644 --- a/core/java/android/view/accessibility/AccessibilityEvent.java +++ b/core/java/android/view/accessibility/AccessibilityEvent.java @@ -612,6 +612,36 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par */ public static final int CONTENT_CHANGE_TYPE_STATE_DESCRIPTION = 0x00000040; + /** + * Change type for {@link #TYPE_WINDOW_CONTENT_CHANGED} event: + * A drag has started while accessibility is enabled. This is either via an + * AccessibilityAction, or via touch events. This is sent from the source that initiated the + * drag. + * + * @see AccessibilityNodeInfo.AccessibilityAction#ACTION_DRAG_START + */ + public static final int CONTENT_CHANGE_TYPE_DRAG_STARTED = 0x00000080; + + /** + * Change type for {@link #TYPE_WINDOW_CONTENT_CHANGED} event: + * A drag in with accessibility enabled has ended. This means the content has been + * successfully dropped. This is sent from the target that accepted the dragged content. + * + * @see AccessibilityNodeInfo.AccessibilityAction#ACTION_DRAG_DROP + */ + public static final int CONTENT_CHANGE_TYPE_DRAG_DROPPED = 0x00000100; + + /** + * Change type for {@link #TYPE_WINDOW_CONTENT_CHANGED} event: + * A drag in with accessibility enabled has ended. This means the content has been + * unsuccessfully dropped, the user has canceled the action via an AccessibilityAction, or + * no drop has been detected within a timeout and the drag was automatically cancelled. This is + * sent from the source that initiated the drag. + * + * @see AccessibilityNodeInfo.AccessibilityAction#ACTION_DRAG_CANCEL + */ + public static final int CONTENT_CHANGE_TYPE_DRAG_CANCELLED = 0x0000200; + /** * Change type for {@link #TYPE_WINDOWS_CHANGED} event: * The window was added. @@ -710,7 +740,10 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par CONTENT_CHANGE_TYPE_STATE_DESCRIPTION, CONTENT_CHANGE_TYPE_PANE_TITLE, CONTENT_CHANGE_TYPE_PANE_APPEARED, - CONTENT_CHANGE_TYPE_PANE_DISAPPEARED + CONTENT_CHANGE_TYPE_PANE_DISAPPEARED, + CONTENT_CHANGE_TYPE_DRAG_STARTED, + CONTENT_CHANGE_TYPE_DRAG_DROPPED, + CONTENT_CHANGE_TYPE_DRAG_CANCELLED }) public @interface ContentChangeTypes {} @@ -959,6 +992,9 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par case CONTENT_CHANGE_TYPE_PANE_APPEARED: return "CONTENT_CHANGE_TYPE_PANE_APPEARED"; case CONTENT_CHANGE_TYPE_PANE_DISAPPEARED: return "CONTENT_CHANGE_TYPE_PANE_DISAPPEARED"; + case CONTENT_CHANGE_TYPE_DRAG_STARTED: return "CONTENT_CHANGE_TYPE_DRAG_STARTED"; + case CONTENT_CHANGE_TYPE_DRAG_DROPPED: return "CONTENT_CHANGE_TYPE_DRAG_DROPPED"; + case CONTENT_CHANGE_TYPE_DRAG_CANCELLED: return "CONTENT_CHANGE_TYPE_DRAG_CANCELLED"; default: return Integer.toHexString(type); } } @@ -1017,6 +1053,7 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par /** * Sets the event type. * + * Note: An event must represent a single event type. * @param eventType The event type. * * @throws IllegalStateException If called from an AccessibilityService. diff --git a/core/java/android/view/accessibility/AccessibilityInteractionClient.java b/core/java/android/view/accessibility/AccessibilityInteractionClient.java index dd81dd93380b..aac09b8a3b57 100644 --- a/core/java/android/view/accessibility/AccessibilityInteractionClient.java +++ b/core/java/android/view/accessibility/AccessibilityInteractionClient.java @@ -16,6 +16,9 @@ package android.view.accessibility; +import static android.accessibilityservice.AccessibilityTrace.FLAGS_ACCESSIBILITY_INTERACTION_CLIENT; +import static android.accessibilityservice.AccessibilityTrace.FLAGS_ACCESSIBILITY_INTERACTION_CONNECTION_CALLBACK; + import android.accessibilityservice.IAccessibilityServiceConnection; import android.annotation.NonNull; import android.annotation.Nullable; @@ -86,6 +89,7 @@ public final class AccessibilityInteractionClient public static final int NO_ID = -1; public static final String CALL_STACK = "call_stack"; + public static final String IGNORE_CALL_STACK = "ignore_call_stack"; private static final String LOG_TAG = "AccessibilityInteractionClient"; @@ -121,6 +125,12 @@ public final class AccessibilityInteractionClient private volatile int mInteractionId = -1; private volatile int mCallingUid = Process.INVALID_UID; + // call stack for IAccessibilityInteractionConnectionCallback APIs. These callback APIs are + // shared by multiple requests APIs in IAccessibilityServiceConnection. To correctly log the + // request API which triggers the callback, we log trace entries for callback after the + // request API thread waiting for the callback returns. To log the correct callback stack in + // the request API thread, we save the callback stack in this member variables. + private List mCallStackOfCallback; private AccessibilityNodeInfo mFindAccessibilityNodeInfoResult; @@ -307,18 +317,30 @@ public final class AccessibilityInteractionClient if (DEBUG) { Log.i(LOG_TAG, "Window cache hit"); } + if (shouldTraceClient()) { + logTraceClient(connection, "getWindow cache", + "connectionId=" + connectionId + ";accessibilityWindowId=" + + accessibilityWindowId + ";bypassCache=false"); + } return window; } if (DEBUG) { Log.i(LOG_TAG, "Window cache miss"); } } + final long identityToken = Binder.clearCallingIdentity(); try { window = connection.getWindow(accessibilityWindowId); } finally { Binder.restoreCallingIdentity(identityToken); } + if (shouldTraceClient()) { + logTraceClient(connection, "getWindow", "connectionId=" + connectionId + + ";accessibilityWindowId=" + accessibilityWindowId + ";bypassCache=" + + bypassCache); + } + if (window != null) { if (!bypassCache) { sAccessibilityCache.addWindow(window); @@ -368,6 +390,10 @@ public final class AccessibilityInteractionClient if (DEBUG) { Log.i(LOG_TAG, "Windows cache hit"); } + if (shouldTraceClient()) { + logTraceClient( + connection, "getWindows cache", "connectionId=" + connectionId); + } return windows; } if (DEBUG) { @@ -379,6 +405,9 @@ public final class AccessibilityInteractionClient } finally { Binder.restoreCallingIdentity(identityToken); } + if (shouldTraceClient()) { + logTraceClient(connection, "getWindows", "connectionId=" + connectionId); + } if (windows != null) { sAccessibilityCache.setWindowsOnAllDisplays(windows); return windows; @@ -472,6 +501,15 @@ public final class AccessibilityInteractionClient Log.i(LOG_TAG, "Node cache hit for " + idToString(accessibilityWindowId, accessibilityNodeId)); } + if (shouldTraceClient()) { + logTraceClient(connection, + "findAccessibilityNodeInfoByAccessibilityId cache", + "connectionId=" + connectionId + ";accessibilityWindowId=" + + accessibilityWindowId + ";accessibilityNodeId=" + + accessibilityNodeId + ";bypassCache=" + bypassCache + + ";prefetchFlags=" + prefetchFlags + ";arguments=" + + arguments); + } return cachedInfo; } if (DEBUG) { @@ -488,6 +526,14 @@ public final class AccessibilityInteractionClient prefetchFlags &= ~AccessibilityNodeInfo.FLAG_PREFETCH_MASK; } final int interactionId = mInteractionIdCounter.getAndIncrement(); + if (shouldTraceClient()) { + logTraceClient(connection, "findAccessibilityNodeInfoByAccessibilityId", + "InteractionId:" + interactionId + "connectionId=" + connectionId + + ";accessibilityWindowId=" + accessibilityWindowId + + ";accessibilityNodeId=" + accessibilityNodeId + ";bypassCache=" + + bypassCache + ";prefetchFlags=" + prefetchFlags + ";arguments=" + + arguments); + } final String[] packageNames; final long identityToken = Binder.clearCallingIdentity(); try { @@ -500,16 +546,10 @@ public final class AccessibilityInteractionClient if (packageNames != null) { AccessibilityNodeInfo info = getFindAccessibilityNodeInfoResultAndClear(interactionId); - if (mAccessibilityManager != null - && mAccessibilityManager.isAccessibilityTracingEnabled()) { - logTrace(connection, "findAccessibilityNodeInfoByAccessibilityId", - "InteractionId:" + interactionId + ";Result: " + info - + ";connectionId=" + connectionId - + ";accessibilityWindowId=" - + accessibilityWindowId + ";accessibilityNodeId=" - + accessibilityNodeId + ";bypassCache=" + bypassCache - + ";prefetchFlags=" + prefetchFlags - + ";arguments=" + arguments); + if (shouldTraceCallback()) { + logTraceCallback(connection, "findAccessibilityNodeInfoByAccessibilityId", + "InteractionId:" + interactionId + ";connectionId=" + + connectionId + ";Result: " + info); } if ((prefetchFlags & AccessibilityNodeInfo.FLAG_PREFETCH_MASK) != 0 && info != null) { @@ -571,6 +611,14 @@ public final class AccessibilityInteractionClient final String[] packageNames; final long identityToken = Binder.clearCallingIdentity(); try { + if (shouldTraceClient()) { + logTraceClient(connection, "findAccessibilityNodeInfosByViewId", + "InteractionId=" + interactionId + ";connectionId=" + connectionId + + ";accessibilityWindowId=" + accessibilityWindowId + + ";accessibilityNodeId=" + accessibilityNodeId + ";viewId=" + + viewId); + } + packageNames = connection.findAccessibilityNodeInfosByViewId( accessibilityWindowId, accessibilityNodeId, viewId, interactionId, this, Thread.currentThread().getId()); @@ -581,13 +629,10 @@ public final class AccessibilityInteractionClient if (packageNames != null) { List infos = getFindAccessibilityNodeInfosResultAndClear( interactionId); - if (mAccessibilityManager != null - && mAccessibilityManager.isAccessibilityTracingEnabled()) { - logTrace(connection, "findAccessibilityNodeInfosByViewId", "InteractionId=" - + interactionId + ":Result: " + infos + ";connectionId=" - + connectionId + ";accessibilityWindowId=" + accessibilityWindowId - + ";accessibilityNodeId=" + accessibilityNodeId + ";viewId=" - + viewId); + if (shouldTraceCallback()) { + logTraceCallback(connection, "findAccessibilityNodeInfosByViewId", + "InteractionId=" + interactionId + ";connectionId=" + connectionId + + ":Result: " + infos); } if (infos != null) { finalizeAndCacheAccessibilityNodeInfos(infos, connectionId, @@ -630,6 +675,12 @@ public final class AccessibilityInteractionClient IAccessibilityServiceConnection connection = getConnection(connectionId); if (connection != null) { final int interactionId = mInteractionIdCounter.getAndIncrement(); + if (shouldTraceClient()) { + logTraceClient(connection, "findAccessibilityNodeInfosByText", + "InteractionId:" + interactionId + "connectionId=" + connectionId + + ";accessibilityWindowId=" + accessibilityWindowId + + ";accessibilityNodeId=" + accessibilityNodeId + ";text=" + text); + } final String[] packageNames; final long identityToken = Binder.clearCallingIdentity(); try { @@ -643,12 +694,10 @@ public final class AccessibilityInteractionClient if (packageNames != null) { List infos = getFindAccessibilityNodeInfosResultAndClear( interactionId); - if (mAccessibilityManager != null - && mAccessibilityManager.isAccessibilityTracingEnabled()) { - logTrace(connection, "findAccessibilityNodeInfosByText", "InteractionId=" - + interactionId + ":Result: " + infos + ";connectionId=" - + connectionId + ";accessibilityWindowId=" + accessibilityWindowId - + ";accessibilityNodeId=" + accessibilityNodeId + ";text=" + text); + if (shouldTraceCallback()) { + logTraceCallback(connection, "findAccessibilityNodeInfosByText", + "InteractionId=" + interactionId + ";connectionId=" + connectionId + + ";Result: " + infos); } if (infos != null) { finalizeAndCacheAccessibilityNodeInfos(infos, connectionId, @@ -690,6 +739,13 @@ public final class AccessibilityInteractionClient IAccessibilityServiceConnection connection = getConnection(connectionId); if (connection != null) { final int interactionId = mInteractionIdCounter.getAndIncrement(); + if (shouldTraceClient()) { + logTraceClient(connection, "findFocus", + "InteractionId:" + interactionId + "connectionId=" + connectionId + + ";accessibilityWindowId=" + accessibilityWindowId + + ";accessibilityNodeId=" + accessibilityNodeId + ";focusType=" + + focusType); + } final String[] packageNames; final long identityToken = Binder.clearCallingIdentity(); try { @@ -703,13 +759,9 @@ public final class AccessibilityInteractionClient if (packageNames != null) { AccessibilityNodeInfo info = getFindAccessibilityNodeInfoResultAndClear( interactionId); - if (mAccessibilityManager != null - && mAccessibilityManager.isAccessibilityTracingEnabled()) { - logTrace(connection, "findFocus", "InteractionId=" + interactionId - + ":Result: " + info + ";connectionId=" + connectionId - + ";accessibilityWindowId=" + accessibilityWindowId - + ";accessibilityNodeId=" + accessibilityNodeId + ";focusType=" - + focusType); + if (shouldTraceCallback()) { + logTraceCallback(connection, "findFocus", "InteractionId=" + interactionId + + ";connectionId=" + connectionId + ";Result:" + info); } finalizeAndCacheAccessibilityNodeInfo(info, connectionId, false, packageNames); return info; @@ -747,6 +799,13 @@ public final class AccessibilityInteractionClient IAccessibilityServiceConnection connection = getConnection(connectionId); if (connection != null) { final int interactionId = mInteractionIdCounter.getAndIncrement(); + if (shouldTraceClient()) { + logTraceClient(connection, "focusSearch", + "InteractionId:" + interactionId + "connectionId=" + connectionId + + ";accessibilityWindowId=" + accessibilityWindowId + + ";accessibilityNodeId=" + accessibilityNodeId + ";direction=" + + direction); + } final String[] packageNames; final long identityToken = Binder.clearCallingIdentity(); try { @@ -761,13 +820,9 @@ public final class AccessibilityInteractionClient AccessibilityNodeInfo info = getFindAccessibilityNodeInfoResultAndClear( interactionId); finalizeAndCacheAccessibilityNodeInfo(info, connectionId, false, packageNames); - if (mAccessibilityManager != null - && mAccessibilityManager.isAccessibilityTracingEnabled()) { - logTrace(connection, "focusSearch", "InteractionId=" + interactionId - + ":Result: " + info + ";connectionId=" + connectionId - + ";accessibilityWindowId=" + accessibilityWindowId - + ";accessibilityNodeId=" + accessibilityNodeId + ";direction=" - + direction); + if (shouldTraceCallback()) { + logTraceCallback(connection, "focusSearch", "InteractionId=" + interactionId + + ";connectionId=" + connectionId + ";Result:" + info); } return info; } @@ -803,6 +858,13 @@ public final class AccessibilityInteractionClient IAccessibilityServiceConnection connection = getConnection(connectionId); if (connection != null) { final int interactionId = mInteractionIdCounter.getAndIncrement(); + if (shouldTraceClient()) { + logTraceClient(connection, "performAccessibilityAction", + "InteractionId:" + interactionId + "connectionId=" + connectionId + + ";accessibilityWindowId=" + accessibilityWindowId + + ";accessibilityNodeId=" + accessibilityNodeId + ";action=" + action + + ";arguments=" + arguments); + } final boolean success; final long identityToken = Binder.clearCallingIdentity(); try { @@ -816,13 +878,10 @@ public final class AccessibilityInteractionClient if (success) { final boolean result = getPerformAccessibilityActionResultAndClear(interactionId); - if (mAccessibilityManager != null - && mAccessibilityManager.isAccessibilityTracingEnabled()) { - logTrace(connection, "performAccessibilityAction", "InteractionId=" - + interactionId + ":Result: " + result + ";connectionId=" - + connectionId + ";accessibilityWindowId=" + accessibilityWindowId - + ";accessibilityNodeId=" + accessibilityNodeId + ";action=" - + action + ";arguments=" + arguments); + if (shouldTraceCallback()) { + logTraceCallback(connection, "performAccessibilityAction", + "InteractionId=" + interactionId + ";connectionId=" + connectionId + + ";Result: " + result); } return result; } @@ -886,6 +945,8 @@ public final class AccessibilityInteractionClient mFindAccessibilityNodeInfoResult = info; mInteractionId = interactionId; mCallingUid = Binder.getCallingUid(); + mCallStackOfCallback = new ArrayList( + Arrays.asList(Thread.currentThread().getStackTrace())); } mInstanceLock.notifyAll(); } @@ -936,6 +997,8 @@ public final class AccessibilityInteractionClient } mInteractionId = interactionId; mCallingUid = Binder.getCallingUid(); + mCallStackOfCallback = new ArrayList( + Arrays.asList(Thread.currentThread().getStackTrace())); } mInstanceLock.notifyAll(); } @@ -975,13 +1038,15 @@ public final class AccessibilityInteractionClient finalizeAndCacheAccessibilityNodeInfos( infos, connectionIdWaitingForPrefetchResultCopy, false, packageNamesForNextPrefetchResultCopy); - if (mAccessibilityManager != null - && mAccessibilityManager.isAccessibilityTracingEnabled()) { + if (shouldTraceCallback()) { logTrace(getConnection(connectionIdWaitingForPrefetchResultCopy), "setPrefetchAccessibilityNodeInfoResult", - "InteractionId:" + interactionId + ";Result: " + infos - + ";connectionId=" + connectionIdWaitingForPrefetchResultCopy, - Binder.getCallingUid()); + "InteractionId:" + interactionId + ";connectionId=" + + connectionIdWaitingForPrefetchResultCopy + ";Result: " + infos, + Binder.getCallingUid(), + Arrays.asList(Thread.currentThread().getStackTrace()), + new HashSet(Arrays.asList("getStackTrace")), + FLAGS_ACCESSIBILITY_INTERACTION_CONNECTION_CALLBACK); } } else if (DEBUG) { Log.w(LOG_TAG, "Prefetching for interaction with id " + interactionId + " dropped " @@ -1013,6 +1078,8 @@ public final class AccessibilityInteractionClient mPerformAccessibilityActionResult = succeeded; mInteractionId = interactionId; mCallingUid = Binder.getCallingUid(); + mCallStackOfCallback = new ArrayList( + Arrays.asList(Thread.currentThread().getStackTrace())); } mInstanceLock.notifyAll(); } @@ -1222,24 +1289,45 @@ public final class AccessibilityInteractionClient return true; } + private boolean shouldTraceClient() { + return (mAccessibilityManager != null) + && mAccessibilityManager.isA11yInteractionClientTraceEnabled(); + } + + private boolean shouldTraceCallback() { + return (mAccessibilityManager != null) + && mAccessibilityManager.isA11yInteractionConnectionCBTraceEnabled(); + } + private void logTrace( IAccessibilityServiceConnection connection, String method, String params, - int callingUid) { + int callingUid, List callStack, HashSet ignoreSet, + long logTypes) { try { Bundle b = new Bundle(); - ArrayList callStack = new ArrayList( - Arrays.asList(Thread.currentThread().getStackTrace())); - b.putSerializable(CALL_STACK, callStack); + b.putSerializable(CALL_STACK, new ArrayList(callStack)); + if (ignoreSet != null) { + b.putSerializable(IGNORE_CALL_STACK, ignoreSet); + } connection.logTrace(SystemClock.elapsedRealtimeNanos(), - LOG_TAG + ".callback for " + method, params, Process.myPid(), - Thread.currentThread().getId(), callingUid, b); + LOG_TAG + "." + method, + logTypes, params, Process.myPid(), Thread.currentThread().getId(), + callingUid, b); } catch (RemoteException e) { Log.e(LOG_TAG, "Failed to log trace. " + e); } } - private void logTrace( + private void logTraceCallback( + IAccessibilityServiceConnection connection, String method, String params) { + logTrace(connection, method + " callback", params, mCallingUid, mCallStackOfCallback, + new HashSet(Arrays.asList("getStackTrace")), + FLAGS_ACCESSIBILITY_INTERACTION_CONNECTION_CALLBACK); + } + + private void logTraceClient( IAccessibilityServiceConnection connection, String method, String params) { - logTrace(connection, method, params, mCallingUid); + logTrace(connection, method, params, Binder.getCallingUid(), + Collections.emptyList(), null, FLAGS_ACCESSIBILITY_INTERACTION_CLIENT); } } diff --git a/core/java/android/view/accessibility/AccessibilityManager.java b/core/java/android/view/accessibility/AccessibilityManager.java index f9cdbd322c26..17fad7e57de7 100644 --- a/core/java/android/view/accessibility/AccessibilityManager.java +++ b/core/java/android/view/accessibility/AccessibilityManager.java @@ -111,7 +111,13 @@ public final class AccessibilityManager { public static final int STATE_FLAG_REQUEST_MULTI_FINGER_GESTURES = 0x00000010; /** @hide */ - public static final int STATE_FLAG_ACCESSIBILITY_TRACING_ENABLED = 0x00000020; + public static final int STATE_FLAG_TRACE_A11Y_INTERACTION_CONNECTION_ENABLED = 0x00000100; + /** @hide */ + public static final int STATE_FLAG_TRACE_A11Y_INTERACTION_CONNECTION_CB_ENABLED = 0x00000200; + /** @hide */ + public static final int STATE_FLAG_TRACE_A11Y_INTERACTION_CLIENT_ENABLED = 0x00000400; + /** @hide */ + public static final int STATE_FLAG_TRACE_A11Y_SERVICE_ENABLED = 0x00000800; /** @hide */ public static final int DALTONIZER_DISABLED = -1; @@ -235,8 +241,8 @@ public final class AccessibilityManager { @UnsupportedAppUsage(trackingBug = 123768939L) boolean mIsHighTextContrastEnabled; - // Whether accessibility tracing is enabled or not - boolean mIsAccessibilityTracingEnabled = false; + // accessibility tracing state + int mAccessibilityTracingState = 0; AccessibilityPolicy mAccessibilityPolicy; @@ -1029,13 +1035,50 @@ public final class AccessibilityManager { } /** - * Gets accessibility tracing enabled state. + * Gets accessibility interaction connection tracing enabled state. + * + * @hide + */ + public boolean isA11yInteractionConnectionTraceEnabled() { + synchronized (mLock) { + return ((mAccessibilityTracingState + & STATE_FLAG_TRACE_A11Y_INTERACTION_CONNECTION_ENABLED) != 0); + } + } + + /** + * Gets accessibility interaction connection callback tracing enabled state. + * + * @hide + */ + public boolean isA11yInteractionConnectionCBTraceEnabled() { + synchronized (mLock) { + return ((mAccessibilityTracingState + & STATE_FLAG_TRACE_A11Y_INTERACTION_CONNECTION_CB_ENABLED) != 0); + } + } + + /** + * Gets accessibility interaction client tracing enabled state. + * + * @hide + */ + public boolean isA11yInteractionClientTraceEnabled() { + synchronized (mLock) { + return ((mAccessibilityTracingState + & STATE_FLAG_TRACE_A11Y_INTERACTION_CLIENT_ENABLED) != 0); + } + } + + /** + * Gets accessibility service tracing enabled state. * * @hide */ - public boolean isAccessibilityTracingEnabled() { + public boolean isA11yServiceTraceEnabled() { synchronized (mLock) { - return mIsAccessibilityTracingEnabled; + return ((mAccessibilityTracingState + & STATE_FLAG_TRACE_A11Y_SERVICE_ENABLED) != 0); } } @@ -1233,8 +1276,6 @@ public final class AccessibilityManager { (stateFlags & STATE_FLAG_TOUCH_EXPLORATION_ENABLED) != 0; final boolean highTextContrastEnabled = (stateFlags & STATE_FLAG_HIGH_TEXT_CONTRAST_ENABLED) != 0; - final boolean accessibilityTracingEnabled = - (stateFlags & STATE_FLAG_ACCESSIBILITY_TRACING_ENABLED) != 0; final boolean wasEnabled = isEnabled(); final boolean wasTouchExplorationEnabled = mIsTouchExplorationEnabled; @@ -1257,7 +1298,7 @@ public final class AccessibilityManager { notifyHighTextContrastStateChanged(); } - updateAccessibilityTracingState(accessibilityTracingEnabled); + updateAccessibilityTracingState(stateFlags); } /** @@ -1715,11 +1756,11 @@ public final class AccessibilityManager { } /** - * Update mIsAccessibilityTracingEnabled. + * Update mAccessibilityTracingState. */ - private void updateAccessibilityTracingState(boolean enabled) { + private void updateAccessibilityTracingState(int stateFlag) { synchronized (mLock) { - mIsAccessibilityTracingEnabled = enabled; + mAccessibilityTracingState = stateFlag; } } diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java index 085eb81182f1..587a27074544 100644 --- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java +++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java @@ -27,6 +27,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.TestApi; import android.compat.annotation.UnsupportedAppUsage; +import android.content.ClipData; import android.graphics.Rect; import android.graphics.Region; import android.os.Build; @@ -4353,6 +4354,14 @@ public class AccessibilityNodeInfo implements Parcelable { case R.id.accessibilityActionImeEnter: return "ACTION_IME_ENTER"; default: + // TODO(197520937): Use finalized constants in switch + if (action == R.id.accessibilityActionDragStart) { + return "ACTION_DRAG"; + } else if (action == R.id.accessibilityActionDragCancel) { + return "ACTION_CANCEL_DRAG"; + } else if (action == R.id.accessibilityActionDragDrop) { + return "ACTION_DROP"; + } return "ACTION_UNKNOWN"; } } @@ -4995,6 +5004,46 @@ public class AccessibilityNodeInfo implements Parcelable { @NonNull public static final AccessibilityAction ACTION_IME_ENTER = new AccessibilityAction(R.id.accessibilityActionImeEnter); + /** + * Action to start a drag. + *

    + * This action initiates a drag & drop within the system. The source's dragged content is + * prepared before the drag begins. In View, this action should prepare the arguments to + * {@link View#startDragAndDrop(ClipData, View.DragShadowBuilder, Object, int)} and then + * call {@link View#startDragAndDrop(ClipData, View.DragShadowBuilder, Object, int)}. The + * equivalent should be performed for other UI toolkits. + *

    + * + * @see AccessibilityEvent#CONTENT_CHANGE_TYPE_DRAG_STARTED + */ + @NonNull public static final AccessibilityAction ACTION_DRAG_START = + new AccessibilityAction(R.id.accessibilityActionDragStart); + + /** + * Action to trigger a drop of the content being dragged. + *

    + * This action is added to potential drop targets if the source started a drag with + * {@link #ACTION_DRAG_START}. In View, these targets are Views that accepted + * {@link android.view.DragEvent#ACTION_DRAG_STARTED} and have an + * {@link View.OnDragListener}. + *

    + * + * @see AccessibilityEvent#CONTENT_CHANGE_TYPE_DRAG_DROPPED + */ + @NonNull public static final AccessibilityAction ACTION_DRAG_DROP = + new AccessibilityAction(R.id.accessibilityActionDragDrop); + + /** + * Action to cancel a drag. + *

    + * This action is added to the source that started a drag with {@link #ACTION_DRAG_START}. + *

    + * + * @see AccessibilityEvent#CONTENT_CHANGE_TYPE_DRAG_CANCELLED + */ + @NonNull public static final AccessibilityAction ACTION_DRAG_CANCEL = + new AccessibilityAction(R.id.accessibilityActionDragCancel); + private final int mActionId; private final CharSequence mLabel; diff --git a/core/java/android/view/accessibility/AccessibilityWindowInfo.java b/core/java/android/view/accessibility/AccessibilityWindowInfo.java index edcb59a79c70..76e226163ca1 100644 --- a/core/java/android/view/accessibility/AccessibilityWindowInfo.java +++ b/core/java/android/view/accessibility/AccessibilityWindowInfo.java @@ -19,6 +19,7 @@ package android.view.accessibility; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.TestApi; +import android.app.ActivityTaskManager; import android.graphics.Rect; import android.graphics.Region; import android.os.Parcel; @@ -114,6 +115,7 @@ public final class AccessibilityWindowInfo implements Parcelable { private int mBooleanProperties; private int mId = UNDEFINED_WINDOW_ID; private int mParentId = UNDEFINED_WINDOW_ID; + private int mTaskId = ActivityTaskManager.INVALID_TASK_ID; private Region mRegionInScreen = new Region(); private LongArray mChildIds; private CharSequence mTitle; @@ -306,6 +308,28 @@ public final class AccessibilityWindowInfo implements Parcelable { mId = id; } + /** + * Gets the task ID. + * + * @return The task ID. + * + * @hide + */ + public int getTaskId() { + return mTaskId; + } + + /** + * Sets the task ID. + * + * @param taskId The task ID. + * + * @hide + */ + public void setTaskId(int taskId) { + mTaskId = taskId; + } + /** * Sets the unique id of the IAccessibilityServiceConnection over which * this instance can send requests to the system. @@ -578,6 +602,7 @@ public final class AccessibilityWindowInfo implements Parcelable { parcel.writeInt(mBooleanProperties); parcel.writeInt(mId); parcel.writeInt(mParentId); + parcel.writeInt(mTaskId); mRegionInScreen.writeToParcel(parcel, flags); parcel.writeCharSequence(mTitle); parcel.writeLong(mAnchorId); @@ -608,6 +633,7 @@ public final class AccessibilityWindowInfo implements Parcelable { mBooleanProperties = other.mBooleanProperties; mId = other.mId; mParentId = other.mParentId; + mTaskId = other.mTaskId; mRegionInScreen.set(other.mRegionInScreen); mTitle = other.mTitle; mAnchorId = other.mAnchorId; @@ -631,6 +657,7 @@ public final class AccessibilityWindowInfo implements Parcelable { mBooleanProperties = parcel.readInt(); mId = parcel.readInt(); mParentId = parcel.readInt(); + mTaskId = parcel.readInt(); mRegionInScreen = Region.CREATOR.createFromParcel(parcel); mTitle = parcel.readCharSequence(); mAnchorId = parcel.readLong(); @@ -676,6 +703,7 @@ public final class AccessibilityWindowInfo implements Parcelable { builder.append("title=").append(mTitle); builder.append(", displayId=").append(mDisplayId); builder.append(", id=").append(mId); + builder.append(", taskId=").append(mTaskId); builder.append(", type=").append(typeToString(mType)); builder.append(", layer=").append(mLayer); builder.append(", region=").append(mRegionInScreen); @@ -719,6 +747,7 @@ public final class AccessibilityWindowInfo implements Parcelable { mBooleanProperties = 0; mId = UNDEFINED_WINDOW_ID; mParentId = UNDEFINED_WINDOW_ID; + mTaskId = ActivityTaskManager.INVALID_TASK_ID; mRegionInScreen.setEmpty(); mChildIds = null; mConnectionId = UNDEFINED_WINDOW_ID; diff --git a/core/java/android/view/contentcapture/ContentCaptureContext.java b/core/java/android/view/contentcapture/ContentCaptureContext.java index 9998fbc02d12..0da54e57ed79 100644 --- a/core/java/android/view/contentcapture/ContentCaptureContext.java +++ b/core/java/android/view/contentcapture/ContentCaptureContext.java @@ -27,6 +27,7 @@ import android.content.ComponentName; import android.content.Context; import android.content.LocusId; import android.os.Bundle; +import android.os.IBinder; import android.os.Parcel; import android.os.Parcelable; import android.view.Display; @@ -105,6 +106,7 @@ public final class ContentCaptureContext implements Parcelable { private final int mFlags; private final int mDisplayId; private final ActivityId mActivityId; + private final IBinder mWindowToken; // Fields below are set by the service upon "delivery" and are not marshalled in the parcel private int mParentSessionId = NO_SESSION_ID; @@ -112,7 +114,7 @@ public final class ContentCaptureContext implements Parcelable { /** @hide */ public ContentCaptureContext(@Nullable ContentCaptureContext clientContext, @NonNull ActivityId activityId, @NonNull ComponentName componentName, int displayId, - int flags) { + IBinder windowToken, int flags) { if (clientContext != null) { mHasClientContext = true; mExtras = clientContext.mExtras; @@ -126,6 +128,7 @@ public final class ContentCaptureContext implements Parcelable { mFlags = flags; mDisplayId = displayId; mActivityId = activityId; + mWindowToken = windowToken; } private ContentCaptureContext(@NonNull Builder builder) { @@ -137,6 +140,7 @@ public final class ContentCaptureContext implements Parcelable { mFlags = 0; mDisplayId = Display.INVALID_DISPLAY; mActivityId = null; + mWindowToken = null; } /** @hide */ @@ -148,6 +152,7 @@ public final class ContentCaptureContext implements Parcelable { mFlags = original.mFlags | extraFlags; mDisplayId = original.mDisplayId; mActivityId = original.mActivityId; + mWindowToken = original.mWindowToken; } /** @@ -229,6 +234,20 @@ public final class ContentCaptureContext implements Parcelable { return mDisplayId; } + /** + * Gets the window token of the activity associated with this context. + * + *

    The token can be used to attach relevant overlay views to the activity's window. This can + * be done through {@link android.view.WindowManager.LayoutParams#token}. + * + * @hide + */ + @SystemApi + @Nullable + public IBinder getWindowToken() { + return mWindowToken; + } + /** * Gets the flags associated with this context. * @@ -328,6 +347,7 @@ public final class ContentCaptureContext implements Parcelable { } pw.print(", activityId="); pw.print(mActivityId); pw.print(", displayId="); pw.print(mDisplayId); + pw.print(", windowToken="); pw.print(mWindowToken); if (mParentSessionId != NO_SESSION_ID) { pw.print(", parentId="); pw.print(mParentSessionId); } @@ -352,6 +372,7 @@ public final class ContentCaptureContext implements Parcelable { builder.append("act=").append(ComponentName.flattenToShortString(mComponentName)) .append(", activityId=").append(mActivityId) .append(", displayId=").append(mDisplayId) + .append(", windowToken=").append(mWindowToken) .append(", flags=").append(mFlags); } else { builder.append("id=").append(mId); @@ -381,6 +402,7 @@ public final class ContentCaptureContext implements Parcelable { parcel.writeParcelable(mComponentName, flags); if (fromServer()) { parcel.writeInt(mDisplayId); + parcel.writeStrongBinder(mWindowToken); parcel.writeInt(mFlags); mActivityId.writeToParcel(parcel, flags); } @@ -411,11 +433,12 @@ public final class ContentCaptureContext implements Parcelable { return clientContext; } else { final int displayId = parcel.readInt(); + final IBinder windowToken = parcel.readStrongBinder(); final int flags = parcel.readInt(); final ActivityId activityId = new ActivityId(parcel); return new ContentCaptureContext(clientContext, activityId, componentName, - displayId, flags); + displayId, windowToken, flags); } } diff --git a/core/java/android/view/contentcapture/ContentCaptureEvent.java b/core/java/android/view/contentcapture/ContentCaptureEvent.java index ce6d034c585e..4b2d3a97bed2 100644 --- a/core/java/android/view/contentcapture/ContentCaptureEvent.java +++ b/core/java/android/view/contentcapture/ContentCaptureEvent.java @@ -24,6 +24,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; import android.graphics.Insets; +import android.graphics.Rect; import android.os.Parcel; import android.os.Parcelable; import android.text.Selection; @@ -122,6 +123,12 @@ public final class ContentCaptureEvent implements Parcelable { */ public static final int TYPE_VIEW_INSETS_CHANGED = 9; + /** + * Called before {@link #TYPE_VIEW_TREE_APPEARING}, or after the size of the window containing + * the views changed. + */ + public static final int TYPE_WINDOW_BOUNDS_CHANGED = 10; + /** @hide */ @IntDef(prefix = { "TYPE_" }, value = { TYPE_VIEW_APPEARED, @@ -132,7 +139,8 @@ public final class ContentCaptureEvent implements Parcelable { TYPE_CONTEXT_UPDATED, TYPE_SESSION_PAUSED, TYPE_SESSION_RESUMED, - TYPE_VIEW_INSETS_CHANGED + TYPE_VIEW_INSETS_CHANGED, + TYPE_WINDOW_BOUNDS_CHANGED, }) @Retention(RetentionPolicy.SOURCE) public @interface EventType{} @@ -150,6 +158,7 @@ public final class ContentCaptureEvent implements Parcelable { private int mParentSessionId = NO_SESSION_ID; private @Nullable ContentCaptureContext mClientContext; private @Nullable Insets mInsets; + private @Nullable Rect mBounds; private int mComposingStart = MAX_INVALID_VALUE; private int mComposingEnd = MAX_INVALID_VALUE; @@ -346,6 +355,13 @@ public final class ContentCaptureEvent implements Parcelable { return this; } + /** @hide */ + @NonNull + public ContentCaptureEvent setBounds(@NonNull Rect bounds) { + mBounds = bounds; + return this; + } + /** * Gets the type of the event. * @@ -418,6 +434,16 @@ public final class ContentCaptureEvent implements Parcelable { return mInsets; } + /** + * Gets the {@link Rect} bounds of the window associated with the event. Valid bounds will only + * be returned if the type of the event is {@link #TYPE_WINDOW_BOUNDS_CHANGED}, otherwise they + * will be null. + */ + @Nullable + public Rect getBounds() { + return mBounds; + } + /** * Merges event of the same type, either {@link #TYPE_VIEW_TEXT_CHANGED} * or {@link #TYPE_VIEW_DISAPPEARED}. @@ -489,6 +515,9 @@ public final class ContentCaptureEvent implements Parcelable { if (mInsets != null) { pw.print(", insets="); pw.println(mInsets); } + if (mBounds != null) { + pw.print(", bounds="); pw.println(mBounds); + } if (mComposingStart > MAX_INVALID_VALUE) { pw.print(", composing("); pw.print(mComposingStart); pw.print(", "); pw.print(mComposingEnd); pw.print(")"); @@ -533,6 +562,9 @@ public final class ContentCaptureEvent implements Parcelable { if (mInsets != null) { string.append(", insets=").append(mInsets); } + if (mBounds != null) { + string.append(", bounds=").append(mBounds); + } if (mComposingStart > MAX_INVALID_VALUE) { string.append(", composing=[") .append(mComposingStart).append(",").append(mComposingEnd).append("]"); @@ -568,6 +600,9 @@ public final class ContentCaptureEvent implements Parcelable { if (mType == TYPE_VIEW_INSETS_CHANGED) { parcel.writeParcelable(mInsets, flags); } + if (mType == TYPE_WINDOW_BOUNDS_CHANGED) { + parcel.writeParcelable(mBounds, flags); + } if (mType == TYPE_VIEW_TEXT_CHANGED) { parcel.writeInt(mComposingStart); parcel.writeInt(mComposingEnd); @@ -608,6 +643,9 @@ public final class ContentCaptureEvent implements Parcelable { if (type == TYPE_VIEW_INSETS_CHANGED) { event.setInsets(parcel.readParcelable(null)); } + if (type == TYPE_WINDOW_BOUNDS_CHANGED) { + event.setBounds(parcel.readParcelable(null)); + } if (type == TYPE_VIEW_TEXT_CHANGED) { event.setComposingIndex(parcel.readInt(), parcel.readInt()); event.restoreComposingSpan(); @@ -649,6 +687,8 @@ public final class ContentCaptureEvent implements Parcelable { return "CONTEXT_UPDATED"; case TYPE_VIEW_INSETS_CHANGED: return "VIEW_INSETS_CHANGED"; + case TYPE_WINDOW_BOUNDS_CHANGED: + return "TYPE_WINDOW_BOUNDS_CHANGED"; default: return "UKNOWN_TYPE: " + type; } diff --git a/core/java/android/view/contentcapture/ContentCaptureManager.java b/core/java/android/view/contentcapture/ContentCaptureManager.java index 9241c3074ddd..cd3c8c9c48f2 100644 --- a/core/java/android/view/contentcapture/ContentCaptureManager.java +++ b/core/java/android/view/contentcapture/ContentCaptureManager.java @@ -483,6 +483,8 @@ public final class ContentCaptureManager { /** * Returns the component name of the system service that is consuming the captured events for * the current user. + * + * @throws RuntimeException if getting the component name is timed out. */ @Nullable public ComponentName getServiceComponentName() { diff --git a/core/java/android/view/contentcapture/MainContentCaptureSession.java b/core/java/android/view/contentcapture/MainContentCaptureSession.java index 4cf553207b6e..98ef4e7ae6fa 100644 --- a/core/java/android/view/contentcapture/MainContentCaptureSession.java +++ b/core/java/android/view/contentcapture/MainContentCaptureSession.java @@ -26,6 +26,7 @@ import static android.view.contentcapture.ContentCaptureEvent.TYPE_VIEW_INSETS_C import static android.view.contentcapture.ContentCaptureEvent.TYPE_VIEW_TEXT_CHANGED; import static android.view.contentcapture.ContentCaptureEvent.TYPE_VIEW_TREE_APPEARED; import static android.view.contentcapture.ContentCaptureEvent.TYPE_VIEW_TREE_APPEARING; +import static android.view.contentcapture.ContentCaptureEvent.TYPE_WINDOW_BOUNDS_CHANGED; import static android.view.contentcapture.ContentCaptureHelper.getSanitizedString; import static android.view.contentcapture.ContentCaptureHelper.sDebug; import static android.view.contentcapture.ContentCaptureHelper.sVerbose; @@ -38,6 +39,7 @@ import android.content.ComponentName; import android.content.Context; import android.content.pm.ParceledListSlice; import android.graphics.Insets; +import android.graphics.Rect; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; @@ -776,6 +778,14 @@ public final class MainContentCaptureSession extends ContentCaptureSession { .setClientContext(context), FORCE_FLUSH)); } + /** public because is also used by ViewRootImpl */ + public void notifyWindowBoundsChanged(int sessionId, @NonNull Rect bounds) { + mHandler.post(() -> sendEvent( + new ContentCaptureEvent(sessionId, TYPE_WINDOW_BOUNDS_CHANGED) + .setBounds(bounds) + )); + } + @Override void dump(@NonNull String prefix, @NonNull PrintWriter pw) { super.dump(prefix, pw); diff --git a/core/java/android/view/inputmethod/InputMethod.java b/core/java/android/view/inputmethod/InputMethod.java index d2db0df6c597..5b2068ff16cd 100644 --- a/core/java/android/view/inputmethod/InputMethod.java +++ b/core/java/android/view/inputmethod/InputMethod.java @@ -96,8 +96,6 @@ public interface InputMethod { * * @param token special token for the system to identify * {@link InputMethodService} - * @param displayId The id of the display that current IME shown. - * Used for {{@link #updateInputMethodDisplay(int)}} * @param privilegedOperations IPC endpoint to do some privileged * operations that are allowed only to the * current IME. @@ -105,9 +103,8 @@ public interface InputMethod { * @hide */ @MainThread - default void initializeInternal(IBinder token, int displayId, + default void initializeInternal(IBinder token, IInputMethodPrivilegedOperations privilegedOperations, int configChanges) { - updateInputMethodDisplay(displayId); attachToken(token); } @@ -142,16 +139,6 @@ public interface InputMethod { @MainThread public void attachToken(IBinder token); - /** - * Update context display according to given displayId. - * - * @param displayId The id of the display that need to update for context. - * @hide - */ - @MainThread - default void updateInputMethodDisplay(int displayId) { - } - /** * Bind a new application environment in to the input method, so that it * can later start and stop input processing. diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java index 42d77cd09689..e6f103e6d53b 100644 --- a/core/java/android/view/inputmethod/InputMethodManager.java +++ b/core/java/android/view/inputmethod/InputMethodManager.java @@ -2154,6 +2154,7 @@ public final class InputMethodManager { * @hide */ public boolean requestImeShow(IBinder windowToken) { + checkFocus(); synchronized (mH) { final View servedView = getServedViewLocked(); if (servedView == null || servedView.getWindowToken() != windowToken) { diff --git a/core/java/android/view/translation/UiTranslationController.java b/core/java/android/view/translation/UiTranslationController.java index d078c2cfbfd1..fb534c7885e4 100644 --- a/core/java/android/view/translation/UiTranslationController.java +++ b/core/java/android/view/translation/UiTranslationController.java @@ -110,11 +110,10 @@ public class UiTranslationController { public void updateUiTranslationState(@UiTranslationState int state, TranslationSpec sourceSpec, TranslationSpec targetSpec, List views, UiTranslationSpec uiTranslationSpec) { - if (!mActivity.isResumed() && (state == STATE_UI_TRANSLATION_STARTED - || state == STATE_UI_TRANSLATION_RESUMED)) { + if (mActivity.isDestroyed()) { + Log.i(TAG, "Cannot update " + stateToString(state) + " for destroyed " + mActivity); return; } - Log.i(TAG, "updateUiTranslationState state: " + stateToString(state) + (DEBUG ? (", views: " + views + ", spec: " + uiTranslationSpec) : "")); synchronized (mLock) { @@ -342,10 +341,8 @@ public class UiTranslationController { */ private void onVirtualViewTranslationCompleted( SparseArray> translatedResult) { - if (!mActivity.isResumed()) { - if (DEBUG) { - Log.v(TAG, "onTranslationCompleted: Activity is not resumed."); - } + if (mActivity.isDestroyed()) { + Log.v(TAG, "onTranslationCompleted:" + mActivity + "is destroyed."); return; } synchronized (mLock) { @@ -372,6 +369,10 @@ public class UiTranslationController { Log.v(TAG, "onVirtualViewTranslationCompleted: received response for " + "AutofillId " + autofillId); } + view.onVirtualViewTranslationResponses(virtualChildResponse); + if (mCurrentState == STATE_UI_TRANSLATION_PAUSED) { + return; + } mActivity.runOnUiThread(() -> { if (view.getViewTranslationCallback() == null) { if (DEBUG) { @@ -380,7 +381,6 @@ public class UiTranslationController { } return; } - view.onVirtualViewTranslationResponses(virtualChildResponse); if (view.getViewTranslationCallback() != null) { view.getViewTranslationCallback().onShowTranslation(view); } @@ -393,10 +393,8 @@ public class UiTranslationController { * The method is used to handle the translation result for non-vertual views. */ private void onTranslationCompleted(SparseArray translatedResult) { - if (!mActivity.isResumed()) { - if (DEBUG) { - Log.v(TAG, "onTranslationCompleted: Activity is not resumed."); - } + if (mActivity.isDestroyed()) { + Log.v(TAG, "onTranslationCompleted:" + mActivity + "is destroyed."); return; } final int resultCount = translatedResult.size(); @@ -430,12 +428,17 @@ public class UiTranslationController { + " may be gone."); continue; } + int currentState; + currentState = mCurrentState; mActivity.runOnUiThread(() -> { ViewTranslationCallback callback = view.getViewTranslationCallback(); if (view.getViewTranslationResponse() != null && view.getViewTranslationResponse().equals(response)) { if (callback instanceof TextViewTranslationCallback) { - if (((TextViewTranslationCallback) callback).isShowingTranslation()) { + TextViewTranslationCallback textViewCallback = + (TextViewTranslationCallback) callback; + if (textViewCallback.isShowingTranslation() + || textViewCallback.isAnimationRunning()) { if (DEBUG) { Log.d(TAG, "Duplicate ViewTranslationResponse for " + autofillId + ". Ignoring."); @@ -463,6 +466,9 @@ public class UiTranslationController { callback.enableContentPadding(); } view.onViewTranslationResponse(response); + if (currentState == STATE_UI_TRANSLATION_PAUSED) { + return; + } callback.onShowTranslation(view); }); } diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java index 3fd0f037f3b0..ac21d952765d 100755 --- a/core/java/android/widget/AbsListView.java +++ b/core/java/android/widget/AbsListView.java @@ -3720,14 +3720,14 @@ public abstract class AbsListView extends AdapterView implements Te if (!mEdgeGlowBottom.isFinished()) { mEdgeGlowBottom.onRelease(); } - invalidateTopGlow(); + invalidateEdgeEffects(); } else if (incrementalDeltaY < 0) { mEdgeGlowBottom.onPullDistance((float) overscroll / getHeight(), 1.f - (float) x / getWidth()); if (!mEdgeGlowTop.isFinished()) { mEdgeGlowTop.onRelease(); } - invalidateBottomGlow(); + invalidateEdgeEffects(); } } } @@ -3767,7 +3767,7 @@ public abstract class AbsListView extends AdapterView implements Te if (!mEdgeGlowBottom.isFinished()) { mEdgeGlowBottom.onRelease(); } - invalidateTopGlow(); + invalidateEdgeEffects(); } else if (rawDeltaY < 0) { mEdgeGlowBottom.onPullDistance( (float) -overScrollDistance / getHeight(), @@ -3775,7 +3775,7 @@ public abstract class AbsListView extends AdapterView implements Te if (!mEdgeGlowTop.isFinished()) { mEdgeGlowTop.onRelease(); } - invalidateBottomGlow(); + invalidateEdgeEffects(); } } } @@ -3821,17 +3821,21 @@ public abstract class AbsListView extends AdapterView implements Te // First allow releasing existing overscroll effect: float consumed = 0; if (mEdgeGlowTop.getDistance() != 0) { - consumed = mEdgeGlowTop.onPullDistance((float) deltaY / getHeight(), - (float) x / getWidth()); - if (consumed != 0f) { - invalidateTopGlow(); + if (canScrollUp()) { + mEdgeGlowTop.onRelease(); + } else { + consumed = mEdgeGlowTop.onPullDistance((float) deltaY / getHeight(), + (float) x / getWidth()); } + invalidateEdgeEffects(); } else if (mEdgeGlowBottom.getDistance() != 0) { - consumed = -mEdgeGlowBottom.onPullDistance((float) -deltaY / getHeight(), - 1f - (float) x / getWidth()); - if (consumed != 0f) { - invalidateBottomGlow(); + if (canScrollDown()) { + mEdgeGlowBottom.onRelease(); + } else { + consumed = -mEdgeGlowBottom.onPullDistance((float) -deltaY / getHeight(), + 1f - (float) x / getWidth()); } + invalidateEdgeEffects(); } int pixelsConsumed = Math.round(consumed * getHeight()); return deltaY - pixelsConsumed; @@ -3841,30 +3845,16 @@ public abstract class AbsListView extends AdapterView implements Te * @return true if either the top or bottom edge glow is currently active or * false if it has no value to release. */ - private boolean isGlowActive() { - return mEdgeGlowBottom.getDistance() != 0 || mEdgeGlowTop.getDistance() != 0; - } - - private void invalidateTopGlow() { - if (!shouldDisplayEdgeEffects()) { - return; - } - final boolean clipToPadding = getClipToPadding(); - final int top = clipToPadding ? mPaddingTop : 0; - final int left = clipToPadding ? mPaddingLeft : 0; - final int right = clipToPadding ? getWidth() - mPaddingRight : getWidth(); - invalidate(left, top, right, top + mEdgeGlowTop.getMaxHeight()); + private boolean doesTouchStopStretch() { + return (mEdgeGlowBottom.getDistance() != 0 && !canScrollDown()) + || (mEdgeGlowTop.getDistance() != 0 && !canScrollUp()); } - private void invalidateBottomGlow() { + private void invalidateEdgeEffects() { if (!shouldDisplayEdgeEffects()) { return; } - final boolean clipToPadding = getClipToPadding(); - final int bottom = clipToPadding ? getHeight() - mPaddingBottom : getHeight(); - final int left = clipToPadding ? mPaddingLeft : 0; - final int right = clipToPadding ? getWidth() - mPaddingRight : getWidth(); - invalidate(left, bottom - mEdgeGlowBottom.getMaxHeight(), right, bottom); + invalidate(); } @Override @@ -4530,7 +4520,7 @@ public abstract class AbsListView extends AdapterView implements Te final int edgeY = Math.min(0, scrollY + mFirstPositionDistanceGuess) + translateY; canvas.translate(translateX, edgeY); if (mEdgeGlowTop.draw(canvas)) { - invalidateTopGlow(); + invalidateEdgeEffects(); } canvas.restoreToCount(restoreCount); } @@ -4544,7 +4534,7 @@ public abstract class AbsListView extends AdapterView implements Te canvas.translate(edgeX, edgeY); canvas.rotate(180, width, 0); if (mEdgeGlowBottom.draw(canvas)) { - invalidateBottomGlow(); + invalidateEdgeEffects(); } canvas.restoreToCount(restoreCount); } @@ -4637,7 +4627,7 @@ public abstract class AbsListView extends AdapterView implements Te mActivePointerId = ev.getPointerId(0); int motionPosition = findMotionRow(y); - if (isGlowActive()) { + if (doesTouchStopStretch()) { // Pressed during edge effect, so this is considered the same as a fling catch. touchMode = mTouchMode = TOUCH_MODE_FLING; } else if (touchMode != TOUCH_MODE_FLING && motionPosition >= 0) { @@ -6657,7 +6647,7 @@ public abstract class AbsListView extends AdapterView implements Te */ public void setBottomEdgeEffectColor(@ColorInt int color) { mEdgeGlowBottom.setColor(color); - invalidateBottomGlow(); + invalidateEdgeEffects(); } /** @@ -6671,7 +6661,7 @@ public abstract class AbsListView extends AdapterView implements Te */ public void setTopEdgeEffectColor(@ColorInt int color) { mEdgeGlowTop.setColor(color); - invalidateTopGlow(); + invalidateEdgeEffects(); } /** diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java index fe5eb085dc5c..1784dcfc505f 100644 --- a/core/java/android/widget/RemoteViews.java +++ b/core/java/android/widget/RemoteViews.java @@ -34,6 +34,7 @@ import android.app.Activity; import android.app.ActivityOptions; import android.app.ActivityThread; import android.app.Application; +import android.app.LoadedApk; import android.app.PendingIntent; import android.app.RemoteInput; import android.appwidget.AppWidgetHostView; @@ -299,6 +300,13 @@ public class RemoteViews implements Parcelable, Filter { */ public static final int FLAG_USE_LIGHT_BACKGROUND_LAYOUT = 4; + /** + * A ReadWriteHelper which has the same behavior as ReadWriteHelper.DEFAULT, but which is + * intentionally a different instance in order to trick Bundle reader so that it doesn't allow + * lazy initialization. + */ + private static final Parcel.ReadWriteHelper ALTERNATIVE_DEFAULT = new Parcel.ReadWriteHelper(); + /** * Used to restrict the views which can be inflated * @@ -337,7 +345,10 @@ public class RemoteViews implements Parcelable, Filter { * Maps bitmaps to unique indicies to avoid Bitmap duplication. */ @UnsupportedAppUsage - private BitmapCache mBitmapCache; + private BitmapCache mBitmapCache = new BitmapCache(); + + /** Cache of ApplicationInfos used by collection items. */ + private ApplicationInfoCache mApplicationInfoCache = new ApplicationInfoCache(); /** * Indicates whether or not this RemoteViews object is contained as a child of any other @@ -575,7 +586,7 @@ public class RemoteViews implements Parcelable, Filter { return 0; } - public void setBitmapCache(BitmapCache bitmapCache) { + public void setHierarchyRootData(HierarchyRootData root) { // Do nothing } @@ -604,14 +615,6 @@ public class RemoteViews implements Parcelable, Filter { return false; } - /** - * Overridden by subclasses which have (or inherit) an ApplicationInfo instance - * as member variable - */ - public boolean hasSameAppInfo(ApplicationInfo parentInfo) { - return true; - } - public void visitUris(@NonNull Consumer visitor) { // Nothing to visit by default } @@ -689,9 +692,8 @@ public class RemoteViews implements Parcelable, Filter { } } - // Because pruning can remove the need for bitmaps, we reconstruct the bitmap cache - mBitmapCache = new BitmapCache(); - setBitmapCache(mBitmapCache); + // Because pruning can remove the need for bitmaps, we reconstruct the caches. + reconstructCaches(); } /** @@ -937,23 +939,70 @@ public class RemoteViews implements Parcelable, Filter { ArrayList list; } - private static class SetRemoteCollectionItemListAdapterAction extends Action { + /** + * Cache of {@link ApplicationInfo}s that can be used to ensure that the same + * {@link ApplicationInfo} instance is used throughout the RemoteViews. + */ + private static class ApplicationInfoCache { + private final Map, ApplicationInfo> mPackageUserToApplicationInfo; + + ApplicationInfoCache() { + mPackageUserToApplicationInfo = new ArrayMap<>(); + } + + /** + * Adds the {@link ApplicationInfo} to the cache if it's not present. Returns either the + * provided {@code applicationInfo} or a previously added value with the same package name + * and uid. + */ + @Nullable + ApplicationInfo getOrPut(@Nullable ApplicationInfo applicationInfo) { + Pair key = getPackageUserKey(applicationInfo); + if (key == null) return null; + return mPackageUserToApplicationInfo.computeIfAbsent(key, ignored -> applicationInfo); + } + + /** Puts the {@link ApplicationInfo} in the cache, replacing any previously stored value. */ + void put(@Nullable ApplicationInfo applicationInfo) { + Pair key = getPackageUserKey(applicationInfo); + if (key == null) return; + mPackageUserToApplicationInfo.put(key, applicationInfo); + } + + /** + * Returns the currently stored {@link ApplicationInfo} from the cache matching + * {@code applicationInfo}, or null if there wasn't any. + */ + @Nullable ApplicationInfo get(@Nullable ApplicationInfo applicationInfo) { + Pair key = getPackageUserKey(applicationInfo); + if (key == null) return null; + return mPackageUserToApplicationInfo.get(key); + } + } + + private class SetRemoteCollectionItemListAdapterAction extends Action { private final RemoteCollectionItems mItems; SetRemoteCollectionItemListAdapterAction(@IdRes int id, RemoteCollectionItems items) { viewId = id; mItems = items; + mItems.setHierarchyRootData(getHierarchyRootData()); } SetRemoteCollectionItemListAdapterAction(Parcel parcel) { viewId = parcel.readInt(); - mItems = parcel.readTypedObject(RemoteCollectionItems.CREATOR); + mItems = new RemoteCollectionItems(parcel, getHierarchyRootData()); + } + + @Override + public void setHierarchyRootData(HierarchyRootData rootData) { + mItems.setHierarchyRootData(rootData); } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeInt(viewId); - dest.writeTypedObject(mItems, flags); + mItems.writeToParcel(dest, flags, /* attached= */ true); } @Override @@ -1601,8 +1650,8 @@ public class RemoteViews implements Parcelable, Filter { } @Override - public void setBitmapCache(BitmapCache bitmapCache) { - bitmapId = bitmapCache.getBitmapId(bitmap); + public void setHierarchyRootData(HierarchyRootData rootData) { + bitmapId = rootData.mBitmapCache.getBitmapId(bitmap); } @Override @@ -1814,7 +1863,18 @@ public class RemoteViews implements Parcelable, Filter { this.value = in.readTypedObject(Bitmap.CREATOR); break; case BUNDLE: - this.value = in.readBundle(); + // Because we use Parcel.allowSquashing() when writing, and that affects + // how the contents of Bundles are written, we need to ensure the bundle is + // unparceled immediately, not lazily. Setting a custom ReadWriteHelper + // just happens to have that effect on Bundle.readFromParcel(). + // TODO(b/212731590): build this state tracking into Bundle + if (in.hasReadWriteHelper()) { + this.value = in.readBundle(); + } else { + in.setReadWriteHelper(ALTERNATIVE_DEFAULT); + this.value = in.readBundle(); + in.setReadWriteHelper(null); + } break; case INTENT: this.value = in.readTypedObject(Intent.CREATOR); @@ -2219,15 +2279,6 @@ public class RemoteViews implements Parcelable, Filter { } } - private void configureRemoteViewsAsChild(RemoteViews rv) { - rv.setBitmapCache(mBitmapCache); - rv.setNotRoot(); - } - - void setNotRoot() { - mIsRoot = false; - } - private static boolean hasStableId(View view) { Object tag = view.getTag(com.android.internal.R.id.remote_views_stable_id); return tag != null; @@ -2301,17 +2352,14 @@ public class RemoteViews implements Parcelable, Filter { mNestedViews = nestedViews; mIndex = index; mStableId = stableId; - if (nestedViews != null) { - configureRemoteViewsAsChild(nestedViews); - } + nestedViews.configureAsChild(getHierarchyRootData()); } - ViewGroupActionAdd(Parcel parcel, BitmapCache bitmapCache, ApplicationInfo info, - int depth, Map classCookies) { + ViewGroupActionAdd(Parcel parcel, ApplicationInfo info, int depth) { viewId = parcel.readInt(); mIndex = parcel.readInt(); mStableId = parcel.readInt(); - mNestedViews = new RemoteViews(parcel, bitmapCache, info, depth, classCookies); + mNestedViews = new RemoteViews(parcel, getHierarchyRootData(), info, depth); mNestedViews.addFlags(mApplyFlags); } @@ -2323,8 +2371,8 @@ public class RemoteViews implements Parcelable, Filter { } @Override - public boolean hasSameAppInfo(ApplicationInfo parentInfo) { - return mNestedViews.hasSameAppInfo(parentInfo); + public void setHierarchyRootData(HierarchyRootData root) { + mNestedViews.configureAsChild(root); } private int findViewIndexToRecycle(ViewGroup target, RemoteViews newContent) { @@ -2492,11 +2540,6 @@ public class RemoteViews implements Parcelable, Filter { }; } - @Override - public void setBitmapCache(BitmapCache bitmapCache) { - mNestedViews.setBitmapCache(bitmapCache); - } - @Override public int mergeBehavior() { return MERGE_APPEND; @@ -3504,8 +3547,7 @@ public class RemoteViews implements Parcelable, Filter { protected RemoteViews(ApplicationInfo application, @LayoutRes int layoutId) { mApplication = application; mLayoutId = layoutId; - mBitmapCache = new BitmapCache(); - mClassCookies = null; + mApplicationInfoCache.put(application); } private boolean hasMultipleLayouts() { @@ -3561,12 +3603,10 @@ public class RemoteViews implements Parcelable, Filter { mLandscape = landscape; mPortrait = portrait; - mBitmapCache = new BitmapCache(); - configureRemoteViewsAsChild(landscape); - configureRemoteViewsAsChild(portrait); - mClassCookies = (portrait.mClassCookies != null) ? portrait.mClassCookies : landscape.mClassCookies; + + configureDescendantsAsChildren(); } /** @@ -3592,10 +3632,12 @@ public class RemoteViews implements Parcelable, Filter { throw new IllegalArgumentException("Too many RemoteViews in constructor"); } if (remoteViews.size() == 1) { - initializeFrom(remoteViews.values().iterator().next()); + // If the map only contains a single mapping, treat this as if that RemoteViews was + // passed as the top-level RemoteViews. + RemoteViews single = remoteViews.values().iterator().next(); + initializeFrom(single, /* hierarchyRoot= */ single); return; } - mBitmapCache = new BitmapCache(); mClassCookies = initializeSizedRemoteViews( remoteViews.entrySet().stream().map( entry -> { @@ -3610,6 +3652,8 @@ public class RemoteViews implements Parcelable, Filter { mLayoutId = smallestView.mLayoutId; mViewId = smallestView.mViewId; mLightBackgroundLayoutId = smallestView.mLightBackgroundLayoutId; + + configureDescendantsAsChildren(); } // Initialize mSizedRemoteViews and return the class cookies. @@ -3638,7 +3682,6 @@ public class RemoteViews implements Parcelable, Filter { } else { sizedRemoteViews.add(view); } - configureRemoteViewsAsChild(view); view.setIdealSize(size); if (classCookies == null) { classCookies = view.mClassCookies; @@ -3653,13 +3696,41 @@ public class RemoteViews implements Parcelable, Filter { * Creates a copy of another RemoteViews. */ public RemoteViews(RemoteViews src) { - initializeFrom(src); + initializeFrom(src, /* hierarchyRoot= */ null); } - private void initializeFrom(RemoteViews src) { - mBitmapCache = src.mBitmapCache; + /** + * No-arg constructor for use with {@link #initializeFrom(RemoteViews, RemoteViews)}. A + * constructor taking two RemoteViews parameters would clash with the landscape/portrait + * constructor. + */ + private RemoteViews() {} + + private static RemoteViews createInitializedFrom(@NonNull RemoteViews src, + @Nullable RemoteViews hierarchyRoot) { + RemoteViews child = new RemoteViews(); + child.initializeFrom(src, hierarchyRoot); + return child; + } + + private void initializeFrom(@NonNull RemoteViews src, @Nullable RemoteViews hierarchyRoot) { + if (hierarchyRoot == null) { + mBitmapCache = src.mBitmapCache; + mApplicationInfoCache = src.mApplicationInfoCache; + } else { + mBitmapCache = hierarchyRoot.mBitmapCache; + mApplicationInfoCache = hierarchyRoot.mApplicationInfoCache; + } + if (hierarchyRoot == null || src.mIsRoot) { + // If there's no provided root, or if src was itself a root, then this RemoteViews is + // the root of the new hierarchy. + mIsRoot = true; + hierarchyRoot = this; + } else { + // Otherwise, we're a descendant in the hierarchy. + mIsRoot = false; + } mApplication = src.mApplication; - mIsRoot = src.mIsRoot; mLayoutId = src.mLayoutId; mLightBackgroundLayoutId = src.mLightBackgroundLayoutId; mApplyFlags = src.mApplyFlags; @@ -3668,21 +3739,21 @@ public class RemoteViews implements Parcelable, Filter { mProviderInstanceId = src.mProviderInstanceId; if (src.hasLandscapeAndPortraitLayouts()) { - mLandscape = new RemoteViews(src.mLandscape); - mPortrait = new RemoteViews(src.mPortrait); + mLandscape = createInitializedFrom(src.mLandscape, hierarchyRoot); + mPortrait = createInitializedFrom(src.mPortrait, hierarchyRoot); } if (src.hasSizedRemoteViews()) { mSizedRemoteViews = new ArrayList<>(src.mSizedRemoteViews.size()); for (RemoteViews srcView : src.mSizedRemoteViews) { - mSizedRemoteViews.add(new RemoteViews(srcView)); + mSizedRemoteViews.add(createInitializedFrom(srcView, hierarchyRoot)); } } if (src.mActions != null) { Parcel p = Parcel.obtain(); p.putClassCookies(mClassCookies); - src.writeActionsToParcel(p); + src.writeActionsToParcel(p, /* flags= */ 0); p.setDataPosition(0); // Since src is already in memory, we do not care about stack overflow as it has // already been read once. @@ -3690,9 +3761,11 @@ public class RemoteViews implements Parcelable, Filter { p.recycle(); } - // Now that everything is initialized and duplicated, setting a new BitmapCache will - // re-initialize the cache. - setBitmapCache(new BitmapCache()); + // Now that everything is initialized and duplicated, create new caches for this + // RemoteViews and recursively set up all descendants. + if (mIsRoot) { + reconstructCaches(); + } } /** @@ -3701,11 +3774,11 @@ public class RemoteViews implements Parcelable, Filter { * @param parcel */ public RemoteViews(Parcel parcel) { - this(parcel, null, null, 0, null); + this(parcel, /* rootParent= */ null, /* info= */ null, /* depth= */ 0); } - private RemoteViews(Parcel parcel, BitmapCache bitmapCache, ApplicationInfo info, int depth, - Map classCookies) { + private RemoteViews(@NonNull Parcel parcel, @Nullable HierarchyRootData rootData, + @Nullable ApplicationInfo info, int depth) { if (depth > MAX_NESTED_VIEWS && (UserHandle.getAppId(Binder.getCallingUid()) != Process.SYSTEM_UID)) { throw new IllegalArgumentException("Too many nested views."); @@ -3714,20 +3787,17 @@ public class RemoteViews implements Parcelable, Filter { int mode = parcel.readInt(); - // We only store a bitmap cache in the root of the RemoteViews. - if (bitmapCache == null) { + if (rootData == null) { + // We only store a bitmap cache in the root of the RemoteViews. mBitmapCache = new BitmapCache(parcel); // Store the class cookies such that they are available when we clone this RemoteView. mClassCookies = parcel.copyClassCookies(); } else { - setBitmapCache(bitmapCache); - mClassCookies = classCookies; - setNotRoot(); + configureAsChild(rootData); } if (mode == MODE_NORMAL) { - mApplication = parcel.readInt() == 0 ? info : - ApplicationInfo.CREATOR.createFromParcel(parcel); + mApplication = ApplicationInfo.CREATOR.createFromParcel(parcel); mIdealSize = parcel.readInt() == 0 ? null : SizeF.CREATOR.createFromParcel(parcel); mLayoutId = parcel.readInt(); mViewId = parcel.readInt(); @@ -3742,8 +3812,7 @@ public class RemoteViews implements Parcelable, Filter { } List remoteViews = new ArrayList<>(numViews); for (int i = 0; i < numViews; i++) { - RemoteViews view = new RemoteViews(parcel, mBitmapCache, info, depth, - mClassCookies); + RemoteViews view = new RemoteViews(parcel, getHierarchyRootData(), info, depth); info = view.mApplication; remoteViews.add(view); } @@ -3755,9 +3824,9 @@ public class RemoteViews implements Parcelable, Filter { mLightBackgroundLayoutId = smallestView.mLightBackgroundLayoutId; } else { // MODE_HAS_LANDSCAPE_AND_PORTRAIT - mLandscape = new RemoteViews(parcel, mBitmapCache, info, depth, mClassCookies); - mPortrait = new RemoteViews(parcel, mBitmapCache, mLandscape.mApplication, depth, - mClassCookies); + mLandscape = new RemoteViews(parcel, getHierarchyRootData(), info, depth); + mPortrait = + new RemoteViews(parcel, getHierarchyRootData(), mLandscape.mApplication, depth); mApplication = mPortrait.mApplication; mLayoutId = mPortrait.mLayoutId; mViewId = mPortrait.mViewId; @@ -3765,6 +3834,11 @@ public class RemoteViews implements Parcelable, Filter { } mApplyFlags = parcel.readInt(); mProviderInstanceId = parcel.readLong(); + + // Ensure that all descendants have their caches set up recursively. + if (mIsRoot) { + configureDescendantsAsChildren(); + } } private void readActionsFromParcel(Parcel parcel, int depth) { @@ -3787,8 +3861,7 @@ public class RemoteViews implements Parcelable, Filter { case REFLECTION_ACTION_TAG: return new ReflectionAction(parcel); case VIEW_GROUP_ACTION_ADD_TAG: - return new ViewGroupActionAdd(parcel, mBitmapCache, mApplication, depth, - mClassCookies); + return new ViewGroupActionAdd(parcel, mApplication, depth); case VIEW_GROUP_ACTION_REMOVE_TAG: return new ViewGroupActionRemove(parcel); case VIEW_CONTENT_NAVIGATION_TAG: @@ -3878,27 +3951,55 @@ public class RemoteViews implements Parcelable, Filter { } /** - * Recursively sets BitmapCache in the hierarchy and update the bitmap ids. + * Sets the root of the hierarchy and then recursively traverses the tree to update the root + * and populate caches for all descendants. */ - private void setBitmapCache(BitmapCache bitmapCache) { - mBitmapCache = bitmapCache; + private void configureAsChild(@NonNull HierarchyRootData rootData) { + mIsRoot = false; + mBitmapCache = rootData.mBitmapCache; + mApplicationInfoCache = rootData.mApplicationInfoCache; + mClassCookies = rootData.mClassCookies; + configureDescendantsAsChildren(); + } + + /** + * Recursively traverses the tree to update the root and populate caches for all descendants. + */ + private void configureDescendantsAsChildren() { + // Before propagating down the tree, replace our application from the root application info + // cache, to ensure the same instance is present throughout the hierarchy to allow for + // squashing. + mApplication = mApplicationInfoCache.getOrPut(mApplication); + + HierarchyRootData rootData = getHierarchyRootData(); if (hasSizedRemoteViews()) { for (RemoteViews remoteView : mSizedRemoteViews) { - remoteView.setBitmapCache(bitmapCache); + remoteView.configureAsChild(rootData); } } else if (hasLandscapeAndPortraitLayouts()) { - mLandscape.setBitmapCache(bitmapCache); - mPortrait.setBitmapCache(bitmapCache); + mLandscape.configureAsChild(rootData); + mPortrait.configureAsChild(rootData); } else { if (mActions != null) { - final int count = mActions.size(); - for (int i = 0; i < count; ++i) { - mActions.get(i).setBitmapCache(bitmapCache); + for (Action action : mActions) { + action.setHierarchyRootData(rootData); } } } } + /** + * Recreates caches at the root level of the hierarchy, then recursively populates the caches + * down the hierarchy. + */ + private void reconstructCaches() { + if (!mIsRoot) return; + mBitmapCache = new BitmapCache(); + mApplicationInfoCache = new ApplicationInfoCache(); + mApplication = mApplicationInfoCache.getOrPut(mApplication); + configureDescendantsAsChildren(); + } + /** * Returns an estimate of the bitmap heap memory usage for this RemoteViews. */ @@ -5475,7 +5576,8 @@ public class RemoteViews implements Parcelable, Filter { // user. So build a context that loads resources from that user but // still returns the current users userId so settings like data / time formats // are loaded without requiring cross user persmissions. - final Context contextForResources = getContextForResources(context); + final Context contextForResources = + getContextForResourcesEnsuringCorrectCachedApkPaths(context); if (colorResources != null) { colorResources.apply(contextForResources); } @@ -5733,24 +5835,44 @@ public class RemoteViews implements Parcelable, Filter { return previousLayoutId == getLayoutId() && mViewId == overrideId; } - // Note: topLevel should be true only for calls on the topLevel RemoteViews, internal calls - // should set it to false. - private void reapply(Context context, View v, InteractionHandler handler, SizeF size, - ColorResources colorResources, boolean topLevel) { - + /** + * Returns the RemoteViews that should be used in the reapply operation. + * + * If the current RemoteViews has multiple layout, this will select the correct one. + * + * @throws RuntimeException If the current RemoteViews should not be reapplied onto the provided + * View. + */ + private RemoteViews getRemoteViewsToReapply(Context context, View v, @Nullable SizeF size) { RemoteViews rvToApply = getRemoteViewsToApply(context, size); // In the case that a view has this RemoteViews applied in one orientation or size, is // persisted across change, and has the RemoteViews re-applied in a different situation // (orientation or size), we throw an exception, since the layouts may be completely // unrelated. - if (hasMultipleLayouts()) { + // If the ViewID has been changed on the view, or is changed by the RemoteViews, we also + // may throw an exception, as the RemoteViews will probably not apply properly. + // However, we need to let potentially unrelated RemoteViews apply, as this lack of testing + // is already used in production code in some apps. + if (hasMultipleLayouts() + || rvToApply.mViewId != View.NO_ID + || v.getTag(R.id.remote_views_override_id) != null) { if (!rvToApply.canRecycleView(v)) { throw new RuntimeException("Attempting to re-apply RemoteViews to a view that" + " that does not share the same root layout id."); } } + return rvToApply; + } + + // Note: topLevel should be true only for calls on the topLevel RemoteViews, internal calls + // should set it to false. + private void reapply(Context context, View v, InteractionHandler handler, SizeF size, + ColorResources colorResources, boolean topLevel) { + + RemoteViews rvToApply = getRemoteViewsToReapply(context, v, size); + rvToApply.performApply(v, (ViewGroup) v.getParent(), handler, colorResources); // If the parent of the view is has is a root, resolve the recycling. @@ -5787,17 +5909,7 @@ public class RemoteViews implements Parcelable, Filter { public CancellationSignal reapplyAsync(Context context, View v, Executor executor, OnViewAppliedListener listener, InteractionHandler handler, SizeF size, ColorResources colorResources) { - RemoteViews rvToApply = getRemoteViewsToApply(context, size); - - // In the case that a view has this RemoteViews applied in one orientation, is persisted - // across orientation change, and has the RemoteViews re-applied in the new orientation, - // we throw an exception, since the layouts may be completely unrelated. - if (hasMultipleLayouts()) { - if ((Integer) v.getTag(R.id.widget_frame) != rvToApply.getLayoutId()) { - throw new RuntimeException("Attempting to re-apply RemoteViews to a view that" + - " that does not share the same root layout id."); - } - } + RemoteViews rvToApply = getRemoteViewsToReapply(context, v, size); return new AsyncApplyTask(rvToApply, (ViewGroup) v.getParent(), context, listener, handler, colorResources, v, true /* topLevel */) @@ -5836,30 +5948,28 @@ public class RemoteViews implements Parcelable, Filter { /** @hide */ public void updateAppInfo(@NonNull ApplicationInfo info) { - if (mApplication != null && mApplication.sourceDir.equals(info.sourceDir)) { + ApplicationInfo existing = mApplicationInfoCache.get(info); + if (existing != null && !existing.sourceDir.equals(info.sourceDir)) { // Overlay paths are generated against a particular version of an application. // The overlays paths of a newly upgraded application are incompatible with the // old version of the application. - mApplication = info; - } - if (hasSizedRemoteViews()) { - for (RemoteViews layout : mSizedRemoteViews) { - layout.updateAppInfo(info); - } - } - if (hasLandscapeAndPortraitLayouts()) { - mLandscape.updateAppInfo(info); - mPortrait.updateAppInfo(info); + return; } + + // If we can update to the new AppInfo, put it in the cache and propagate the change + // throughout the hierarchy. + mApplicationInfoCache.put(info); + configureDescendantsAsChildren(); } - private Context getContextForResources(Context context) { + private Context getContextForResourcesEnsuringCorrectCachedApkPaths(Context context) { if (mApplication != null) { if (context.getUserId() == UserHandle.getUserId(mApplication.uid) && context.getPackageName().equals(mApplication.packageName)) { return context; } try { + LoadedApk.checkAndUpdateApkPaths(mApplication); return context.createApplicationContext(mApplication, Context.CONTEXT_RESTRICTED); } catch (NameNotFoundException e) { @@ -6015,6 +6125,8 @@ public class RemoteViews implements Parcelable, Filter { } public void writeToParcel(Parcel dest, int flags) { + boolean prevSquashingAllowed = dest.allowSquashing(); + if (!hasMultipleLayouts()) { dest.writeInt(MODE_NORMAL); // We only write the bitmap cache if we are the root RemoteViews, as this cache @@ -6022,12 +6134,7 @@ public class RemoteViews implements Parcelable, Filter { if (mIsRoot) { mBitmapCache.writeBitmapsToParcel(dest, flags); } - if (!mIsRoot && (flags & PARCELABLE_ELIDE_DUPLICATES) != 0) { - dest.writeInt(0); - } else { - dest.writeInt(1); - mApplication.writeToParcel(dest, flags); - } + mApplication.writeToParcel(dest, flags); if (mIsRoot || mIdealSize == null) { dest.writeInt(0); } else { @@ -6037,17 +6144,15 @@ public class RemoteViews implements Parcelable, Filter { dest.writeInt(mLayoutId); dest.writeInt(mViewId); dest.writeInt(mLightBackgroundLayoutId); - writeActionsToParcel(dest); + writeActionsToParcel(dest, flags); } else if (hasSizedRemoteViews()) { dest.writeInt(MODE_HAS_SIZED_REMOTEVIEWS); if (mIsRoot) { mBitmapCache.writeBitmapsToParcel(dest, flags); } - int childFlags = flags; dest.writeInt(mSizedRemoteViews.size()); for (RemoteViews view : mSizedRemoteViews) { - view.writeToParcel(dest, childFlags); - childFlags |= PARCELABLE_ELIDE_DUPLICATES; + view.writeToParcel(dest, flags); } } else { dest.writeInt(MODE_HAS_LANDSCAPE_AND_PORTRAIT); @@ -6058,13 +6163,15 @@ public class RemoteViews implements Parcelable, Filter { } mLandscape.writeToParcel(dest, flags); // Both RemoteViews already share the same package and user - mPortrait.writeToParcel(dest, flags | PARCELABLE_ELIDE_DUPLICATES); + mPortrait.writeToParcel(dest, flags); } dest.writeInt(mApplyFlags); dest.writeLong(mProviderInstanceId); + + dest.restoreAllowSquashing(prevSquashingAllowed); } - private void writeActionsToParcel(Parcel parcel) { + private void writeActionsToParcel(Parcel parcel, int flags) { int count; if (mActions != null) { count = mActions.size(); @@ -6075,8 +6182,7 @@ public class RemoteViews implements Parcelable, Filter { for (int i = 0; i < count; i++) { Action a = mActions.get(i); parcel.writeInt(a.getActionTag()); - a.writeToParcel(parcel, a.hasSameAppInfo(mApplication) - ? PARCELABLE_ELIDE_DUPLICATES : 0); + a.writeToParcel(parcel, flags); } } @@ -6555,6 +6661,8 @@ public class RemoteViews implements Parcelable, Filter { private final boolean mHasStableIds; private final int mViewTypeCount; + private HierarchyRootData mHierarchyRootData; + RemoteCollectionItems( long[] ids, RemoteViews[] views, boolean hasStableIds, int viewTypeCount) { mIds = ids; @@ -6577,16 +6685,53 @@ public class RemoteViews implements Parcelable, Filter { "View type count is set to " + viewTypeCount + ", but the collection " + "contains " + layoutIdCount + " different layout ids"); } + + // Until the collection items are attached to a parent, we configure the first item + // to be the root of the others to share caches and save space during serialization. + if (views.length > 0) { + setHierarchyRootData(views[0].getHierarchyRootData()); + views[0].mIsRoot = true; + } } - RemoteCollectionItems(Parcel in) { + RemoteCollectionItems(@NonNull Parcel in, @Nullable HierarchyRootData hierarchyRootData) { + mHasStableIds = in.readBoolean(); + mViewTypeCount = in.readInt(); int length = in.readInt(); mIds = new long[length]; in.readLongArray(mIds); + + boolean attached = in.readBoolean(); mViews = new RemoteViews[length]; - in.readTypedArray(mViews, RemoteViews.CREATOR); - mHasStableIds = in.readBoolean(); - mViewTypeCount = in.readInt(); + int firstChildIndex; + if (attached) { + if (hierarchyRootData == null) { + throw new IllegalStateException("Cannot unparcel a RemoteCollectionItems that " + + "was parceled as attached without providing data for a root " + + "RemoteViews"); + } + mHierarchyRootData = hierarchyRootData; + firstChildIndex = 0; + } else { + mViews[0] = new RemoteViews(in); + mHierarchyRootData = mViews[0].getHierarchyRootData(); + firstChildIndex = 1; + } + + for (int i = firstChildIndex; i < length; i++) { + mViews[i] = new RemoteViews( + in, + mHierarchyRootData, + /* info= */ null, + /* depth= */ 0); + } + } + + void setHierarchyRootData(@NonNull HierarchyRootData rootData) { + mHierarchyRootData = rootData; + for (RemoteViews view : mViews) { + view.configureAsChild(rootData); + } } @Override @@ -6596,11 +6741,39 @@ public class RemoteViews implements Parcelable, Filter { @Override public void writeToParcel(@NonNull Parcel dest, int flags) { - dest.writeInt(mIds.length); - dest.writeLongArray(mIds); - dest.writeTypedArray(mViews, flags); + writeToParcel(dest, flags, /* attached= */ false); + } + + private void writeToParcel(@NonNull Parcel dest, int flags, boolean attached) { + boolean prevAllowSquashing = dest.allowSquashing(); + dest.writeBoolean(mHasStableIds); dest.writeInt(mViewTypeCount); + dest.writeInt(mIds.length); + dest.writeLongArray(mIds); + + if (attached && mHierarchyRootData == null) { + throw new IllegalStateException("Cannot call writeToParcelAttached for a " + + "RemoteCollectionItems without first calling setHierarchyRootData()"); + } + + // Write whether we parceled as attached or not. This allows cleaner validation and + // proper error messaging when unparceling later. + dest.writeBoolean(attached); + boolean restoreRoot = false; + if (!attached && mViews.length > 0 && !mViews[0].mIsRoot) { + // If we're writing unattached, temporarily set the first item as the root so that + // the bitmap cache is written to the parcel. + restoreRoot = true; + mViews[0].mIsRoot = true; + } + + for (RemoteViews view : mViews) { + view.writeToParcel(dest, flags); + } + + if (restoreRoot) mViews[0].mIsRoot = false; + dest.restoreAllowSquashing(prevAllowSquashing); } /** @@ -6658,7 +6831,7 @@ public class RemoteViews implements Parcelable, Filter { @NonNull @Override public RemoteCollectionItems createFromParcel(@NonNull Parcel source) { - return new RemoteCollectionItems(source); + return new RemoteCollectionItems(source, /* hierarchyRoot= */ null); } @NonNull @@ -6833,4 +7006,29 @@ public class RemoteViews implements Parcelable, Filter { viewId |= childId; return viewId; } + + @Nullable + private static Pair getPackageUserKey(@Nullable ApplicationInfo info) { + if (info == null || info.packageName == null) return null; + return Pair.create(info.packageName, info.uid); + } + + private HierarchyRootData getHierarchyRootData() { + return new HierarchyRootData(mBitmapCache, mApplicationInfoCache, mClassCookies); + } + + private static final class HierarchyRootData { + final BitmapCache mBitmapCache; + final ApplicationInfoCache mApplicationInfoCache; + final Map mClassCookies; + + HierarchyRootData( + BitmapCache bitmapCache, + ApplicationInfoCache applicationInfoCache, + Map classCookies) { + mBitmapCache = bitmapCache; + mApplicationInfoCache = applicationInfoCache; + mClassCookies = classCookies; + } + } } diff --git a/core/java/android/widget/RemoteViewsAdapter.java b/core/java/android/widget/RemoteViewsAdapter.java index 6b33428d7fe4..8e293f4b356d 100644 --- a/core/java/android/widget/RemoteViewsAdapter.java +++ b/core/java/android/widget/RemoteViewsAdapter.java @@ -408,7 +408,7 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback } @Override - protected Context getRemoteContext() { + protected Context getRemoteContextEnsuringCorrectCachedApkPath() { return null; } diff --git a/core/java/android/widget/TextViewTranslationCallback.java b/core/java/android/widget/TextViewTranslationCallback.java index 4a78f3ee6fac..942be21b1ade 100644 --- a/core/java/android/widget/TextViewTranslationCallback.java +++ b/core/java/android/widget/TextViewTranslationCallback.java @@ -46,6 +46,7 @@ public class TextViewTranslationCallback implements ViewTranslationCallback { private TranslationTransformationMethod mTranslationTransformation; private boolean mIsShowingTranslation = false; + private boolean mAnimationRunning = false; private boolean mIsTextPaddingEnabled = false; private CharSequence mPaddedText; private int mAnimationDurationMillis = 250; // default value @@ -92,6 +93,7 @@ public class TextViewTranslationCallback implements ViewTranslationCallback { (TextView) view, () -> { mIsShowingTranslation = true; + mAnimationRunning = false; // TODO(b/178353965): well-handle setTransformationMethod. ((TextView) view).setTransformationMethod(transformation); }); @@ -124,6 +126,7 @@ public class TextViewTranslationCallback implements ViewTranslationCallback { (TextView) view, () -> { mIsShowingTranslation = false; + mAnimationRunning = false; ((TextView) view).setTransformationMethod(transformation); }); if (!TextUtils.isEmpty(mContentDescription)) { @@ -162,6 +165,13 @@ public class TextViewTranslationCallback implements ViewTranslationCallback { return mIsShowingTranslation; } + /** + * Returns whether the view is running animation to show or hide the translation. + */ + public boolean isAnimationRunning() { + return mAnimationRunning; + } + @Override public void enableContentPadding() { mIsTextPaddingEnabled = true; @@ -230,6 +240,7 @@ public class TextViewTranslationCallback implements ViewTranslationCallback { mAnimator.end(); // Note: mAnimator is now null; do not use again here. } + mAnimationRunning = true; int fadedOutColor = colorWithAlpha(view.getCurrentTextColor(), 0); mAnimator = ValueAnimator.ofArgb(view.getCurrentTextColor(), fadedOutColor); mAnimator.addUpdateListener( diff --git a/core/java/android/window/ConfigurationHelper.java b/core/java/android/window/ConfigurationHelper.java new file mode 100644 index 000000000000..9a079751553f --- /dev/null +++ b/core/java/android/window/ConfigurationHelper.java @@ -0,0 +1,132 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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.window; + +import static android.view.Display.INVALID_DISPLAY; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.app.ResourcesManager; +import android.content.Context; +import android.content.pm.ActivityInfo; +import android.content.res.Configuration; +import android.graphics.Canvas; +import android.graphics.Rect; +import android.os.IBinder; +import android.view.Display; +import android.view.WindowManager; + +/** + * A helper class to maintain {@link android.content.res.Configuration} related methods used both + * in {@link android.app.Activity} and {@link WindowContext}. + * + * @hide + */ +public class ConfigurationHelper { + private ConfigurationHelper() {} + + /** Ask text layout engine to free its caches if there is a locale change. */ + public static void freeTextLayoutCachesIfNeeded(int configDiff) { + if ((configDiff & ActivityInfo.CONFIG_LOCALE) != 0) { + Canvas.freeTextLayoutCaches(); + } + } + + /** + * A helper method to filter out {@link ActivityInfo#CONFIG_SCREEN_SIZE} if the + * {@link Configuration#diffPublicOnly(Configuration) diff} of two {@link Configuration} + * doesn't cross the boundary. + * + * @see SizeConfigurationBuckets#filterDiff(int, Configuration, Configuration, + * SizeConfigurationBuckets) + */ + public static int diffPublicWithSizeBuckets(@Nullable Configuration currentConfig, + @NonNull Configuration newConfig, @Nullable SizeConfigurationBuckets buckets) { + // If current configuration is null, it is definitely different from updated Configuration. + if (currentConfig == null) { + return 0xffffffff; + } + int publicDiff = currentConfig.diffPublicOnly(newConfig); + return SizeConfigurationBuckets.filterDiff(publicDiff, currentConfig, newConfig, buckets); + } + + /** + * Returns {@code true} if the {@link android.content.res.Resources} associated with + * a {@code token} needs to be updated. + * + * @param token A {@link Context#getActivityToken() activity token} or + * {@link Context#getWindowContextToken() window context token} + * @param config The original {@link Configuration} + * @param newConfig The updated Configuration + * @param displayChanged a flag to indicate there's a display change + * @param configChanged a flag to indicate there's a Configuration change. + * + * @see ResourcesManager#updateResourcesForActivity(IBinder, Configuration, int) + */ + public static boolean shouldUpdateResources(IBinder token, @Nullable Configuration config, + @NonNull Configuration newConfig, @NonNull Configuration overrideConfig, + boolean displayChanged, @Nullable Boolean configChanged) { + // The configuration has not yet been initialized. We should update it. + if (config == null) { + return true; + } + // If the token associated context is moved to another display, we should update the + // ResourcesKey. + if (displayChanged) { + return true; + } + // If the new config is the same as the config this Activity is already running with and + // the override config also didn't change, then don't update the Resources + if (!ResourcesManager.getInstance().isSameResourcesOverrideConfig(token, overrideConfig)) { + return true; + } + // If there's a update on WindowConfiguration#mBounds or maxBounds, we should update the + // Resources to make WindowMetrics API report the updated result. + if (shouldUpdateWindowMetricsBounds(config, newConfig)) { + return true; + } + return configChanged == null ? config.diff(newConfig) != 0 : configChanged; + } + + /** + * Returns {@code true} if {@code displayId} is different from {@code newDisplayId}. + * Note that {@link Display#INVALID_DISPLAY} means no difference. + */ + public static boolean isDifferentDisplay(int displayId, int newDisplayId) { + return newDisplayId != INVALID_DISPLAY && displayId != newDisplayId; + } + + // TODO(b/173090263): Remove this method after the improvement of AssetManager and ResourcesImpl + // constructions. + /** + * Returns {@code true} if the metrics reported by {@link android.view.WindowMetrics} APIs + * should be updated. + * + * @see WindowManager#getCurrentWindowMetrics() + * @see WindowManager#getMaximumWindowMetrics() + */ + private static boolean shouldUpdateWindowMetricsBounds(@NonNull Configuration currentConfig, + @NonNull Configuration newConfig) { + final Rect currentBounds = currentConfig.windowConfiguration.getBounds(); + final Rect newBounds = newConfig.windowConfiguration.getBounds(); + + final Rect currentMaxBounds = currentConfig.windowConfiguration.getMaxBounds(); + final Rect newMaxBounds = newConfig.windowConfiguration.getMaxBounds(); + + return !currentBounds.equals(newBounds) || !currentMaxBounds.equals(newMaxBounds); + } +} diff --git a/core/java/android/window/DisplayAreaInfo.java b/core/java/android/window/DisplayAreaInfo.java index 358467ff599f..1a7aab6852b6 100644 --- a/core/java/android/window/DisplayAreaInfo.java +++ b/core/java/android/window/DisplayAreaInfo.java @@ -16,6 +16,8 @@ package android.window; +import static android.window.DisplayAreaOrganizer.FEATURE_UNDEFINED; + import android.annotation.NonNull; import android.annotation.TestApi; import android.content.res.Configuration; @@ -43,8 +45,17 @@ public final class DisplayAreaInfo implements Parcelable { */ public final int displayId; + /** + * The feature id of this display area. + */ public final int featureId; + /** + * The feature id of the root display area this display area is associated with. + * @hide + */ + public int rootDisplayAreaId = FEATURE_UNDEFINED; + public DisplayAreaInfo(@NonNull WindowContainerToken token, int displayId, int featureId) { this.token = token; this.displayId = displayId; @@ -56,6 +67,7 @@ public final class DisplayAreaInfo implements Parcelable { configuration.readFromParcel(in); displayId = in.readInt(); featureId = in.readInt(); + rootDisplayAreaId = in.readInt(); } @Override @@ -64,6 +76,7 @@ public final class DisplayAreaInfo implements Parcelable { configuration.writeToParcel(dest, flags); dest.writeInt(displayId); dest.writeInt(featureId); + dest.writeInt(rootDisplayAreaId); } @NonNull diff --git a/core/java/android/window/DisplayAreaOrganizer.java b/core/java/android/window/DisplayAreaOrganizer.java index 878439906de2..6758a3b411a2 100644 --- a/core/java/android/window/DisplayAreaOrganizer.java +++ b/core/java/android/window/DisplayAreaOrganizer.java @@ -33,6 +33,15 @@ import java.util.concurrent.Executor; @TestApi public class DisplayAreaOrganizer extends WindowOrganizer { + /** + * Key to specify the {@link com.android.server.wm.RootDisplayArea} to attach a window to. + * It will be used by the function passed in from + * {@link com.android.server.wm.DisplayAreaPolicyBuilder#setSelectRootForWindowFunc(BiFunction)} + * to find the Root DA to attach the window. + * @hide + */ + public static final String KEY_ROOT_DISPLAY_AREA_ID = "root_display_area_id"; + /** * The value in display area indicating that no value has been set. */ @@ -256,6 +265,7 @@ public class DisplayAreaOrganizer extends WindowOrganizer { } }; + @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) private IDisplayAreaOrganizerController getController() { try { return getWindowOrganizerController().getDisplayAreaOrganizerController(); @@ -263,5 +273,4 @@ public class DisplayAreaOrganizer extends WindowOrganizer { return null; } } - } diff --git a/core/java/android/window/IRemoteTransitionFinishedCallback.aidl b/core/java/android/window/IRemoteTransitionFinishedCallback.aidl index 02aa1a93a35f..7864c245310e 100644 --- a/core/java/android/window/IRemoteTransitionFinishedCallback.aidl +++ b/core/java/android/window/IRemoteTransitionFinishedCallback.aidl @@ -16,14 +16,18 @@ package android.window; +import android.view.SurfaceControl; import android.window.WindowContainerTransaction; /** * Interface to be invoked by the controlling process when a remote transition has finished. * * @see IRemoteTransition + * @param wct An optional WindowContainerTransaction to apply before the transition finished. + * @param sct An optional Surface Transaction that is added to the end of the finish/cleanup + * transaction. This is applied by shell.Transitions (before submitting the wct). * {@hide} */ interface IRemoteTransitionFinishedCallback { - void onTransitionFinished(in WindowContainerTransaction wct); + void onTransitionFinished(in WindowContainerTransaction wct, in SurfaceControl.Transaction sct); } diff --git a/core/java/android/window/ITaskFragmentOrganizer.aidl b/core/java/android/window/ITaskFragmentOrganizer.aidl new file mode 100644 index 000000000000..cdfa206423c2 --- /dev/null +++ b/core/java/android/window/ITaskFragmentOrganizer.aidl @@ -0,0 +1,51 @@ +/** + * Copyright (c) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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.window; + +import android.content.res.Configuration; +import android.os.Bundle; +import android.os.IBinder; +import android.window.TaskFragmentInfo; + +/** @hide */ +oneway interface ITaskFragmentOrganizer { + void onTaskFragmentAppeared(in TaskFragmentInfo taskFragmentInfo); + void onTaskFragmentInfoChanged(in TaskFragmentInfo taskFragmentInfo); + void onTaskFragmentVanished(in TaskFragmentInfo taskFragmentInfo); + + /** + * Called when the parent leaf Task of organized TaskFragments is changed. + * When the leaf Task is changed, the organizer may want to update the TaskFragments in one + * transaction. + * + * For case like screen size change, it will trigger onTaskFragmentParentInfoChanged with new + * Task bounds, but may not trigger onTaskFragmentInfoChanged because there can be an override + * bounds. + */ + void onTaskFragmentParentInfoChanged(in IBinder fragmentToken, in Configuration parentConfig); + + /** + * Called when the {@link WindowContainerTransaction} created with + * {@link WindowContainerTransaction#setErrorCallbackToken(IBinder)} failed on the server side. + * + * @param errorCallbackToken Token set through {@link + * WindowContainerTransaction#setErrorCallbackToken(IBinder)} + * @param exceptionBundle Bundle containing the exception. Should be created with + * {@link TaskFragmentOrganizer#putExceptionInBundle}. + */ + void onTaskFragmentError(in IBinder errorCallbackToken, in Bundle exceptionBundle); +} diff --git a/core/java/android/window/ITaskFragmentOrganizerController.aidl b/core/java/android/window/ITaskFragmentOrganizerController.aidl new file mode 100644 index 000000000000..4399207fcc27 --- /dev/null +++ b/core/java/android/window/ITaskFragmentOrganizerController.aidl @@ -0,0 +1,53 @@ +/** + * Copyright (c) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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.window; + +import android.view.RemoteAnimationDefinition; +import android.window.ITaskFragmentOrganizer; + +/** @hide */ +interface ITaskFragmentOrganizerController { + + /** + * Registers a TaskFragmentOrganizer to manage TaskFragments. + */ + void registerOrganizer(in ITaskFragmentOrganizer organizer); + + /** + * Unregisters a previously registered TaskFragmentOrganizer. + */ + void unregisterOrganizer(in ITaskFragmentOrganizer organizer); + + /** + * Registers remote animations per transition type for the organizer. It will override the + * animations if the transition only contains windows that belong to the organized + * TaskFragments. + */ + void registerRemoteAnimations(in ITaskFragmentOrganizer organizer, + in RemoteAnimationDefinition definition); + + /** + * Unregisters remote animations per transition type for the organizer. + */ + void unregisterRemoteAnimations(in ITaskFragmentOrganizer organizer); + + /** + * Checks if an activity organized by a {@link android.window.TaskFragmentOrganizer} and + * only occupies a portion of Task bounds. + */ + boolean isActivityEmbedded(in IBinder activityToken); +} diff --git a/core/java/android/window/ITaskOrganizer.aidl b/core/java/android/window/ITaskOrganizer.aidl index 69bc1b5f7763..fd86769293a6 100644 --- a/core/java/android/window/ITaskOrganizer.aidl +++ b/core/java/android/window/ITaskOrganizer.aidl @@ -20,6 +20,7 @@ import android.view.SurfaceControl; import android.app.ActivityManager; import android.graphics.Rect; import android.window.StartingWindowInfo; +import android.window.StartingWindowRemovalInfo; import android.window.WindowContainerToken; /** @@ -39,12 +40,9 @@ oneway interface ITaskOrganizer { /** * Called when the Task want to remove the starting window. - * @param leash A persistent leash for the top window in this task. - * @param frame Window frame of the top window. - * @param playRevealAnimation Play vanish animation. + * @param removalInfo The information used to remove the starting window. */ - void removeStartingWindow(int taskId, in SurfaceControl leash, in Rect frame, - in boolean playRevealAnimation); + void removeStartingWindow(in StartingWindowRemovalInfo removalInfo); /** * Called when the Task want to copy the splash screen. diff --git a/core/java/android/window/ITransitionMetricsReporter.aidl b/core/java/android/window/ITransitionMetricsReporter.aidl new file mode 100644 index 000000000000..00f71dc7bb90 --- /dev/null +++ b/core/java/android/window/ITransitionMetricsReporter.aidl @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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.window; + +import android.os.IBinder; + +/** + * Implemented by WM Core to know the metrics of transition that runs on a different process. + * @hide + */ +oneway interface ITransitionMetricsReporter { + + /** + * Called when the transition animation starts. + * + * @param startTime The time when the animation started. + */ + void reportAnimationStart(IBinder transitionToken, long startTime); +} diff --git a/core/java/android/window/IWindowOrganizerController.aidl b/core/java/android/window/IWindowOrganizerController.aidl index 1223d72f643e..3c7cd0254e78 100644 --- a/core/java/android/window/IWindowOrganizerController.aidl +++ b/core/java/android/window/IWindowOrganizerController.aidl @@ -19,8 +19,11 @@ package android.window; import android.view.SurfaceControl; import android.os.IBinder; +import android.view.RemoteAnimationAdapter; import android.window.IDisplayAreaOrganizerController; +import android.window.ITaskFragmentOrganizerController; import android.window.ITaskOrganizerController; +import android.window.ITransitionMetricsReporter; import android.window.ITransitionPlayer; import android.window.IWindowContainerTransactionCallback; import android.window.WindowContainerToken; @@ -59,6 +62,17 @@ interface IWindowOrganizerController { IBinder startTransition(int type, in @nullable IBinder transitionToken, in @nullable WindowContainerTransaction t); + /** + * Starts a legacy transition. + * @param type The transition type. + * @param adapter The animation to use. + * @param syncCallback A sync callback for the contents of `t` + * @param t Operations that are part of the transition. + * @return sync-id or -1 if this no-op'd because a transition is already running. + */ + int startLegacyTransition(int type, in RemoteAnimationAdapter adapter, + in IWindowContainerTransactionCallback syncCallback, in WindowContainerTransaction t); + /** * Finishes a transition. This must be called for all created transitions. * @param transitionToken Which transition to finish @@ -77,9 +91,15 @@ interface IWindowOrganizerController { /** @return An interface enabling the management of display area organizers. */ IDisplayAreaOrganizerController getDisplayAreaOrganizerController(); + /** @return An interface enabling the management of task fragment organizers. */ + ITaskFragmentOrganizerController getTaskFragmentOrganizerController(); + /** * Registers a transition player with Core. There is only one of these at a time and calling * this will replace the existing one if set. */ void registerTransitionPlayer(in ITransitionPlayer player); + + /** @return An interface enabling the transition players to report its metrics. */ + ITransitionMetricsReporter getTransitionMetricsReporter(); } diff --git a/core/java/android/window/PictureInPictureSurfaceTransaction.java b/core/java/android/window/PictureInPictureSurfaceTransaction.java index dbf7eb34e273..2bf2f3193789 100644 --- a/core/java/android/window/PictureInPictureSurfaceTransaction.java +++ b/core/java/android/window/PictureInPictureSurfaceTransaction.java @@ -19,6 +19,7 @@ package android.window; import android.annotation.NonNull; import android.annotation.Nullable; import android.graphics.Matrix; +import android.graphics.PointF; import android.graphics.Rect; import android.os.Parcel; import android.os.Parcelable; @@ -34,9 +35,10 @@ import java.util.Objects; * @hide */ public final class PictureInPictureSurfaceTransaction implements Parcelable { + private static final float NOT_SET = -1f; - public final float mPositionX; - public final float mPositionY; + public final float mAlpha; + public final PointF mPosition; public final float[] mFloat9; @@ -45,33 +47,37 @@ public final class PictureInPictureSurfaceTransaction implements Parcelable { public final float mCornerRadius; - private final Rect mWindowCrop = new Rect(); + private final Rect mWindowCrop; - public PictureInPictureSurfaceTransaction(Parcel in) { - mPositionX = in.readFloat(); - mPositionY = in.readFloat(); + private PictureInPictureSurfaceTransaction(Parcel in) { + mAlpha = in.readFloat(); + mPosition = in.readTypedObject(PointF.CREATOR); mFloat9 = new float[9]; in.readFloatArray(mFloat9); mRotation = in.readFloat(); mCornerRadius = in.readFloat(); - mWindowCrop.set(Objects.requireNonNull(in.readTypedObject(Rect.CREATOR))); + mWindowCrop = in.readTypedObject(Rect.CREATOR); } - public PictureInPictureSurfaceTransaction(float positionX, float positionY, - float[] float9, float rotation, float cornerRadius, + private PictureInPictureSurfaceTransaction(float alpha, @Nullable PointF position, + @Nullable float[] float9, float rotation, float cornerRadius, @Nullable Rect windowCrop) { - mPositionX = positionX; - mPositionY = positionY; - mFloat9 = Arrays.copyOf(float9, 9); - mRotation = rotation; - mCornerRadius = cornerRadius; - if (windowCrop != null) { - mWindowCrop.set(windowCrop); + mAlpha = alpha; + mPosition = position; + if (float9 == null) { + mFloat9 = new float[9]; + Matrix.IDENTITY_MATRIX.getValues(mFloat9); + mRotation = 0; + } else { + mFloat9 = Arrays.copyOf(float9, 9); + mRotation = rotation; } + mCornerRadius = cornerRadius; + mWindowCrop = (windowCrop == null) ? null : new Rect(windowCrop); } public PictureInPictureSurfaceTransaction(PictureInPictureSurfaceTransaction other) { - this(other.mPositionX, other.mPositionY, + this(other.mAlpha, other.mPosition, other.mFloat9, other.mRotation, other.mCornerRadius, other.mWindowCrop); } @@ -82,13 +88,18 @@ public final class PictureInPictureSurfaceTransaction implements Parcelable { return matrix; } + /** @return {@code true} if this transaction contains setting corner radius. */ + public boolean hasCornerRadiusSet() { + return mCornerRadius > 0; + } + @Override public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof PictureInPictureSurfaceTransaction)) return false; PictureInPictureSurfaceTransaction that = (PictureInPictureSurfaceTransaction) o; - return Objects.equals(mPositionX, that.mPositionX) - && Objects.equals(mPositionY, that.mPositionY) + return Objects.equals(mAlpha, that.mAlpha) + && Objects.equals(mPosition, that.mPosition) && Arrays.equals(mFloat9, that.mFloat9) && Objects.equals(mRotation, that.mRotation) && Objects.equals(mCornerRadius, that.mCornerRadius) @@ -97,7 +108,7 @@ public final class PictureInPictureSurfaceTransaction implements Parcelable { @Override public int hashCode() { - return Objects.hash(mPositionX, mPositionY, Arrays.hashCode(mFloat9), + return Objects.hash(mAlpha, mPosition, Arrays.hashCode(mFloat9), mRotation, mCornerRadius, mWindowCrop); } @@ -108,8 +119,8 @@ public final class PictureInPictureSurfaceTransaction implements Parcelable { @Override public void writeToParcel(Parcel out, int flags) { - out.writeFloat(mPositionX); - out.writeFloat(mPositionY); + out.writeFloat(mAlpha); + out.writeTypedObject(mPosition, 0 /* flags */); out.writeFloatArray(mFloat9); out.writeFloat(mRotation); out.writeFloat(mCornerRadius); @@ -120,8 +131,8 @@ public final class PictureInPictureSurfaceTransaction implements Parcelable { public String toString() { final Matrix matrix = getMatrix(); return "PictureInPictureSurfaceTransaction(" - + " posX=" + mPositionX - + " posY=" + mPositionY + + " alpha=" + mAlpha + + " position=" + mPosition + " matrix=" + matrix.toShortString() + " rotation=" + mRotation + " cornerRadius=" + mCornerRadius @@ -134,11 +145,20 @@ public final class PictureInPictureSurfaceTransaction implements Parcelable { @NonNull SurfaceControl surfaceControl, @NonNull SurfaceControl.Transaction tx) { final Matrix matrix = surfaceTransaction.getMatrix(); - tx.setMatrix(surfaceControl, matrix, new float[9]) - .setPosition(surfaceControl, - surfaceTransaction.mPositionX, surfaceTransaction.mPositionY) - .setWindowCrop(surfaceControl, surfaceTransaction.mWindowCrop) - .setCornerRadius(surfaceControl, surfaceTransaction.mCornerRadius); + tx.setMatrix(surfaceControl, matrix, new float[9]); + if (surfaceTransaction.mPosition != null) { + tx.setPosition(surfaceControl, + surfaceTransaction.mPosition.x, surfaceTransaction.mPosition.y); + } + if (surfaceTransaction.mWindowCrop != null) { + tx.setWindowCrop(surfaceControl, surfaceTransaction.mWindowCrop); + } + if (surfaceTransaction.hasCornerRadiusSet()) { + tx.setCornerRadius(surfaceControl, surfaceTransaction.mCornerRadius); + } + if (surfaceTransaction.mAlpha != NOT_SET) { + tx.setAlpha(surfaceControl, surfaceTransaction.mAlpha); + } } public static final @android.annotation.NonNull Creator @@ -151,4 +171,44 @@ public final class PictureInPictureSurfaceTransaction implements Parcelable { return new PictureInPictureSurfaceTransaction[size]; } }; + + public static class Builder { + private float mAlpha = NOT_SET; + private PointF mPosition; + private float[] mFloat9; + private float mRotation; + private float mCornerRadius = NOT_SET; + private Rect mWindowCrop; + + public Builder setAlpha(float alpha) { + mAlpha = alpha; + return this; + } + + public Builder setPosition(float x, float y) { + mPosition = new PointF(x, y); + return this; + } + + public Builder setTransform(@NonNull float[] float9, float rotation) { + mFloat9 = Arrays.copyOf(float9, 9); + mRotation = rotation; + return this; + } + + public Builder setCornerRadius(float cornerRadius) { + mCornerRadius = cornerRadius; + return this; + } + + public Builder setWindowCrop(@NonNull Rect windowCrop) { + mWindowCrop = new Rect(windowCrop); + return this; + } + + public PictureInPictureSurfaceTransaction build() { + return new PictureInPictureSurfaceTransaction(mAlpha, mPosition, + mFloat9, mRotation, mCornerRadius, mWindowCrop); + } + } } diff --git a/core/java/android/window/RemoteTransition.aidl b/core/java/android/window/RemoteTransition.aidl new file mode 100644 index 000000000000..f3c3f54410ed --- /dev/null +++ b/core/java/android/window/RemoteTransition.aidl @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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.window; + +parcelable RemoteTransition; diff --git a/core/java/android/window/RemoteTransition.java b/core/java/android/window/RemoteTransition.java new file mode 100644 index 000000000000..4bd15f27a91a --- /dev/null +++ b/core/java/android/window/RemoteTransition.java @@ -0,0 +1,196 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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.window; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.app.IApplicationThread; +import android.os.IBinder; +import android.os.Parcelable; + +import com.android.internal.util.DataClass; + +/** + * Represents a remote transition animation and information required to run it (eg. the app thread + * that needs to be boosted). + * @hide + */ +@DataClass(genToString = true, genSetters = true, genAidl = true) +public class RemoteTransition implements Parcelable { + + /** The actual remote-transition interface used to run the transition animation. */ + private @NonNull IRemoteTransition mRemoteTransition; + + /** The application thread that will be running the remote transition. */ + private @Nullable IApplicationThread mAppThread; + + /** Constructs with no app thread (animation runs in shell). */ + public RemoteTransition(@NonNull IRemoteTransition remoteTransition) { + this(remoteTransition, null /* appThread */); + } + + /** Get the IBinder associated with the underlying IRemoteTransition. */ + public @Nullable IBinder asBinder() { + return mRemoteTransition.asBinder(); + } + + + + // Code below generated by codegen v1.0.23. + // + // DO NOT MODIFY! + // CHECKSTYLE:OFF Generated code + // + // To regenerate run: + // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/window/RemoteTransition.java + // + // To exclude the generated code from IntelliJ auto-formatting enable (one-time): + // Settings > Editor > Code Style > Formatter Control + //@formatter:off + + + /** + * Creates a new RemoteTransition. + * + * @param remoteTransition + * The actual remote-transition interface used to run the transition animation. + * @param appThread + * The application thread that will be running the remote transition. + */ + @DataClass.Generated.Member + public RemoteTransition( + @NonNull IRemoteTransition remoteTransition, + @Nullable IApplicationThread appThread) { + this.mRemoteTransition = remoteTransition; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mRemoteTransition); + this.mAppThread = appThread; + + // onConstructed(); // You can define this method to get a callback + } + + /** + * The actual remote-transition interface used to run the transition animation. + */ + @DataClass.Generated.Member + public @NonNull IRemoteTransition getRemoteTransition() { + return mRemoteTransition; + } + + /** + * The application thread that will be running the remote transition. + */ + @DataClass.Generated.Member + public @Nullable IApplicationThread getAppThread() { + return mAppThread; + } + + /** + * The actual remote-transition interface used to run the transition animation. + */ + @DataClass.Generated.Member + public @NonNull RemoteTransition setRemoteTransition(@NonNull IRemoteTransition value) { + mRemoteTransition = value; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mRemoteTransition); + return this; + } + + /** + * The application thread that will be running the remote transition. + */ + @DataClass.Generated.Member + public @NonNull RemoteTransition setAppThread(@NonNull IApplicationThread value) { + mAppThread = value; + return this; + } + + @Override + @DataClass.Generated.Member + public String toString() { + // You can override field toString logic by defining methods like: + // String fieldNameToString() { ... } + + return "RemoteTransition { " + + "remoteTransition = " + mRemoteTransition + ", " + + "appThread = " + mAppThread + + " }"; + } + + @Override + @DataClass.Generated.Member + public void writeToParcel(@NonNull android.os.Parcel dest, int flags) { + // You can override field parcelling by defining methods like: + // void parcelFieldName(Parcel dest, int flags) { ... } + + byte flg = 0; + if (mAppThread != null) flg |= 0x2; + dest.writeByte(flg); + dest.writeStrongInterface(mRemoteTransition); + if (mAppThread != null) dest.writeStrongInterface(mAppThread); + } + + @Override + @DataClass.Generated.Member + public int describeContents() { return 0; } + + /** @hide */ + @SuppressWarnings({"unchecked", "RedundantCast"}) + @DataClass.Generated.Member + protected RemoteTransition(@NonNull android.os.Parcel in) { + // You can override field unparcelling by defining methods like: + // static FieldType unparcelFieldName(Parcel in) { ... } + + byte flg = in.readByte(); + IRemoteTransition remoteTransition = IRemoteTransition.Stub.asInterface(in.readStrongBinder()); + IApplicationThread appThread = (flg & 0x2) == 0 ? null : IApplicationThread.Stub.asInterface(in.readStrongBinder()); + + this.mRemoteTransition = remoteTransition; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mRemoteTransition); + this.mAppThread = appThread; + + // onConstructed(); // You can define this method to get a callback + } + + @DataClass.Generated.Member + public static final @NonNull Parcelable.Creator CREATOR + = new Parcelable.Creator() { + @Override + public RemoteTransition[] newArray(int size) { + return new RemoteTransition[size]; + } + + @Override + public RemoteTransition createFromParcel(@NonNull android.os.Parcel in) { + return new RemoteTransition(in); + } + }; + + @DataClass.Generated( + time = 1630690027011L, + codegenVersion = "1.0.23", + sourceFile = "frameworks/base/core/java/android/window/RemoteTransition.java", + inputSignatures = "private @android.annotation.NonNull android.window.IRemoteTransition mRemoteTransition\nprivate @android.annotation.Nullable android.app.IApplicationThread mAppThread\npublic @android.annotation.Nullable android.os.IBinder asBinder()\nclass RemoteTransition extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genSetters=true, genAidl=true)") + @Deprecated + private void __metadata() {} + + + //@formatter:on + // End of generated code + +} diff --git a/core/java/android/window/SizeConfigurationBuckets.java b/core/java/android/window/SizeConfigurationBuckets.java index 7422f2449a8d..f474f0a76cc6 100644 --- a/core/java/android/window/SizeConfigurationBuckets.java +++ b/core/java/android/window/SizeConfigurationBuckets.java @@ -16,6 +16,7 @@ package android.window; +import static android.content.pm.ActivityInfo.CONFIG_SCREEN_LAYOUT; import static android.content.pm.ActivityInfo.CONFIG_SCREEN_SIZE; import static android.content.pm.ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE; @@ -25,6 +26,7 @@ import android.content.res.Configuration; import android.os.Parcelable; import android.util.SparseIntArray; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.DataClass; import java.util.Arrays; @@ -54,10 +56,24 @@ public final class SizeConfigurationBuckets implements Parcelable { @Nullable private final int[] mSmallest; + /** Screen Layout Size (screenLayout & SCREENLAYOUT_SIZE_MASK) buckets */ + @Nullable + private final int[] mScreenLayoutSize; + + /** + * Screen Layout Long (screenLayout & SCREENLAYOUT_LONG_MASK) boolean. Only need to know if a + * value is set because only two possible buckets, SCREENLAYOUT_LONG_NO and + * SCREENLAYOUT_LONG_YES, so if either is set, then any change is a bucket change. + */ + private final boolean mScreenLayoutLongSet; + public SizeConfigurationBuckets(Configuration[] sizeConfigurations) { SparseIntArray horizontal = new SparseIntArray(); SparseIntArray vertical = new SparseIntArray(); SparseIntArray smallest = new SparseIntArray(); + SparseIntArray screenLayoutSize = new SparseIntArray(); + int curScreenLayoutSize; + boolean screenLayoutLongSet = false; for (int i = sizeConfigurations.length - 1; i >= 0; i--) { Configuration config = sizeConfigurations[i]; if (config.screenHeightDp != Configuration.SCREEN_HEIGHT_DP_UNDEFINED) { @@ -69,23 +85,42 @@ public final class SizeConfigurationBuckets implements Parcelable { if (config.smallestScreenWidthDp != Configuration.SMALLEST_SCREEN_WIDTH_DP_UNDEFINED) { smallest.put(config.smallestScreenWidthDp, 0); } + if ((curScreenLayoutSize = config.screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) + != Configuration.SCREENLAYOUT_SIZE_UNDEFINED) { + screenLayoutSize.put(curScreenLayoutSize, 0); + } + if (!screenLayoutLongSet && (config.screenLayout & Configuration.SCREENLAYOUT_LONG_MASK) + != Configuration.SCREENLAYOUT_LONG_UNDEFINED) { + screenLayoutLongSet = true; + } } mHorizontal = horizontal.copyKeys(); mVertical = vertical.copyKeys(); mSmallest = smallest.copyKeys(); + mScreenLayoutSize = screenLayoutSize.copyKeys(); + mScreenLayoutLongSet = screenLayoutLongSet; } /** * Get the changes between two configurations but don't count changes in sizes if they don't - * cross boundaries that are important to the app. + * cross boundaries that are important to the app. * * This is a static helper to deal with null `buckets`. When no buckets have been specified, * this actually filters out all 3 size-configs. This is legacy behavior. */ - public static int filterDiff(int diff, Configuration oldConfig, Configuration newConfig, - @Nullable SizeConfigurationBuckets buckets) { + public static int filterDiff(int diff, @NonNull Configuration oldConfig, + @NonNull Configuration newConfig, @Nullable SizeConfigurationBuckets buckets) { + final boolean nonSizeLayoutFieldsUnchanged = + areNonSizeLayoutFieldsUnchanged(oldConfig.screenLayout, newConfig.screenLayout); if (buckets == null) { - return diff & ~(CONFIG_SCREEN_SIZE | CONFIG_SMALLEST_SCREEN_SIZE); + // Only unflip CONFIG_SCREEN_LAYOUT if non-size-related attributes of screen layout do + // not change. + if (nonSizeLayoutFieldsUnchanged) { + return diff & ~(CONFIG_SCREEN_SIZE | CONFIG_SMALLEST_SCREEN_SIZE + | CONFIG_SCREEN_LAYOUT); + } else { + return diff & ~(CONFIG_SCREEN_SIZE | CONFIG_SMALLEST_SCREEN_SIZE); + } } if ((diff & CONFIG_SCREEN_SIZE) != 0) { final boolean crosses = buckets.crossesHorizontalSizeThreshold(oldConfig.screenWidthDp, @@ -103,6 +138,13 @@ public final class SizeConfigurationBuckets implements Parcelable { diff &= ~CONFIG_SMALLEST_SCREEN_SIZE; } } + if ((diff & CONFIG_SCREEN_LAYOUT) != 0 && nonSizeLayoutFieldsUnchanged) { + if (!buckets.crossesScreenLayoutSizeThreshold(oldConfig, newConfig) + && !buckets.crossesScreenLayoutLongThreshold(oldConfig.screenLayout, + newConfig.screenLayout)) { + diff &= ~CONFIG_SCREEN_LAYOUT; + } + } return diff; } @@ -118,6 +160,61 @@ public final class SizeConfigurationBuckets implements Parcelable { return crossesSizeThreshold(mSmallest, firstDp, secondDp); } + /** + * Returns whether a screen layout size threshold has been crossed. + */ + @VisibleForTesting + public boolean crossesScreenLayoutSizeThreshold(@NonNull Configuration firstConfig, + @NonNull Configuration secondConfig) { + // If both the old and new screen layout are equal (both can be undefined), then no + // threshold is crossed. + if ((firstConfig.screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) + == (secondConfig.screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK)) { + return false; + } + // Any time the new layout size is smaller than the old layout size, the activity has + // crossed a size threshold because layout size represents the smallest possible size the + // activity can occupy. + if (!secondConfig.isLayoutSizeAtLeast(firstConfig.screenLayout + & Configuration.SCREENLAYOUT_SIZE_MASK)) { + return true; + } + // If the new layout size is at least as large as the old layout size, then check if the new + // layout size has crossed a threshold. + if (mScreenLayoutSize != null) { + for (int screenLayoutSize : mScreenLayoutSize) { + if (firstConfig.isLayoutSizeAtLeast(screenLayoutSize) + != secondConfig.isLayoutSizeAtLeast(screenLayoutSize)) { + return true; + } + } + } + return false; + } + + private boolean crossesScreenLayoutLongThreshold(int firstScreenLayout, + int secondScreenLayout) { + final int firstScreenLayoutLongValue = firstScreenLayout + & Configuration.SCREENLAYOUT_LONG_MASK; + final int secondScreenLayoutLongValue = secondScreenLayout + & Configuration.SCREENLAYOUT_LONG_MASK; + return mScreenLayoutLongSet && firstScreenLayoutLongValue != secondScreenLayoutLongValue; + } + + /** + * Returns whether non-size related screen layout attributes have changed. If true, then + * {@link ActivityInfo#CONFIG_SCREEN_LAYOUT} should not be filtered out in + * {@link SizeConfigurationBuckets#filterDiff()} because the non-size related attributes + * do not have a bucket range like the size-related attributes of screen layout. + */ + @VisibleForTesting + public static boolean areNonSizeLayoutFieldsUnchanged(int oldScreenLayout, + int newScreenLayout) { + final int nonSizeRelatedFields = Configuration.SCREENLAYOUT_LAYOUTDIR_MASK + | Configuration.SCREENLAYOUT_ROUND_MASK | Configuration.SCREENLAYOUT_COMPAT_NEEDED; + return (oldScreenLayout & nonSizeRelatedFields) == (newScreenLayout & nonSizeRelatedFields); + } + /** * The purpose of this method is to decide whether the activity needs to be relaunched upon * changing its size. In most cases the activities don't need to be relaunched, if the resize @@ -132,7 +229,8 @@ public final class SizeConfigurationBuckets implements Parcelable { * it resizes width from 620dp to 700dp, it won't be relaunched as it stays on the same side * of the threshold. */ - private static boolean crossesSizeThreshold(int[] thresholds, int firstDp, + @VisibleForTesting + public static boolean crossesSizeThreshold(int[] thresholds, int firstDp, int secondDp) { if (thresholds == null) { return false; @@ -150,12 +248,13 @@ public final class SizeConfigurationBuckets implements Parcelable { @Override public String toString() { return Arrays.toString(mHorizontal) + " " + Arrays.toString(mVertical) + " " - + Arrays.toString(mSmallest); + + Arrays.toString(mSmallest) + " " + Arrays.toString(mScreenLayoutSize) + " " + + mScreenLayoutLongSet; } - // Code below generated by codegen v1.0.22. + // Code below generated by codegen v1.0.23. // // DO NOT MODIFY! // CHECKSTYLE:OFF Generated code @@ -177,15 +276,25 @@ public final class SizeConfigurationBuckets implements Parcelable { * Vertical (screenHeightDp) buckets * @param smallest * Smallest (smallestScreenWidthDp) buckets + * @param screenLayoutSize + * Screen Layout Size (screenLayout & SCREENLAYOUT_SIZE_MASK) buckets + * @param screenLayoutLongSet + * Screen Layout Long (screenLayout & SCREENLAYOUT_LONG_MASK) boolean. Only need to know if a + * value is set because only two possible buckets, SCREENLAYOUT_LONG_NO and + * SCREENLAYOUT_LONG_YES, so if either is set, then any change is a bucket change. */ @DataClass.Generated.Member public SizeConfigurationBuckets( @Nullable int[] horizontal, @Nullable int[] vertical, - @Nullable int[] smallest) { + @Nullable int[] smallest, + @Nullable int[] screenLayoutSize, + boolean screenLayoutLongSet) { this.mHorizontal = horizontal; this.mVertical = vertical; this.mSmallest = smallest; + this.mScreenLayoutSize = screenLayoutSize; + this.mScreenLayoutLongSet = screenLayoutLongSet; // onConstructed(); // You can define this method to get a callback } @@ -214,6 +323,24 @@ public final class SizeConfigurationBuckets implements Parcelable { return mSmallest; } + /** + * Screen Layout Size (screenLayout & SCREENLAYOUT_SIZE_MASK) buckets + */ + @DataClass.Generated.Member + public @Nullable int[] getScreenLayoutSize() { + return mScreenLayoutSize; + } + + /** + * Screen Layout Long (screenLayout & SCREENLAYOUT_LONG_MASK) boolean. Only need to know if a + * value is set because only two possible buckets, SCREENLAYOUT_LONG_NO and + * SCREENLAYOUT_LONG_YES, so if either is set, then any change is a bucket change. + */ + @DataClass.Generated.Member + public boolean isScreenLayoutLongSet() { + return mScreenLayoutLongSet; + } + @Override @DataClass.Generated.Member public void writeToParcel(@NonNull android.os.Parcel dest, int flags) { @@ -221,13 +348,16 @@ public final class SizeConfigurationBuckets implements Parcelable { // void parcelFieldName(Parcel dest, int flags) { ... } byte flg = 0; + if (mScreenLayoutLongSet) flg |= 0x10; if (mHorizontal != null) flg |= 0x1; if (mVertical != null) flg |= 0x2; if (mSmallest != null) flg |= 0x4; + if (mScreenLayoutSize != null) flg |= 0x8; dest.writeByte(flg); if (mHorizontal != null) dest.writeIntArray(mHorizontal); if (mVertical != null) dest.writeIntArray(mVertical); if (mSmallest != null) dest.writeIntArray(mSmallest); + if (mScreenLayoutSize != null) dest.writeIntArray(mScreenLayoutSize); } @Override @@ -242,13 +372,17 @@ public final class SizeConfigurationBuckets implements Parcelable { // static FieldType unparcelFieldName(Parcel in) { ... } byte flg = in.readByte(); + boolean screenLayoutLongSet = (flg & 0x10) != 0; int[] horizontal = (flg & 0x1) == 0 ? null : in.createIntArray(); int[] vertical = (flg & 0x2) == 0 ? null : in.createIntArray(); int[] smallest = (flg & 0x4) == 0 ? null : in.createIntArray(); + int[] screenLayoutSize = (flg & 0x8) == 0 ? null : in.createIntArray(); this.mHorizontal = horizontal; this.mVertical = vertical; this.mSmallest = smallest; + this.mScreenLayoutSize = screenLayoutSize; + this.mScreenLayoutLongSet = screenLayoutLongSet; // onConstructed(); // You can define this method to get a callback } @@ -268,10 +402,10 @@ public final class SizeConfigurationBuckets implements Parcelable { }; @DataClass.Generated( - time = 1615845864280L, - codegenVersion = "1.0.22", + time = 1628273704583L, + codegenVersion = "1.0.23", sourceFile = "frameworks/base/core/java/android/window/SizeConfigurationBuckets.java", - inputSignatures = "private final @android.annotation.Nullable int[] mHorizontal\nprivate final @android.annotation.Nullable int[] mVertical\nprivate final @android.annotation.Nullable int[] mSmallest\npublic static int filterDiff(int,android.content.res.Configuration,android.content.res.Configuration,android.window.SizeConfigurationBuckets)\nprivate boolean crossesHorizontalSizeThreshold(int,int)\nprivate boolean crossesVerticalSizeThreshold(int,int)\nprivate boolean crossesSmallestSizeThreshold(int,int)\nprivate static boolean crossesSizeThreshold(int[],int,int)\npublic @java.lang.Override java.lang.String toString()\nclass SizeConfigurationBuckets extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genAidl=true)") + inputSignatures = "private final @android.annotation.Nullable int[] mHorizontal\nprivate final @android.annotation.Nullable int[] mVertical\nprivate final @android.annotation.Nullable int[] mSmallest\nprivate final @android.annotation.Nullable int[] mScreenLayoutSize\nprivate final boolean mScreenLayoutLongSet\npublic static int filterDiff(int,android.content.res.Configuration,android.content.res.Configuration,android.window.SizeConfigurationBuckets)\nprivate boolean crossesHorizontalSizeThreshold(int,int)\nprivate boolean crossesVerticalSizeThreshold(int,int)\nprivate boolean crossesSmallestSizeThreshold(int,int)\npublic @com.android.internal.annotations.VisibleForTesting boolean crossesScreenLayoutSizeThreshold(android.content.res.Configuration,android.content.res.Configuration)\nprivate boolean crossesScreenLayoutLongThreshold(int,int)\npublic static @com.android.internal.annotations.VisibleForTesting boolean areNonSizeLayoutFieldsUnchanged(int,int)\npublic static @com.android.internal.annotations.VisibleForTesting boolean crossesSizeThreshold(int[],int,int)\npublic @java.lang.Override java.lang.String toString()\nclass SizeConfigurationBuckets extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genAidl=true)") @Deprecated private void __metadata() {} diff --git a/core/java/android/window/SplashScreen.java b/core/java/android/window/SplashScreen.java index 3e0075857402..090dbff488e9 100644 --- a/core/java/android/window/SplashScreen.java +++ b/core/java/android/window/SplashScreen.java @@ -42,6 +42,11 @@ import java.util.ArrayList; * Activity.getSplashScreen() to get the SplashScreen.

    */ public interface SplashScreen { + /** + * The splash screen style is not defined. + * @hide + */ + int SPLASH_SCREEN_STYLE_UNDEFINED = -1; /** * Force splash screen to be empty. * @hide @@ -55,6 +60,7 @@ public interface SplashScreen { /** @hide */ @IntDef(prefix = { "SPLASH_SCREEN_STYLE_" }, value = { + SPLASH_SCREEN_STYLE_UNDEFINED, SPLASH_SCREEN_STYLE_EMPTY, SPLASH_SCREEN_STYLE_ICON }) @@ -92,6 +98,9 @@ public interface SplashScreen { * overrides and persists the theme used for the {@link SplashScreen} of this application. *

    * To reset to the default theme, set this the themeId to {@link Resources#ID_NULL}. + *

    + * Note: The theme name must be stable across versions, otherwise it won't be found + * after your application is updated. */ void setSplashScreenTheme(@StyleRes int themeId); @@ -241,7 +250,6 @@ public interface SplashScreen { public void handOverSplashScreenView(@NonNull IBinder token, @NonNull SplashScreenView splashScreenView) { - transferSurface(splashScreenView); dispatchOnExitAnimation(token, splashScreenView); } @@ -265,9 +273,5 @@ public interface SplashScreen { return impl != null && impl.mExitAnimationListener != null; } } - - private void transferSurface(@NonNull SplashScreenView splashScreenView) { - splashScreenView.transferSurface(); - } } } diff --git a/core/java/android/window/SplashScreenView.java b/core/java/android/window/SplashScreenView.java index 6a875d1be65d..f04155d112d4 100644 --- a/core/java/android/window/SplashScreenView.java +++ b/core/java/android/window/SplashScreenView.java @@ -20,6 +20,10 @@ import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACK import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION; import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS; +import static com.android.internal.jank.InteractionJankMonitor.CUJ_SPLASHSCREEN_AVD; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; import android.annotation.ColorInt; import android.annotation.NonNull; import android.annotation.Nullable; @@ -54,11 +58,13 @@ import android.widget.FrameLayout; import android.widget.ImageView; import com.android.internal.R; +import com.android.internal.jank.InteractionJankMonitor; import com.android.internal.policy.DecorView; import com.android.internal.util.ContrastColorUtil; import java.time.Duration; import java.time.Instant; +import java.util.function.Consumer; /** *

    The view which allows an activity to customize its splash screen exit animation.

    @@ -144,6 +150,7 @@ public final class SplashScreenView extends FrameLayout { private Bitmap mParceledBrandingBitmap; private Instant mIconAnimationStart; private Duration mIconAnimationDuration; + private Consumer mUiThreadInitTask; public Builder(@NonNull Context context) { mContext = context; @@ -231,6 +238,15 @@ public final class SplashScreenView extends FrameLayout { return this; } + /** + * Set the Runnable that can receive the task which should be executed on UI thread. + * @param uiThreadInitTask + */ + public Builder setUiThreadInitConsumer(Consumer uiThreadInitTask) { + mUiThreadInitTask = uiThreadInitTask; + return this; + } + /** * Set the Drawable object and size for the branding view. */ @@ -262,7 +278,11 @@ public final class SplashScreenView extends FrameLayout { // center icon if (mIconDrawable instanceof SplashScreenView.IconAnimateListener || mSurfacePackage != null) { - view.mIconView = createSurfaceView(view); + if (mUiThreadInitTask != null) { + mUiThreadInitTask.accept(() -> view.mIconView = createSurfaceView(view)); + } else { + view.mIconView = createSurfaceView(view); + } view.initIconAnimation(mIconDrawable, mIconAnimationDuration != null ? mIconAnimationDuration.toMillis() : 0); view.mIconAnimationStart = mIconAnimationStart; @@ -316,6 +336,7 @@ public final class SplashScreenView extends FrameLayout { } private SurfaceView createSurfaceView(@NonNull SplashScreenView view) { + Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "SplashScreenView#createSurfaceView"); final Context viewContext = view.getContext(); final SurfaceView surfaceView = new SurfaceView(viewContext); surfaceView.setPadding(0, 0, 0, 0); @@ -361,6 +382,7 @@ public final class SplashScreenView extends FrameLayout { view.addView(surfaceView); view.mSurfaceView = surfaceView; + Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); return surfaceView; } } @@ -447,7 +469,10 @@ public final class SplashScreenView extends FrameLayout { } - void transferSurface() { + /** + * @hide + */ + public void syncTransferSurfaceOnDraw() { if (mSurfacePackage == null) { return; } @@ -457,8 +482,8 @@ public final class SplashScreenView extends FrameLayout { String.format("SurfacePackage'surface reparented to %s", parent))); Log.d(TAG, "Transferring surface " + mSurfaceView.toString()); } - mSurfaceView.setChildSurfacePackage(mSurfacePackage); + mSurfaceView.setChildSurfacePackageOnDraw(mSurfacePackage); } void initIconAnimation(Drawable iconDrawable, long duration) { @@ -467,6 +492,23 @@ public final class SplashScreenView extends FrameLayout { } IconAnimateListener aniDrawable = (IconAnimateListener) iconDrawable; aniDrawable.prepareAnimate(duration, this::animationStartCallback); + aniDrawable.setAnimationJankMonitoring(new AnimatorListenerAdapter() { + @Override + public void onAnimationCancel(Animator animation) { + InteractionJankMonitor.getInstance().cancel(CUJ_SPLASHSCREEN_AVD); + } + + @Override + public void onAnimationEnd(Animator animation) { + InteractionJankMonitor.getInstance().end(CUJ_SPLASHSCREEN_AVD); + } + + @Override + public void onAnimationStart(Animator animation) { + InteractionJankMonitor.getInstance().begin( + SplashScreenView.this, CUJ_SPLASHSCREEN_AVD); + } + }); } private void animationStartCallback() { @@ -516,10 +558,6 @@ public final class SplashScreenView extends FrameLayout { restoreSystemUIColors(); mWindow = null; } - if (mHostActivity != null) { - mHostActivity.setSplashScreenView(null); - mHostActivity = null; - } mHasRemoved = true; } @@ -532,23 +570,32 @@ public final class SplashScreenView extends FrameLayout { private void releaseAnimationSurfaceHost() { if (mSurfaceHost != null && !mIsCopied) { - final SurfaceControlViewHost finalSurfaceHost = mSurfaceHost; + if (DEBUG) { + Log.d(TAG, + "Shell removed splash screen." + + " Releasing SurfaceControlViewHost on thread #" + + Thread.currentThread().getId()); + } + releaseIconHost(mSurfaceHost); mSurfaceHost = null; - finalSurfaceHost.getView().post(() -> { - if (DEBUG) { - Log.d(TAG, - "Shell removed splash screen." - + " Releasing SurfaceControlViewHost on thread #" - + Thread.currentThread().getId()); - } - finalSurfaceHost.release(); - }); } else if (mSurfacePackage != null && mSurfaceHost == null) { mSurfacePackage = null; mClientCallback.sendResult(null); } } + /** + * Release the host which hold the SurfaceView of the icon. + * @hide + */ + public static void releaseIconHost(SurfaceControlViewHost host) { + final Drawable background = host.getView().getBackground(); + if (background instanceof SplashScreenView.IconAnimateListener) { + ((SplashScreenView.IconAnimateListener) background).stopAnimation(); + } + host.release(); + } + /** * Called when this view is attached to an activity. This also makes SystemUI colors * transparent so the content of splash screen view can draw fully. @@ -556,7 +603,6 @@ public final class SplashScreenView extends FrameLayout { * @hide */ public void attachHostActivityAndSetSystemUIColors(Activity activity, Window window) { - activity.setSplashScreenView(this); mHostActivity = activity; mWindow = window; final WindowManager.LayoutParams attr = window.getAttributes(); @@ -640,6 +686,17 @@ public final class SplashScreenView extends FrameLayout { * @return true if this drawable object can also be animated and it can be played now. */ boolean prepareAnimate(long duration, Runnable startListener); + + /** + * Stop animation. + */ + void stopAnimation(); + + /** + * Provides a chance to start interaction jank monitoring in avd animation. + * @param listener a listener to start jank monitoring + */ + default void setAnimationJankMonitoring(AnimatorListenerAdapter listener) {} } /** diff --git a/core/java/android/window/StartingWindowInfo.java b/core/java/android/window/StartingWindowInfo.java index 8c64474dc887..5950e9fc6456 100644 --- a/core/java/android/window/StartingWindowInfo.java +++ b/core/java/android/window/StartingWindowInfo.java @@ -19,13 +19,13 @@ package android.window; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.TestApi; import android.app.ActivityManager; import android.app.TaskInfo; import android.content.pm.ActivityInfo; import android.os.Parcel; import android.os.Parcelable; import android.view.InsetsState; +import android.view.InsetsVisibilities; import android.view.WindowManager; /** @@ -33,7 +33,6 @@ import android.view.WindowManager; * start in the system. * @hide */ -@TestApi public final class StartingWindowInfo implements Parcelable { /** * Prefer nothing or not care the type of starting window. @@ -165,7 +164,13 @@ public final class StartingWindowInfo implements Parcelable { * TaskSnapshot. * @hide */ - public TaskSnapshot mTaskSnapshot; + public TaskSnapshot taskSnapshot; + + /** + * The requested insets visibility of the top main window. + * @hide + */ + public final InsetsVisibilities requestedVisibilities = new InsetsVisibilities(); public StartingWindowInfo() { @@ -190,7 +195,8 @@ public final class StartingWindowInfo implements Parcelable { dest.writeTypedObject(mainWindowLayoutParams, flags); dest.writeInt(splashScreenThemeResId); dest.writeBoolean(isKeyguardOccluded); - dest.writeTypedObject(mTaskSnapshot, flags); + dest.writeTypedObject(taskSnapshot, flags); + requestedVisibilities.writeToParcel(dest, flags); } void readFromParcel(@NonNull Parcel source) { @@ -203,7 +209,8 @@ public final class StartingWindowInfo implements Parcelable { mainWindowLayoutParams = source.readTypedObject(WindowManager.LayoutParams.CREATOR); splashScreenThemeResId = source.readInt(); isKeyguardOccluded = source.readBoolean(); - mTaskSnapshot = source.readTypedObject(TaskSnapshot.CREATOR); + taskSnapshot = source.readTypedObject(TaskSnapshot.CREATOR); + requestedVisibilities.readFromParcel(source); } @Override diff --git a/core/java/android/window/StartingWindowRemovalInfo.aidl b/core/java/android/window/StartingWindowRemovalInfo.aidl new file mode 100644 index 000000000000..8e4ac0453f83 --- /dev/null +++ b/core/java/android/window/StartingWindowRemovalInfo.aidl @@ -0,0 +1,20 @@ +/** + * Copyright (c) 2021, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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.window; + +/** @hide */ +parcelable StartingWindowRemovalInfo; \ No newline at end of file diff --git a/core/java/android/window/StartingWindowRemovalInfo.java b/core/java/android/window/StartingWindowRemovalInfo.java new file mode 100644 index 000000000000..573db0d58625 --- /dev/null +++ b/core/java/android/window/StartingWindowRemovalInfo.java @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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.window; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.graphics.Rect; +import android.os.Parcel; +import android.os.Parcelable; +import android.view.SurfaceControl; + +/** + * Information when removing a starting window of a particular task. + * @hide + */ +public final class StartingWindowRemovalInfo implements Parcelable { + + /** + * The identifier of a task. + * @hide + */ + public int taskId; + + /** + * The animation container layer of the top activity. + * @hide + */ + @Nullable + public SurfaceControl windowAnimationLeash; + + /** + * The main window frame for the window of the top activity. + * @hide + */ + @Nullable + public Rect mainFrame; + + /** + * Whether need to play reveal animation. + * @hide + */ + public boolean playRevealAnimation; + + /** + * Whether need to defer removing the starting window for IME. + * @hide + */ + public boolean deferRemoveForIme; + + public StartingWindowRemovalInfo() { + + } + + private StartingWindowRemovalInfo(@NonNull Parcel source) { + readFromParcel(source); + } + + @Override + public int describeContents() { + return 0; + } + + void readFromParcel(@NonNull Parcel source) { + taskId = source.readInt(); + windowAnimationLeash = source.readTypedObject(SurfaceControl.CREATOR); + mainFrame = source.readTypedObject(Rect.CREATOR); + playRevealAnimation = source.readBoolean(); + deferRemoveForIme = source.readBoolean(); + } + + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeInt(taskId); + dest.writeTypedObject(windowAnimationLeash, flags); + dest.writeTypedObject(mainFrame, flags); + dest.writeBoolean(playRevealAnimation); + dest.writeBoolean(deferRemoveForIme); + } + + @Override + public String toString() { + return "StartingWindowRemovalInfo{taskId=" + taskId + + " frame=" + mainFrame + + " playRevealAnimation=" + playRevealAnimation + + " deferRemoveForIme=" + deferRemoveForIme + "}"; + } + + public static final @android.annotation.NonNull Creator CREATOR = + new Creator() { + public StartingWindowRemovalInfo createFromParcel(@NonNull Parcel source) { + return new StartingWindowRemovalInfo(source); + } + public StartingWindowRemovalInfo[] newArray(int size) { + return new StartingWindowRemovalInfo[size]; + } + }; +} diff --git a/core/java/android/window/TaskFragmentCreationParams.aidl b/core/java/android/window/TaskFragmentCreationParams.aidl new file mode 100644 index 000000000000..fde50892640b --- /dev/null +++ b/core/java/android/window/TaskFragmentCreationParams.aidl @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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.window; + +/** + * Data object for options to create TaskFragment with. + * @hide + */ +parcelable TaskFragmentCreationParams; diff --git a/core/java/android/window/TaskFragmentCreationParams.java b/core/java/android/window/TaskFragmentCreationParams.java new file mode 100644 index 000000000000..81ab7836435d --- /dev/null +++ b/core/java/android/window/TaskFragmentCreationParams.java @@ -0,0 +1,193 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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.window; + +import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; +import static android.app.WindowConfiguration.WindowingMode; + +import android.annotation.NonNull; +import android.annotation.TestApi; +import android.graphics.Rect; +import android.os.IBinder; +import android.os.Parcel; +import android.os.Parcelable; + +/** + * Data object for options to create TaskFragment with. + * @hide + */ +@TestApi +public final class TaskFragmentCreationParams implements Parcelable { + + /** The organizer that will organize this TaskFragment. */ + @NonNull + private final TaskFragmentOrganizerToken mOrganizer; + + /** + * Unique token assigned from the client organizer to identify the {@link TaskFragmentInfo} when + * a new TaskFragment is created with this option. + */ + @NonNull + private final IBinder mFragmentToken; + + /** + * Activity token used to identify the leaf Task to create the TaskFragment in. It has to belong + * to the same app as the root Activity of the target Task. + */ + @NonNull + private final IBinder mOwnerToken; + + /** The initial bounds of the TaskFragment. Fills parent if empty. */ + @NonNull + private final Rect mInitialBounds = new Rect(); + + /** The initial windowing mode of the TaskFragment. Inherits from parent if not set. */ + @WindowingMode + private int mWindowingMode = WINDOWING_MODE_UNDEFINED; + + private TaskFragmentCreationParams( + @NonNull TaskFragmentOrganizerToken organizer, + @NonNull IBinder fragmentToken, @NonNull IBinder ownerToken) { + mOrganizer = organizer; + mFragmentToken = fragmentToken; + mOwnerToken = ownerToken; + } + + @NonNull + public TaskFragmentOrganizerToken getOrganizer() { + return mOrganizer; + } + + @NonNull + public IBinder getFragmentToken() { + return mFragmentToken; + } + + @NonNull + public IBinder getOwnerToken() { + return mOwnerToken; + } + + @NonNull + public Rect getInitialBounds() { + return mInitialBounds; + } + + @WindowingMode + public int getWindowingMode() { + return mWindowingMode; + } + + private TaskFragmentCreationParams(Parcel in) { + mOrganizer = TaskFragmentOrganizerToken.CREATOR.createFromParcel(in); + mFragmentToken = in.readStrongBinder(); + mOwnerToken = in.readStrongBinder(); + mInitialBounds.readFromParcel(in); + mWindowingMode = in.readInt(); + } + + /** @hide */ + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + mOrganizer.writeToParcel(dest, flags); + dest.writeStrongBinder(mFragmentToken); + dest.writeStrongBinder(mOwnerToken); + mInitialBounds.writeToParcel(dest, flags); + dest.writeInt(mWindowingMode); + } + + @NonNull + public static final Creator CREATOR = + new Creator() { + @Override + public TaskFragmentCreationParams createFromParcel(Parcel in) { + return new TaskFragmentCreationParams(in); + } + + @Override + public TaskFragmentCreationParams[] newArray(int size) { + return new TaskFragmentCreationParams[size]; + } + }; + + @Override + public String toString() { + return "TaskFragmentCreationParams{" + + " organizer=" + mOrganizer + + " fragmentToken=" + mFragmentToken + + " ownerToken=" + mOwnerToken + + " initialBounds=" + mInitialBounds + + " windowingMode=" + mWindowingMode + + "}"; + } + + /** @hide */ + @Override + public int describeContents() { + return 0; + } + + /** Builder to construct the options to create TaskFragment with. */ + public static final class Builder { + + @NonNull + private final TaskFragmentOrganizerToken mOrganizer; + + @NonNull + private final IBinder mFragmentToken; + + @NonNull + private final IBinder mOwnerToken; + + @NonNull + private final Rect mInitialBounds = new Rect(); + + @WindowingMode + private int mWindowingMode = WINDOWING_MODE_UNDEFINED; + + public Builder(@NonNull TaskFragmentOrganizerToken organizer, + @NonNull IBinder fragmentToken, @NonNull IBinder ownerToken) { + mOrganizer = organizer; + mFragmentToken = fragmentToken; + mOwnerToken = ownerToken; + } + + /** Sets the initial bounds for the TaskFragment. */ + @NonNull + public Builder setInitialBounds(@NonNull Rect bounds) { + mInitialBounds.set(bounds); + return this; + } + + /** Sets the initial windowing mode for the TaskFragment. */ + @NonNull + public Builder setWindowingMode(@WindowingMode int windowingMode) { + mWindowingMode = windowingMode; + return this; + } + + /** Constructs the options to create TaskFragment with. */ + @NonNull + public TaskFragmentCreationParams build() { + final TaskFragmentCreationParams result = new TaskFragmentCreationParams( + mOrganizer, mFragmentToken, mOwnerToken); + result.mInitialBounds.set(mInitialBounds); + result.mWindowingMode = mWindowingMode; + return result; + } + } +} diff --git a/core/java/android/window/TaskFragmentInfo.aidl b/core/java/android/window/TaskFragmentInfo.aidl new file mode 100644 index 000000000000..461a7364803f --- /dev/null +++ b/core/java/android/window/TaskFragmentInfo.aidl @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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.window; + +/** + * Stores information about a particular TaskFragment. + * @hide + */ +parcelable TaskFragmentInfo; diff --git a/core/java/android/window/TaskFragmentInfo.java b/core/java/android/window/TaskFragmentInfo.java new file mode 100644 index 000000000000..a118f9a8188f --- /dev/null +++ b/core/java/android/window/TaskFragmentInfo.java @@ -0,0 +1,227 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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.window; + +import static android.app.WindowConfiguration.WindowingMode; + +import static java.util.Objects.requireNonNull; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.TestApi; +import android.content.res.Configuration; +import android.graphics.Point; +import android.os.IBinder; +import android.os.Parcel; +import android.os.Parcelable; + +import java.util.ArrayList; +import java.util.List; + +/** + * Stores information about a particular TaskFragment. + * @hide + */ +@TestApi +public final class TaskFragmentInfo implements Parcelable { + + /** + * Client assigned unique token in {@link TaskFragmentCreationParams#getFragmentToken()} to + * create this TaskFragment with. + */ + @NonNull + private final IBinder mFragmentToken; + + @NonNull + private final WindowContainerToken mToken; + + @NonNull + private final Configuration mConfiguration = new Configuration(); + + /** Whether the TaskFragment contains any child Window Container. */ + private final boolean mIsEmpty; + + /** The number of the running activities in the TaskFragment. */ + private final int mRunningActivityCount; + + /** Whether this TaskFragment is visible on the window hierarchy. */ + private final boolean mIsVisible; + + /** + * List of Activity tokens that are children of this TaskFragment. It only contains Activities + * that belong to the organizer process for security. + */ + @NonNull + private final List mActivities = new ArrayList<>(); + + /** Relative position of the fragment's top left corner in the parent container. */ + private final Point mPositionInParent; + + /** + * Whether the last running activity in the TaskFragment was finished due to clearing task while + * launching an activity in the host Task. + */ + private final boolean mIsTaskClearedForReuse; + + /** @hide */ + public TaskFragmentInfo( + @NonNull IBinder fragmentToken, @NonNull WindowContainerToken token, + @NonNull Configuration configuration, boolean isEmpty, int runningActivityCount, + boolean isVisible, @NonNull List activities, @NonNull Point positionInParent, + boolean isTaskClearedForReuse) { + mFragmentToken = requireNonNull(fragmentToken); + mToken = requireNonNull(token); + mConfiguration.setTo(configuration); + mIsEmpty = isEmpty; + mRunningActivityCount = runningActivityCount; + mIsVisible = isVisible; + mActivities.addAll(activities); + mPositionInParent = requireNonNull(positionInParent); + mIsTaskClearedForReuse = isTaskClearedForReuse; + } + + @NonNull + public IBinder getFragmentToken() { + return mFragmentToken; + } + + @NonNull + public WindowContainerToken getToken() { + return mToken; + } + + @NonNull + public Configuration getConfiguration() { + return mConfiguration; + } + + public boolean isEmpty() { + return mIsEmpty; + } + + public boolean hasRunningActivity() { + return mRunningActivityCount > 0; + } + + public int getRunningActivityCount() { + return mRunningActivityCount; + } + + public boolean isVisible() { + return mIsVisible; + } + + @NonNull + public List getActivities() { + return mActivities; + } + + /** Returns the relative position of the fragment's top left corner in the parent container. */ + @NonNull + public Point getPositionInParent() { + return mPositionInParent; + } + + public boolean isTaskClearedForReuse() { + return mIsTaskClearedForReuse; + } + + @WindowingMode + public int getWindowingMode() { + return mConfiguration.windowConfiguration.getWindowingMode(); + } + + /** + * Returns {@code true} if the parameters that are important for task fragment organizers are + * equal between this {@link TaskFragmentInfo} and {@param that}. + */ + public boolean equalsForTaskFragmentOrganizer(@Nullable TaskFragmentInfo that) { + if (that == null) { + return false; + } + + return mFragmentToken.equals(that.mFragmentToken) + && mToken.equals(that.mToken) + && mIsEmpty == that.mIsEmpty + && mRunningActivityCount == that.mRunningActivityCount + && mIsVisible == that.mIsVisible + && getWindowingMode() == that.getWindowingMode() + && mActivities.equals(that.mActivities) + && mPositionInParent.equals(that.mPositionInParent) + && mIsTaskClearedForReuse == that.mIsTaskClearedForReuse; + } + + private TaskFragmentInfo(Parcel in) { + mFragmentToken = in.readStrongBinder(); + mToken = in.readTypedObject(WindowContainerToken.CREATOR); + mConfiguration.readFromParcel(in); + mIsEmpty = in.readBoolean(); + mRunningActivityCount = in.readInt(); + mIsVisible = in.readBoolean(); + in.readBinderList(mActivities); + mPositionInParent = requireNonNull(in.readTypedObject(Point.CREATOR)); + mIsTaskClearedForReuse = in.readBoolean(); + } + + /** @hide */ + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeStrongBinder(mFragmentToken); + dest.writeTypedObject(mToken, flags); + mConfiguration.writeToParcel(dest, flags); + dest.writeBoolean(mIsEmpty); + dest.writeInt(mRunningActivityCount); + dest.writeBoolean(mIsVisible); + dest.writeBinderList(mActivities); + dest.writeTypedObject(mPositionInParent, flags); + dest.writeBoolean(mIsTaskClearedForReuse); + } + + @NonNull + public static final Creator CREATOR = + new Creator() { + @Override + public TaskFragmentInfo createFromParcel(Parcel in) { + return new TaskFragmentInfo(in); + } + + @Override + public TaskFragmentInfo[] newArray(int size) { + return new TaskFragmentInfo[size]; + } + }; + + @Override + public String toString() { + return "TaskFragmentInfo{" + + " fragmentToken=" + mFragmentToken + + " token=" + mToken + + " isEmpty=" + mIsEmpty + + " runningActivityCount=" + mRunningActivityCount + + " isVisible=" + mIsVisible + + " activities=" + mActivities + + " positionInParent=" + mPositionInParent + + " isTaskClearedForReuse=" + mIsTaskClearedForReuse + + "}"; + } + + /** @hide */ + @Override + public int describeContents() { + return 0; + } +} diff --git a/core/java/android/window/TaskFragmentOrganizer.java b/core/java/android/window/TaskFragmentOrganizer.java new file mode 100644 index 000000000000..9c2fde04e4d2 --- /dev/null +++ b/core/java/android/window/TaskFragmentOrganizer.java @@ -0,0 +1,232 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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.window; + +import android.annotation.CallSuper; +import android.annotation.NonNull; +import android.annotation.TestApi; +import android.content.res.Configuration; +import android.os.Bundle; +import android.os.IBinder; +import android.os.RemoteException; +import android.view.RemoteAnimationDefinition; + +import java.util.concurrent.Executor; + +/** + * Interface for WindowManager to delegate control of {@code TaskFragment}. + * @hide + */ +@TestApi +public class TaskFragmentOrganizer extends WindowOrganizer { + + /** + * Key to the exception in {@link Bundle} in {@link ITaskFragmentOrganizer#onTaskFragmentError}. + */ + private static final String KEY_ERROR_CALLBACK_EXCEPTION = "fragment_exception"; + + /** + * Creates a {@link Bundle} with an exception that can be passed to + * {@link ITaskFragmentOrganizer#onTaskFragmentError}. + * @hide + */ + public static Bundle putExceptionInBundle(@NonNull Throwable exception) { + final Bundle exceptionBundle = new Bundle(); + exceptionBundle.putSerializable(KEY_ERROR_CALLBACK_EXCEPTION, exception); + return exceptionBundle; + } + + /** + * Callbacks from WM Core are posted on this executor. + */ + private final Executor mExecutor; + + public TaskFragmentOrganizer(@NonNull Executor executor) { + mExecutor = executor; + } + + /** + * Gets the executor to run callbacks on. + */ + @NonNull + public Executor getExecutor() { + return mExecutor; + } + + /** + * Registers a TaskFragmentOrganizer to manage TaskFragments. + */ + @CallSuper + public void registerOrganizer() { + try { + getController().registerOrganizer(mInterface); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Unregisters a previously registered TaskFragmentOrganizer. + */ + @CallSuper + public void unregisterOrganizer() { + try { + getController().unregisterOrganizer(mInterface); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Registers remote animations per transition type for the organizer. It will override the + * animations if the transition only contains windows that belong to the organized + * TaskFragments. + * @hide + */ + @CallSuper + public void registerRemoteAnimations(@NonNull RemoteAnimationDefinition definition) { + try { + getController().registerRemoteAnimations(mInterface, definition); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Unregisters remote animations per transition type for the organizer. + * @hide + */ + @CallSuper + public void unregisterRemoteAnimations() { + try { + getController().unregisterRemoteAnimations(mInterface); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** Called when a TaskFragment is created and organized by this organizer. */ + public void onTaskFragmentAppeared(@NonNull TaskFragmentInfo taskFragmentInfo) {} + + /** Called when the status of an organized TaskFragment is changed. */ + public void onTaskFragmentInfoChanged(@NonNull TaskFragmentInfo taskFragmentInfo) {} + + /** Called when an organized TaskFragment is removed. */ + public void onTaskFragmentVanished(@NonNull TaskFragmentInfo taskFragmentInfo) {} + + /** + * Called when the parent leaf Task of organized TaskFragments is changed. + * When the leaf Task is changed, the organizer may want to update the TaskFragments in one + * transaction. + * + * For case like screen size change, it will trigger onTaskFragmentParentInfoChanged with new + * Task bounds, but may not trigger onTaskFragmentInfoChanged because there can be an override + * bounds. + */ + public void onTaskFragmentParentInfoChanged( + @NonNull IBinder fragmentToken, @NonNull Configuration parentConfig) {} + + /** + * Called when the {@link WindowContainerTransaction} created with + * {@link WindowContainerTransaction#setErrorCallbackToken(IBinder)} failed on the server side. + * + * @param errorCallbackToken token set in + * {@link WindowContainerTransaction#setErrorCallbackToken(IBinder)} + * @param exception exception from the server side. + */ + public void onTaskFragmentError( + @NonNull IBinder errorCallbackToken, @NonNull Throwable exception) {} + + @Override + public void applyTransaction(@NonNull WindowContainerTransaction t) { + t.setTaskFragmentOrganizer(mInterface); + super.applyTransaction(t); + } + + // Suppress the lint because it is not a registration method. + @SuppressWarnings("ExecutorRegistration") + @Override + public int applySyncTransaction(@NonNull WindowContainerTransaction t, + @NonNull WindowContainerTransactionCallback callback) { + t.setTaskFragmentOrganizer(mInterface); + return super.applySyncTransaction(t, callback); + } + + private final ITaskFragmentOrganizer mInterface = new ITaskFragmentOrganizer.Stub() { + @Override + public void onTaskFragmentAppeared(@NonNull TaskFragmentInfo taskFragmentInfo) { + mExecutor.execute( + () -> TaskFragmentOrganizer.this.onTaskFragmentAppeared(taskFragmentInfo)); + } + + @Override + public void onTaskFragmentInfoChanged(@NonNull TaskFragmentInfo taskFragmentInfo) { + mExecutor.execute( + () -> TaskFragmentOrganizer.this.onTaskFragmentInfoChanged(taskFragmentInfo)); + } + + @Override + public void onTaskFragmentVanished(@NonNull TaskFragmentInfo taskFragmentInfo) { + mExecutor.execute( + () -> TaskFragmentOrganizer.this.onTaskFragmentVanished(taskFragmentInfo)); + } + + @Override + public void onTaskFragmentParentInfoChanged( + @NonNull IBinder fragmentToken, @NonNull Configuration parentConfig) { + mExecutor.execute( + () -> TaskFragmentOrganizer.this.onTaskFragmentParentInfoChanged( + fragmentToken, parentConfig)); + } + + @Override + public void onTaskFragmentError( + @NonNull IBinder errorCallbackToken, @NonNull Bundle exceptionBundle) { + mExecutor.execute(() -> TaskFragmentOrganizer.this.onTaskFragmentError( + errorCallbackToken, + (Throwable) exceptionBundle.getSerializable(KEY_ERROR_CALLBACK_EXCEPTION))); + } + }; + + private final TaskFragmentOrganizerToken mToken = new TaskFragmentOrganizerToken(mInterface); + + @NonNull + public TaskFragmentOrganizerToken getOrganizerToken() { + return mToken; + } + + private ITaskFragmentOrganizerController getController() { + try { + return getWindowOrganizerController().getTaskFragmentOrganizerController(); + } catch (RemoteException e) { + return null; + } + } + + /** + * Checks if an activity organized by a {@link android.window.TaskFragmentOrganizer} and + * only occupies a portion of Task bounds. + * @hide + */ + public boolean isActivityEmbedded(@NonNull IBinder activityToken) { + try { + return getController().isActivityEmbedded(activityToken); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } +} diff --git a/core/java/android/window/TaskFragmentOrganizerToken.java b/core/java/android/window/TaskFragmentOrganizerToken.java new file mode 100644 index 000000000000..d5216a6444d9 --- /dev/null +++ b/core/java/android/window/TaskFragmentOrganizerToken.java @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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.window; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.TestApi; +import android.os.IBinder; +import android.os.Parcel; +import android.os.Parcelable; + +/** + * Interface to communicate between window manager and {@link TaskFragmentOrganizer}. + *

    + * Window manager will dispatch TaskFragment information updates via this interface. + * It is necessary because {@link ITaskFragmentOrganizer} aidl interface can not be used as a + * {@link TestApi}. + * @hide + */ +@TestApi +public final class TaskFragmentOrganizerToken implements Parcelable { + private final ITaskFragmentOrganizer mRealToken; + + TaskFragmentOrganizerToken(ITaskFragmentOrganizer realToken) { + mRealToken = realToken; + } + + /** @hide */ + public IBinder asBinder() { + return mRealToken.asBinder(); + } + + /** @hide */ + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeStrongInterface(mRealToken); + } + + /** @hide */ + @Override + public int describeContents() { + return 0; + } + + @NonNull + public static final Creator CREATOR = + new Creator() { + @Override + public TaskFragmentOrganizerToken createFromParcel(Parcel in) { + final ITaskFragmentOrganizer realToken = + ITaskFragmentOrganizer.Stub.asInterface(in.readStrongBinder()); + // The TaskFragmentOrganizerToken may be null for TaskOrganizer or + // DisplayAreaOrganizer. + if (realToken == null) { + return null; + } + return new TaskFragmentOrganizerToken(realToken); + } + + @Override + public TaskFragmentOrganizerToken[] newArray(int size) { + return new TaskFragmentOrganizerToken[size]; + } + }; + + @Override + public int hashCode() { + return mRealToken.asBinder().hashCode(); + } + + @Override + public String toString() { + return "TaskFragmentOrganizerToken{" + mRealToken + "}"; + } + + @Override + public boolean equals(@Nullable Object obj) { + if (!(obj instanceof TaskFragmentOrganizerToken)) { + return false; + } + return mRealToken.asBinder() == ((TaskFragmentOrganizerToken) obj).asBinder(); + } +} diff --git a/core/java/android/window/TaskOrganizer.java b/core/java/android/window/TaskOrganizer.java index d8723a821a22..27c7d3158f95 100644 --- a/core/java/android/window/TaskOrganizer.java +++ b/core/java/android/window/TaskOrganizer.java @@ -24,7 +24,6 @@ import android.annotation.RequiresPermission; import android.annotation.SuppressLint; import android.annotation.TestApi; import android.app.ActivityManager; -import android.graphics.Rect; import android.os.IBinder; import android.os.RemoteException; import android.view.SurfaceControl; @@ -94,6 +93,7 @@ public class TaskOrganizer extends WindowOrganizer { * @param info The information about the Task that's available * @param appToken Token of the application being started. * context to for resources + * @hide */ @BinderThread public void addStartingWindow(@NonNull StartingWindowInfo info, @@ -101,14 +101,11 @@ public class TaskOrganizer extends WindowOrganizer { /** * Called when the Task want to remove the starting window. - * @param leash A persistent leash for the top window in this task. Release it once exit - * animation has finished. - * @param frame Window frame of the top window. - * @param playRevealAnimation Play vanish animation. + * @param removalInfo The information used to remove the starting window. + * @hide */ @BinderThread - public void removeStartingWindow(int taskId, @Nullable SurfaceControl leash, - @Nullable Rect frame, boolean playRevealAnimation) {} + public void removeStartingWindow(@NonNull StartingWindowRemovalInfo removalInfo) {} /** * Called when the Task want to copy the splash screen. @@ -226,6 +223,7 @@ public class TaskOrganizer extends WindowOrganizer { } } + /** * Restarts the top activity in the given task by killing its process if it is visible. * @hide @@ -256,10 +254,8 @@ public class TaskOrganizer extends WindowOrganizer { } @Override - public void removeStartingWindow(int taskId, SurfaceControl leash, Rect frame, - boolean playRevealAnimation) { - mExecutor.execute(() -> TaskOrganizer.this.removeStartingWindow(taskId, leash, frame, - playRevealAnimation)); + public void removeStartingWindow(StartingWindowRemovalInfo removalInfo) { + mExecutor.execute(() -> TaskOrganizer.this.removeStartingWindow(removalInfo)); } @Override @@ -298,6 +294,7 @@ public class TaskOrganizer extends WindowOrganizer { } }; + @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) private ITaskOrganizerController getController() { try { return getWindowOrganizerController().getTaskOrganizerController(); diff --git a/core/java/android/window/TaskSnapshot.java b/core/java/android/window/TaskSnapshot.java index f1e5fb95ea54..b7bb6082296e 100644 --- a/core/java/android/window/TaskSnapshot.java +++ b/core/java/android/window/TaskSnapshot.java @@ -50,6 +50,7 @@ public class TaskSnapshot implements Parcelable { /** The size of the snapshot before scaling */ private final Point mTaskSize; private final Rect mContentInsets; + private final Rect mLetterboxInsets; // Whether this snapshot is a down-sampled version of the high resolution snapshot, used // mainly for loading snapshots quickly from disk when user is flinging fast private final boolean mIsLowResolution; @@ -67,9 +68,10 @@ public class TaskSnapshot implements Parcelable { public TaskSnapshot(long id, @NonNull ComponentName topActivityComponent, HardwareBuffer snapshot, @NonNull ColorSpace colorSpace, int orientation, int rotation, Point taskSize, - Rect contentInsets, boolean isLowResolution, boolean isRealSnapshot, - int windowingMode, @WindowInsetsController.Appearance int appearance, - boolean isTranslucent, boolean hasImeSurface) { + Rect contentInsets, Rect letterboxInsets, boolean isLowResolution, + boolean isRealSnapshot, int windowingMode, + @WindowInsetsController.Appearance int appearance, boolean isTranslucent, + boolean hasImeSurface) { mId = id; mTopActivityComponent = topActivityComponent; mSnapshot = snapshot; @@ -79,6 +81,7 @@ public class TaskSnapshot implements Parcelable { mRotation = rotation; mTaskSize = new Point(taskSize); mContentInsets = new Rect(contentInsets); + mLetterboxInsets = new Rect(letterboxInsets); mIsLowResolution = isLowResolution; mIsRealSnapshot = isRealSnapshot; mWindowingMode = windowingMode; @@ -99,6 +102,7 @@ public class TaskSnapshot implements Parcelable { mRotation = source.readInt(); mTaskSize = source.readTypedObject(Point.CREATOR); mContentInsets = source.readTypedObject(Rect.CREATOR); + mLetterboxInsets = source.readTypedObject(Rect.CREATOR); mIsLowResolution = source.readBoolean(); mIsRealSnapshot = source.readBoolean(); mWindowingMode = source.readInt(); @@ -178,6 +182,14 @@ public class TaskSnapshot implements Parcelable { return mContentInsets; } + /** + * @return The letterbox insets on the snapshot. These can be clipped off in order to + * remove any letterbox areas in the snapshot. + */ + public Rect getLetterboxInsets() { + return mLetterboxInsets; + } + /** * @return Whether this snapshot is a down-sampled version of the full resolution. */ @@ -241,6 +253,7 @@ public class TaskSnapshot implements Parcelable { dest.writeInt(mRotation); dest.writeTypedObject(mTaskSize, 0); dest.writeTypedObject(mContentInsets, 0); + dest.writeTypedObject(mLetterboxInsets, 0); dest.writeBoolean(mIsLowResolution); dest.writeBoolean(mIsRealSnapshot); dest.writeInt(mWindowingMode); @@ -262,6 +275,7 @@ public class TaskSnapshot implements Parcelable { + " mRotation=" + mRotation + " mTaskSize=" + mTaskSize.toString() + " mContentInsets=" + mContentInsets.toShortString() + + " mLetterboxInsets=" + mLetterboxInsets.toShortString() + " mIsLowResolution=" + mIsLowResolution + " mIsRealSnapshot=" + mIsRealSnapshot + " mWindowingMode=" + mWindowingMode @@ -289,6 +303,7 @@ public class TaskSnapshot implements Parcelable { private int mRotation; private Point mTaskSize; private Rect mContentInsets; + private Rect mLetterboxInsets; private boolean mIsRealSnapshot; private int mWindowingMode; private @WindowInsetsController.Appearance @@ -340,6 +355,11 @@ public class TaskSnapshot implements Parcelable { return this; } + public Builder setLetterboxInsets(Rect letterboxInsets) { + mLetterboxInsets = letterboxInsets; + return this; + } + public Builder setIsRealSnapshot(boolean realSnapshot) { mIsRealSnapshot = realSnapshot; return this; @@ -387,6 +407,7 @@ public class TaskSnapshot implements Parcelable { mRotation, mTaskSize, mContentInsets, + mLetterboxInsets, // When building a TaskSnapshot with the Builder class, isLowResolution // is always false. Low-res snapshots are only created when loading from // disk. diff --git a/core/java/android/window/TransitionFilter.java b/core/java/android/window/TransitionFilter.java index 141f47b130d1..db15145b0a1e 100644 --- a/core/java/android/window/TransitionFilter.java +++ b/core/java/android/window/TransitionFilter.java @@ -17,12 +17,17 @@ package android.window; import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; +import static android.view.WindowManager.TransitionType; +import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; +import android.app.ActivityManager; import android.app.WindowConfiguration; +import android.content.ComponentName; import android.os.Parcel; import android.os.Parcelable; +import android.view.WindowManager; /** * A parcelable filter that can be used for rerouting transitions to a remote. This is a local @@ -33,11 +38,29 @@ import android.os.Parcelable; */ public final class TransitionFilter implements Parcelable { + /** The associated requirement doesn't care about the z-order. */ + public static final int CONTAINER_ORDER_ANY = 0; + /** The associated requirement only matches the top-most (z-order) container. */ + public static final int CONTAINER_ORDER_TOP = 1; + + /** @hide */ + @IntDef(prefix = { "CONTAINER_ORDER_" }, value = { + CONTAINER_ORDER_ANY, + CONTAINER_ORDER_TOP, + }) + public @interface ContainerOrder {} + /** * When non-null: this is a list of transition types that this filter applies to. This filter * will fail for transitions that aren't one of these types. */ - @Nullable public int[] mTypeSet = null; + @Nullable public @TransitionType int[] mTypeSet = null; + + /** All flags must be set on a transition. */ + public @WindowManager.TransitionFlags int mFlags = 0; + + /** All flags must NOT be set on a transition. */ + public @WindowManager.TransitionFlags int mNotFlags = 0; /** * A list of required changes. To pass, a transition must meet all requirements. @@ -49,6 +72,8 @@ public final class TransitionFilter implements Parcelable { private TransitionFilter(Parcel in) { mTypeSet = in.createIntArray(); + mFlags = in.readInt(); + mNotFlags = in.readInt(); mRequirements = in.createTypedArray(Requirement.CREATOR); } @@ -65,10 +90,19 @@ public final class TransitionFilter implements Parcelable { } if (!typePass) return false; } + if ((info.getFlags() & mFlags) != mFlags) { + return false; + } + if ((info.getFlags() & mNotFlags) != 0) { + return false; + } // Make sure info meets all of the requirements. if (mRequirements != null) { for (int i = 0; i < mRequirements.length; ++i) { - if (!mRequirements[i].matches(info)) return false; + final boolean matches = mRequirements[i].matches(info); + if (matches == mRequirements[i].mNot) { + return false; + } } } return true; @@ -78,6 +112,8 @@ public final class TransitionFilter implements Parcelable { /** @hide */ public void writeToParcel(@NonNull Parcel dest, int flags) { dest.writeIntArray(mTypeSet); + dest.writeInt(mFlags); + dest.writeInt(mNotFlags); dest.writeTypedArray(mRequirements, flags); } @@ -107,10 +143,12 @@ public final class TransitionFilter implements Parcelable { sb.append("{types=["); if (mTypeSet != null) { for (int i = 0; i < mTypeSet.length; ++i) { - sb.append((i == 0 ? "" : ",") + mTypeSet[i]); + sb.append((i == 0 ? "" : ",") + WindowManager.transitTypeToString(mTypeSet[i])); } } - sb.append("] checks=["); + sb.append("] flags=0x" + Integer.toHexString(mFlags)); + sb.append("] notFlags=0x" + Integer.toHexString(mNotFlags)); + sb.append(" checks=["); if (mRequirements != null) { for (int i = 0; i < mRequirements.length; ++i) { sb.append((i == 0 ? "" : ",") + mRequirements[i]); @@ -125,30 +163,56 @@ public final class TransitionFilter implements Parcelable { */ public static final class Requirement implements Parcelable { public int mActivityType = ACTIVITY_TYPE_UNDEFINED; + + /** This only matches if the change is independent of its parents. */ + public boolean mMustBeIndependent = true; + + /** If this matches, the parent filter will fail */ + public boolean mNot = false; + public int[] mModes = null; + /** Matches only if all the flags here are set on the change. */ + public @TransitionInfo.ChangeFlags int mFlags = 0; + + /** If this needs to be a task. */ + public boolean mMustBeTask = false; + + public @ContainerOrder int mOrder = CONTAINER_ORDER_ANY; + public ComponentName mTopActivity; + public Requirement() { } private Requirement(Parcel in) { mActivityType = in.readInt(); + mMustBeIndependent = in.readBoolean(); + mNot = in.readBoolean(); mModes = in.createIntArray(); + mFlags = in.readInt(); + mMustBeTask = in.readBoolean(); + mOrder = in.readInt(); + mTopActivity = in.readTypedObject(ComponentName.CREATOR); } /** Go through changes and find if at-least one change matches this filter */ boolean matches(@NonNull TransitionInfo info) { for (int i = info.getChanges().size() - 1; i >= 0; --i) { final TransitionInfo.Change change = info.getChanges().get(i); - if (!TransitionInfo.isIndependent(change, info)) { + if (mMustBeIndependent && !TransitionInfo.isIndependent(change, info)) { // Only look at independent animating windows. continue; } + if (mOrder == CONTAINER_ORDER_TOP && i > 0) { + continue; + } if (mActivityType != ACTIVITY_TYPE_UNDEFINED) { if (change.getTaskInfo() == null || change.getTaskInfo().getActivityType() != mActivityType) { continue; } } + if (!matchesTopActivity(change.getTaskInfo())) continue; if (mModes != null) { boolean pass = false; for (int m = 0; m < mModes.length; ++m) { @@ -159,24 +223,44 @@ public final class TransitionFilter implements Parcelable { } if (!pass) continue; } + if ((change.getFlags() & mFlags) != mFlags) { + continue; + } + if (mMustBeTask && change.getTaskInfo() == null) { + continue; + } return true; } return false; } + private boolean matchesTopActivity(ActivityManager.RunningTaskInfo info) { + if (mTopActivity == null) return true; + if (info == null) return false; + final ComponentName component = info.topActivity; + return mTopActivity.equals(component); + } + /** Check if the request matches this filter. It may generate false positives */ boolean matches(@NonNull TransitionRequestInfo request) { - // Can't check modes since the transition hasn't been built at this point. + // Can't check modes/order since the transition hasn't been built at this point. if (mActivityType == ACTIVITY_TYPE_UNDEFINED) return true; return request.getTriggerTask() != null - && request.getTriggerTask().getActivityType() == mActivityType; + && request.getTriggerTask().getActivityType() == mActivityType + && matchesTopActivity(request.getTriggerTask()); } @Override /** @hide */ public void writeToParcel(@NonNull Parcel dest, int flags) { dest.writeInt(mActivityType); + dest.writeBoolean(mMustBeIndependent); + dest.writeBoolean(mNot); dest.writeIntArray(mModes); + dest.writeInt(mFlags); + dest.writeBoolean(mMustBeTask); + dest.writeInt(mOrder); + dest.writeTypedObject(mTopActivity, flags); } @NonNull @@ -202,14 +286,31 @@ public final class TransitionFilter implements Parcelable { @Override public String toString() { StringBuilder out = new StringBuilder(); - out.append("{atype=" + WindowConfiguration.activityTypeToString(mActivityType)); + out.append('{'); + if (mNot) out.append("NOT "); + out.append("atype=" + WindowConfiguration.activityTypeToString(mActivityType)); + out.append(" independent=" + mMustBeIndependent); out.append(" modes=["); if (mModes != null) { for (int i = 0; i < mModes.length; ++i) { out.append((i == 0 ? "" : ",") + TransitionInfo.modeToString(mModes[i])); } } - return out.append("]}").toString(); + out.append("]").toString(); + out.append(" flags=" + TransitionInfo.flagsToString(mFlags)); + out.append(" mustBeTask=" + mMustBeTask); + out.append(" order=" + containerOrderToString(mOrder)); + out.append(" topActivity=").append(mTopActivity); + out.append("}"); + return out.toString(); + } + } + + private static String containerOrderToString(int order) { + switch (order) { + case CONTAINER_ORDER_ANY: return "ANY"; + case CONTAINER_ORDER_TOP: return "TOP"; } + return "UNKNOWN(" + order + ")"; } } diff --git a/core/java/android/window/TransitionInfo.java b/core/java/android/window/TransitionInfo.java index 23b8ee4a019f..7208930c0b20 100644 --- a/core/java/android/window/TransitionInfo.java +++ b/core/java/android/window/TransitionInfo.java @@ -16,13 +16,23 @@ package android.window; +import static android.app.ActivityOptions.ANIM_CLIP_REVEAL; +import static android.app.ActivityOptions.ANIM_CUSTOM; +import static android.app.ActivityOptions.ANIM_OPEN_CROSS_PROFILE_APPS; +import static android.app.ActivityOptions.ANIM_SCALE_UP; +import static android.app.ActivityOptions.ANIM_THUMBNAIL_SCALE_DOWN; +import static android.app.ActivityOptions.ANIM_THUMBNAIL_SCALE_UP; import static android.app.WindowConfiguration.ROTATION_UNDEFINED; +import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_UNSPECIFIED; import static android.view.WindowManager.TRANSIT_CHANGE; import static android.view.WindowManager.TRANSIT_CLOSE; +import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY; import static android.view.WindowManager.TRANSIT_NONE; import static android.view.WindowManager.TRANSIT_OPEN; import static android.view.WindowManager.TRANSIT_TO_BACK; import static android.view.WindowManager.TRANSIT_TO_FRONT; +import static android.view.WindowManager.TransitionFlags; +import static android.view.WindowManager.TransitionType; import static android.view.WindowManager.transitTypeToString; import android.annotation.IntDef; @@ -31,11 +41,11 @@ import android.annotation.Nullable; import android.app.ActivityManager; import android.graphics.Point; import android.graphics.Rect; +import android.hardware.HardwareBuffer; import android.os.Parcel; import android.os.Parcelable; import android.view.Surface; import android.view.SurfaceControl; -import android.view.WindowManager; import java.util.ArrayList; import java.util.List; @@ -80,8 +90,22 @@ public final class TransitionInfo implements Parcelable { /** The container has voice session. */ public static final int FLAG_IS_VOICE_INTERACTION = 1 << 4; + /** The container is the display. */ + public static final int FLAG_IS_DISPLAY = 1 << 5; + + /** The container can show on top of lock screen. */ + public static final int FLAG_OCCLUDES_KEYGUARD = 1 << 6; + + /** + * Only for IS_DISPLAY containers. Is set if the display has system alert windows. This is + * used to prevent seamless rotation. + * TODO(b/194540864): Once we can include all windows in transition, then replace this with + * something like FLAG_IS_SYSTEM_ALERT instead. Then we can do mixed rotations. + */ + public static final int FLAG_DISPLAY_HAS_ALERT_WINDOWS = 1 << 7; + /** The first unused bit. This can be used by remotes to attach custom flags to this change. */ - public static final int FLAG_FIRST_CUSTOM = 1 << 5; + public static final int FLAG_FIRST_CUSTOM = 1 << 8; /** @hide */ @IntDef(prefix = { "FLAG_" }, value = { @@ -91,20 +115,24 @@ public final class TransitionInfo implements Parcelable { FLAG_TRANSLUCENT, FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT, FLAG_IS_VOICE_INTERACTION, + FLAG_IS_DISPLAY, + FLAG_OCCLUDES_KEYGUARD, + FLAG_DISPLAY_HAS_ALERT_WINDOWS, FLAG_FIRST_CUSTOM }) public @interface ChangeFlags {} - private final @WindowManager.TransitionOldType int mType; - private final @WindowManager.TransitionFlags int mFlags; + private final @TransitionType int mType; + private final @TransitionFlags int mFlags; private final ArrayList mChanges = new ArrayList<>(); private SurfaceControl mRootLeash; private final Point mRootOffset = new Point(); + private AnimationOptions mOptions; + /** @hide */ - public TransitionInfo(@WindowManager.TransitionOldType int type, - @WindowManager.TransitionFlags int flags) { + public TransitionInfo(@TransitionType int type, @TransitionFlags int flags) { mType = type; mFlags = flags; } @@ -112,10 +140,11 @@ public final class TransitionInfo implements Parcelable { private TransitionInfo(Parcel in) { mType = in.readInt(); mFlags = in.readInt(); - in.readList(mChanges, null /* classLoader */); + in.readTypedList(mChanges, Change.CREATOR); mRootLeash = new SurfaceControl(); mRootLeash.readFromParcel(in); mRootOffset.readFromParcel(in); + mOptions = in.readTypedObject(AnimationOptions.CREATOR); } @Override @@ -123,9 +152,10 @@ public final class TransitionInfo implements Parcelable { public void writeToParcel(@NonNull Parcel dest, int flags) { dest.writeInt(mType); dest.writeInt(mFlags); - dest.writeList(mChanges); + dest.writeTypedList(mChanges); mRootLeash.writeToParcel(dest, flags); mRootOffset.writeToParcel(dest, flags); + dest.writeTypedObject(mOptions, flags); } @NonNull @@ -154,7 +184,11 @@ public final class TransitionInfo implements Parcelable { mRootOffset.set(offsetLeft, offsetTop); } - public int getType() { + public void setAnimationOptions(AnimationOptions options) { + mOptions = options; + } + + public @TransitionType int getType() { return mType; } @@ -182,6 +216,14 @@ public final class TransitionInfo implements Parcelable { return mRootOffset; } + public AnimationOptions getAnimationOptions() { + return mOptions; + } + + /** + * @return the list of {@link Change}s in this transition. The list is sorted top-to-bottom + * in Z (meaning index 0 is the top-most container). + */ @NonNull public List getChanges() { return mChanges; @@ -208,10 +250,17 @@ public final class TransitionInfo implements Parcelable { mChanges.add(change); } + /** + * Whether this transition includes keyguard going away. + */ + public boolean isKeyguardGoingAway() { + return (mFlags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY) != 0; + } + @Override public String toString() { StringBuilder sb = new StringBuilder(); - sb.append("{t=" + transitTypeToString(mType) + " f=" + Integer.toHexString(mFlags) + sb.append("{t=" + transitTypeToString(mType) + " f=0x" + Integer.toHexString(mFlags) + " ro=" + mRootOffset + " c=["); for (int i = 0; i < mChanges.size(); ++i) { if (i > 0) { @@ -257,6 +306,15 @@ public final class TransitionInfo implements Parcelable { if ((flags & FLAG_IS_VOICE_INTERACTION) != 0) { sb.append((sb.length() == 0 ? "" : "|") + "IS_VOICE_INTERACTION"); } + if ((flags & FLAG_IS_DISPLAY) != 0) { + sb.append((sb.length() == 0 ? "" : "|") + "IS_DISPLAY"); + } + if ((flags & FLAG_OCCLUDES_KEYGUARD) != 0) { + sb.append((sb.length() == 0 ? "" : "|") + "OCCLUDES_KEYGUARD"); + } + if ((flags & FLAG_DISPLAY_HAS_ALERT_WINDOWS) != 0) { + sb.append((sb.length() == 0 ? "" : "|") + "DISPLAY_HAS_ALERT_WINDOWS"); + } if ((flags & FLAG_FIRST_CUSTOM) != 0) { sb.append((sb.length() == 0 ? "" : "|") + "FIRST_CUSTOM"); } @@ -302,8 +360,10 @@ public final class TransitionInfo implements Parcelable { private final Rect mEndAbsBounds = new Rect(); private final Point mEndRelOffset = new Point(); private ActivityManager.RunningTaskInfo mTaskInfo = null; + private boolean mAllowEnterPip; private int mStartRotation = ROTATION_UNDEFINED; private int mEndRotation = ROTATION_UNDEFINED; + private int mRotationAnimation = ROTATION_ANIMATION_UNSPECIFIED; public Change(@Nullable WindowContainerToken container, @NonNull SurfaceControl leash) { mContainer = container; @@ -321,8 +381,10 @@ public final class TransitionInfo implements Parcelable { mEndAbsBounds.readFromParcel(in); mEndRelOffset.readFromParcel(in); mTaskInfo = in.readTypedObject(ActivityManager.RunningTaskInfo.CREATOR); + mAllowEnterPip = in.readBoolean(); mStartRotation = in.readInt(); mEndRotation = in.readInt(); + mRotationAnimation = in.readInt(); } /** Sets the parent of this change's container. The parent must be a participant or null. */ @@ -363,12 +425,25 @@ public final class TransitionInfo implements Parcelable { mTaskInfo = taskInfo; } + /** Sets the allowEnterPip flag which represents AppOpsManager check on PiP permission */ + public void setAllowEnterPip(boolean allowEnterPip) { + mAllowEnterPip = allowEnterPip; + } + /** Sets the start and end rotation of this container. */ public void setRotation(@Surface.Rotation int start, @Surface.Rotation int end) { mStartRotation = start; mEndRotation = end; } + /** + * Sets the app-requested animation type for rotation. Will be one of the + * ROTATION_ANIMATION_ values in {@link android.view.WindowManager.LayoutParams}; + */ + public void setRotationAnimation(int anim) { + mRotationAnimation = anim; + } + /** @return the container that is changing. May be null if non-remotable (eg. activity) */ @Nullable public WindowContainerToken getContainer() { @@ -432,6 +507,10 @@ public final class TransitionInfo implements Parcelable { return mTaskInfo; } + public boolean getAllowEnterPip() { + return mAllowEnterPip; + } + public int getStartRotation() { return mStartRotation; } @@ -440,6 +519,11 @@ public final class TransitionInfo implements Parcelable { return mEndRotation; } + /** @return the rotation animation. */ + public int getRotationAnimation() { + return mRotationAnimation; + } + /** @hide */ @Override public void writeToParcel(@NonNull Parcel dest, int flags) { @@ -452,8 +536,10 @@ public final class TransitionInfo implements Parcelable { mEndAbsBounds.writeToParcel(dest, flags); mEndRelOffset.writeToParcel(dest, flags); dest.writeTypedObject(mTaskInfo, flags); + dest.writeBoolean(mAllowEnterPip); dest.writeInt(mStartRotation); dest.writeInt(mEndRotation); + dest.writeInt(mRotationAnimation); } @NonNull @@ -481,7 +567,149 @@ public final class TransitionInfo implements Parcelable { return "{" + mContainer + "(" + mParent + ") leash=" + mLeash + " m=" + modeToString(mMode) + " f=" + flagsToString(mFlags) + " sb=" + mStartAbsBounds + " eb=" + mEndAbsBounds + " eo=" + mEndRelOffset + " r=" - + mStartRotation + "->" + mEndRotation + "}"; + + mStartRotation + "->" + mEndRotation + ":" + mRotationAnimation + "}"; + } + } + + /** Represents animation options during a transition */ + public static final class AnimationOptions implements Parcelable { + + private int mType; + private int mEnterResId; + private int mExitResId; + private boolean mOverrideTaskTransition; + private String mPackageName; + private final Rect mTransitionBounds = new Rect(); + private HardwareBuffer mThumbnail; + + private AnimationOptions(int type) { + mType = type; + } + + public AnimationOptions(Parcel in) { + mType = in.readInt(); + mEnterResId = in.readInt(); + mExitResId = in.readInt(); + mOverrideTaskTransition = in.readBoolean(); + mPackageName = in.readString(); + mTransitionBounds.readFromParcel(in); + mThumbnail = in.readTypedObject(HardwareBuffer.CREATOR); + } + + public static AnimationOptions makeCustomAnimOptions(String packageName, int enterResId, + int exitResId, boolean overrideTaskTransition) { + AnimationOptions options = new AnimationOptions(ANIM_CUSTOM); + options.mPackageName = packageName; + options.mEnterResId = enterResId; + options.mExitResId = exitResId; + options.mOverrideTaskTransition = overrideTaskTransition; + return options; + } + + public static AnimationOptions makeClipRevealAnimOptions(int startX, int startY, int width, + int height) { + AnimationOptions options = new AnimationOptions(ANIM_CLIP_REVEAL); + options.mTransitionBounds.set(startX, startY, startX + width, startY + height); + return options; + } + + public static AnimationOptions makeScaleUpAnimOptions(int startX, int startY, int width, + int height) { + AnimationOptions options = new AnimationOptions(ANIM_SCALE_UP); + options.mTransitionBounds.set(startX, startY, startX + width, startY + height); + return options; + } + + public static AnimationOptions makeThumnbnailAnimOptions(HardwareBuffer srcThumb, + int startX, int startY, boolean scaleUp) { + AnimationOptions options = new AnimationOptions( + scaleUp ? ANIM_THUMBNAIL_SCALE_UP : ANIM_THUMBNAIL_SCALE_DOWN); + options.mTransitionBounds.set(startX, startY, startX, startY); + options.mThumbnail = srcThumb; + return options; + } + + public static AnimationOptions makeCrossProfileAnimOptions() { + AnimationOptions options = new AnimationOptions(ANIM_OPEN_CROSS_PROFILE_APPS); + return options; + } + + public int getType() { + return mType; + } + + public int getEnterResId() { + return mEnterResId; + } + + public int getExitResId() { + return mExitResId; + } + + public boolean getOverrideTaskTransition() { + return mOverrideTaskTransition; + } + + public String getPackageName() { + return mPackageName; + } + + public Rect getTransitionBounds() { + return mTransitionBounds; + } + + public HardwareBuffer getThumbnail() { + return mThumbnail; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(mType); + dest.writeInt(mEnterResId); + dest.writeInt(mExitResId); + dest.writeBoolean(mOverrideTaskTransition); + dest.writeString(mPackageName); + mTransitionBounds.writeToParcel(dest, flags); + dest.writeTypedObject(mThumbnail, flags); + } + + @NonNull + public static final Creator CREATOR = + new Creator() { + @Override + public AnimationOptions createFromParcel(Parcel in) { + return new AnimationOptions(in); + } + + @Override + public AnimationOptions[] newArray(int size) { + return new AnimationOptions[size]; + } + }; + + /** @hide */ + @Override + public int describeContents() { + return 0; + } + + @NonNull + private static String typeToString(int mode) { + switch(mode) { + case ANIM_CUSTOM: return "ANIM_CUSTOM"; + case ANIM_CLIP_REVEAL: return "ANIM_CLIP_REVEAL"; + case ANIM_SCALE_UP: return "ANIM_SCALE_UP"; + case ANIM_THUMBNAIL_SCALE_UP: return "ANIM_THUMBNAIL_SCALE_UP"; + case ANIM_THUMBNAIL_SCALE_DOWN: return "ANIM_THUMBNAIL_SCALE_DOWN"; + case ANIM_OPEN_CROSS_PROFILE_APPS: return "ANIM_OPEN_CROSS_PROFILE_APPS"; + default: return ""; + } + } + + @Override + public String toString() { + return "{ AnimationOtions type= " + typeToString(mType) + " package=" + mPackageName + + " override=" + mOverrideTaskTransition + " b=" + mTransitionBounds + "}"; } } } diff --git a/core/java/android/window/TransitionMetrics.java b/core/java/android/window/TransitionMetrics.java new file mode 100644 index 000000000000..9a93c1a1ffd6 --- /dev/null +++ b/core/java/android/window/TransitionMetrics.java @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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.window; + +import android.os.IBinder; +import android.os.RemoteException; +import android.os.SystemClock; +import android.util.Singleton; + +/** + * A helper class for who plays transition animation can report its metrics easily. + * @hide + */ +public class TransitionMetrics { + + private final ITransitionMetricsReporter mTransitionMetricsReporter; + + private TransitionMetrics(ITransitionMetricsReporter reporter) { + mTransitionMetricsReporter = reporter; + } + + /** Reports the current timestamp as when the transition animation starts. */ + public void reportAnimationStart(IBinder transitionToken) { + try { + mTransitionMetricsReporter.reportAnimationStart(transitionToken, + SystemClock.elapsedRealtime()); + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } + } + + /** Gets the singleton instance of TransitionMetrics. */ + public static TransitionMetrics getInstance() { + return sTransitionMetrics.get(); + } + + private static final Singleton sTransitionMetrics = new Singleton<>() { + @Override + protected TransitionMetrics create() { + return new TransitionMetrics(WindowOrganizer.getTransitionMetricsReporter()); + } + }; +} diff --git a/core/java/android/window/TransitionRequestInfo.java b/core/java/android/window/TransitionRequestInfo.java index cc493ab63e22..f7707317efd7 100644 --- a/core/java/android/window/TransitionRequestInfo.java +++ b/core/java/android/window/TransitionRequestInfo.java @@ -40,11 +40,11 @@ public final class TransitionRequestInfo implements Parcelable { private @Nullable ActivityManager.RunningTaskInfo mTriggerTask; /** If non-null, a remote-transition associated with the source of this transition. */ - private @Nullable IRemoteTransition mRemoteTransition; + private @Nullable RemoteTransition mRemoteTransition; - // Code below generated by codegen v1.0.22. + // Code below generated by codegen v1.0.23. // // DO NOT MODIFY! // CHECKSTYLE:OFF Generated code @@ -72,7 +72,7 @@ public final class TransitionRequestInfo implements Parcelable { public TransitionRequestInfo( @WindowManager.TransitionType int type, @Nullable ActivityManager.RunningTaskInfo triggerTask, - @Nullable IRemoteTransition remoteTransition) { + @Nullable RemoteTransition remoteTransition) { this.mType = type; com.android.internal.util.AnnotationValidations.validate( WindowManager.TransitionType.class, null, mType); @@ -103,7 +103,7 @@ public final class TransitionRequestInfo implements Parcelable { * If non-null, a remote-transition associated with the source of this transition. */ @DataClass.Generated.Member - public @Nullable IRemoteTransition getRemoteTransition() { + public @Nullable RemoteTransition getRemoteTransition() { return mRemoteTransition; } @@ -121,7 +121,7 @@ public final class TransitionRequestInfo implements Parcelable { * If non-null, a remote-transition associated with the source of this transition. */ @DataClass.Generated.Member - public @android.annotation.NonNull TransitionRequestInfo setRemoteTransition(@android.annotation.NonNull IRemoteTransition value) { + public @android.annotation.NonNull TransitionRequestInfo setRemoteTransition(@android.annotation.NonNull RemoteTransition value) { mRemoteTransition = value; return this; } @@ -151,7 +151,7 @@ public final class TransitionRequestInfo implements Parcelable { dest.writeByte(flg); dest.writeInt(mType); if (mTriggerTask != null) dest.writeTypedObject(mTriggerTask, flags); - if (mRemoteTransition != null) dest.writeStrongInterface(mRemoteTransition); + if (mRemoteTransition != null) dest.writeTypedObject(mRemoteTransition, flags); } @Override @@ -168,7 +168,7 @@ public final class TransitionRequestInfo implements Parcelable { byte flg = in.readByte(); int type = in.readInt(); ActivityManager.RunningTaskInfo triggerTask = (flg & 0x2) == 0 ? null : (ActivityManager.RunningTaskInfo) in.readTypedObject(ActivityManager.RunningTaskInfo.CREATOR); - IRemoteTransition remoteTransition = (flg & 0x4) == 0 ? null : IRemoteTransition.Stub.asInterface(in.readStrongBinder()); + RemoteTransition remoteTransition = (flg & 0x4) == 0 ? null : (RemoteTransition) in.readTypedObject(RemoteTransition.CREATOR); this.mType = type; com.android.internal.util.AnnotationValidations.validate( @@ -194,10 +194,10 @@ public final class TransitionRequestInfo implements Parcelable { }; @DataClass.Generated( - time = 1610060387917L, - codegenVersion = "1.0.22", + time = 1629321632222L, + codegenVersion = "1.0.23", sourceFile = "frameworks/base/core/java/android/window/TransitionRequestInfo.java", - inputSignatures = "private final @android.view.WindowManager.TransitionType int mType\nprivate @android.annotation.Nullable android.app.ActivityManager.RunningTaskInfo mTriggerTask\nprivate @android.annotation.Nullable android.window.IRemoteTransition mRemoteTransition\nclass TransitionRequestInfo extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genSetters=true, genAidl=true)") + inputSignatures = "private final @android.view.WindowManager.TransitionType int mType\nprivate @android.annotation.Nullable android.app.ActivityManager.RunningTaskInfo mTriggerTask\nprivate @android.annotation.Nullable android.window.RemoteTransition mRemoteTransition\nclass TransitionRequestInfo extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genSetters=true, genAidl=true)") @Deprecated private void __metadata() {} diff --git a/core/java/android/window/WindowContainerTransaction.java b/core/java/android/window/WindowContainerTransaction.java index c0af57214e5e..6864ccaa7c8a 100644 --- a/core/java/android/window/WindowContainerTransaction.java +++ b/core/java/android/window/WindowContainerTransaction.java @@ -19,7 +19,9 @@ package android.window; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.TestApi; +import android.app.PendingIntent; import android.app.WindowConfiguration; +import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.res.Configuration; import android.graphics.Rect; @@ -34,6 +36,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Map; +import java.util.Objects; /** * Represents a collection of operations on some WindowContainers that should be applied all at @@ -48,11 +51,19 @@ public final class WindowContainerTransaction implements Parcelable { // Flat list because re-order operations are order-dependent private final ArrayList mHierarchyOps = new ArrayList<>(); + @Nullable + private IBinder mErrorCallbackToken; + + @Nullable + private ITaskFragmentOrganizer mTaskFragmentOrganizer; + public WindowContainerTransaction() {} private WindowContainerTransaction(Parcel in) { in.readMap(mChanges, null /* loader */); in.readList(mHierarchyOps, null /* loader */); + mErrorCallbackToken = in.readStrongBinder(); + mTaskFragmentOrganizer = ITaskFragmentOrganizer.Stub.asInterface(in.readStrongBinder()); } private Change getOrCreateChange(IBinder token) { @@ -284,7 +295,7 @@ public final class WindowContainerTransaction implements Parcelable { } /** - * Reparent's all children tasks of {@param currentParent} in the specified + * Reparent's all children tasks or the top task of {@param currentParent} in the specified * {@param windowingMode} and {@param activityType} to {@param newParent} in their current * z-order. * @@ -295,20 +306,45 @@ public final class WindowContainerTransaction implements Parcelable { * @param activityTypes of the tasks to reparent. * @param onTop When {@code true}, the child goes to the top of parent; otherwise it goes to * the bottom. + * @param reparentTopOnly When {@code true}, only reparent the top task which fit windowingModes + * and activityTypes. + * @hide */ @NonNull public WindowContainerTransaction reparentTasks(@Nullable WindowContainerToken currentParent, @Nullable WindowContainerToken newParent, @Nullable int[] windowingModes, - @Nullable int[] activityTypes, boolean onTop) { + @Nullable int[] activityTypes, boolean onTop, boolean reparentTopOnly) { mHierarchyOps.add(HierarchyOp.createForChildrenTasksReparent( currentParent != null ? currentParent.asBinder() : null, newParent != null ? newParent.asBinder() : null, windowingModes, activityTypes, - onTop)); + onTop, + reparentTopOnly)); return this; } + /** + * Reparent's all children tasks of {@param currentParent} in the specified + * {@param windowingMode} and {@param activityType} to {@param newParent} in their current + * z-order. + * + * @param currentParent of the tasks to perform the operation no. + * {@code null} will perform the operation on the display. + * @param newParent for the tasks. {@code null} will perform the operation on the display. + * @param windowingModes of the tasks to reparent. + * @param activityTypes of the tasks to reparent. + * @param onTop When {@code true}, the child goes to the top of parent; otherwise it goes to + * the bottom. + */ + @NonNull + public WindowContainerTransaction reparentTasks(@Nullable WindowContainerToken currentParent, + @Nullable WindowContainerToken newParent, @Nullable int[] windowingModes, + @Nullable int[] activityTypes, boolean onTop) { + return reparentTasks(currentParent, newParent, windowingModes, activityTypes, onTop, + false /* reparentTopOnly */); + } + /** * Sets whether a container should be the launch root for the specified windowing mode and * activity type. This currently only applies to Task containers created by organizer. @@ -325,16 +361,19 @@ public final class WindowContainerTransaction implements Parcelable { /** * Sets to containers adjacent to each other. Containers below two visible adjacent roots will - * be made invisible. This currently only applies to Task containers created by organizer. + * be made invisible. This currently only applies to TaskFragment containers created by + * organizer. * @param root1 the first root. * @param root2 the second root. */ @NonNull public WindowContainerTransaction setAdjacentRoots( - @NonNull WindowContainerToken root1, @NonNull WindowContainerToken root2) { + @NonNull WindowContainerToken root1, @NonNull WindowContainerToken root2, + boolean moveTogether) { mHierarchyOps.add(HierarchyOp.createForAdjacentRoots( root1.asBinder(), - root2.asBinder())); + root2.asBinder(), + moveTogether)); return this; } @@ -377,6 +416,177 @@ public final class WindowContainerTransaction implements Parcelable { return this; } + /** + * Sends a pending intent in sync. + * @param sender The PendingIntent sender. + * @param intent The fillIn intent to patch over the sender's base intent. + * @param options bundle containing ActivityOptions for the task's top activity. + * @hide + */ + @NonNull + public WindowContainerTransaction sendPendingIntent(PendingIntent sender, Intent intent, + @Nullable Bundle options) { + mHierarchyOps.add(new HierarchyOp.Builder(HierarchyOp.HIERARCHY_OP_TYPE_PENDING_INTENT) + .setLaunchOptions(options) + .setPendingIntent(sender) + .setActivityIntent(intent) + .build()); + return this; + } + + /** + * Creates a new TaskFragment with the given options. + * @param taskFragmentOptions the options used to create the TaskFragment. + */ + @NonNull + public WindowContainerTransaction createTaskFragment( + @NonNull TaskFragmentCreationParams taskFragmentOptions) { + final HierarchyOp hierarchyOp = + new HierarchyOp.Builder(HierarchyOp.HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT) + .setTaskFragmentCreationOptions(taskFragmentOptions) + .build(); + mHierarchyOps.add(hierarchyOp); + return this; + } + + /** + * Deletes an existing TaskFragment. Any remaining activities below it will be destroyed. + * @param taskFragment the TaskFragment to be removed. + */ + @NonNull + public WindowContainerTransaction deleteTaskFragment( + @NonNull WindowContainerToken taskFragment) { + final HierarchyOp hierarchyOp = + new HierarchyOp.Builder(HierarchyOp.HIERARCHY_OP_TYPE_DELETE_TASK_FRAGMENT) + .setContainer(taskFragment.asBinder()) + .build(); + mHierarchyOps.add(hierarchyOp); + return this; + } + + /** + * Starts an activity in the TaskFragment. + * @param fragmentToken client assigned unique token to create TaskFragment with specified in + * {@link TaskFragmentCreationParams#getFragmentToken()}. + * @param callerToken the activity token that initialized the activity launch. + * @param activityIntent intent to start the activity. + * @param activityOptions ActivityOptions to start the activity with. + * @see android.content.Context#startActivity(Intent, Bundle). + */ + @NonNull + public WindowContainerTransaction startActivityInTaskFragment( + @NonNull IBinder fragmentToken, @NonNull IBinder callerToken, + @NonNull Intent activityIntent, @Nullable Bundle activityOptions) { + final HierarchyOp hierarchyOp = + new HierarchyOp.Builder( + HierarchyOp.HIERARCHY_OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT) + .setContainer(fragmentToken) + .setReparentContainer(callerToken) + .setActivityIntent(activityIntent) + .setLaunchOptions(activityOptions) + .build(); + mHierarchyOps.add(hierarchyOp); + return this; + } + + /** + * Moves an activity into the TaskFragment. + * @param fragmentToken client assigned unique token to create TaskFragment with specified in + * {@link TaskFragmentCreationParams#getFragmentToken()}. + * @param activityToken activity to be reparented. + */ + @NonNull + public WindowContainerTransaction reparentActivityToTaskFragment( + @NonNull IBinder fragmentToken, @NonNull IBinder activityToken) { + final HierarchyOp hierarchyOp = + new HierarchyOp.Builder( + HierarchyOp.HIERARCHY_OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT) + .setReparentContainer(fragmentToken) + .setContainer(activityToken) + .build(); + mHierarchyOps.add(hierarchyOp); + return this; + } + + /** + * Reparents all children of one TaskFragment to another. + * @param oldParent children of this TaskFragment will be reparented. + * @param newParent the new parent TaskFragment to move the children to. If {@code null}, the + * children will be moved to the leaf Task. + */ + @NonNull + public WindowContainerTransaction reparentChildren( + @NonNull WindowContainerToken oldParent, + @Nullable WindowContainerToken newParent) { + final HierarchyOp hierarchyOp = + new HierarchyOp.Builder(HierarchyOp.HIERARCHY_OP_TYPE_REPARENT_CHILDREN) + .setContainer(oldParent.asBinder()) + .setReparentContainer(newParent != null ? newParent.asBinder() : null) + .build(); + mHierarchyOps.add(hierarchyOp); + return this; + } + + /** + * Sets to TaskFragments adjacent to each other. Containers below two visible adjacent + * TaskFragments will be made invisible. This is similar to + * {@link #setAdjacentRoots(WindowContainerToken, WindowContainerToken)}, but can be used with + * fragmentTokens when that TaskFragments haven't been created (but will be created in the same + * {@link WindowContainerTransaction}). + * To reset it, pass {@code null} for {@code fragmentToken2}. + * @param fragmentToken1 client assigned unique token to create TaskFragment with specified + * in {@link TaskFragmentCreationParams#getFragmentToken()}. + * @param fragmentToken2 client assigned unique token to create TaskFragment with specified + * in {@link TaskFragmentCreationParams#getFragmentToken()}. If it is + * {@code null}, the transaction will reset the adjacent TaskFragment. + */ + @NonNull + public WindowContainerTransaction setAdjacentTaskFragments( + @NonNull IBinder fragmentToken1, @Nullable IBinder fragmentToken2, + @Nullable TaskFragmentAdjacentParams params) { + final HierarchyOp hierarchyOp = + new HierarchyOp.Builder(HierarchyOp.HIERARCHY_OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS) + .setContainer(fragmentToken1) + .setReparentContainer(fragmentToken2) + .setLaunchOptions(params != null ? params.toBundle() : null) + .build(); + mHierarchyOps.add(hierarchyOp); + return this; + } + + /** + * When this {@link WindowContainerTransaction} failed to finish on the server side, it will + * trigger callback with this {@param errorCallbackToken}. + * @param errorCallbackToken client provided token that will be passed back as parameter in + * the callback if there is an error on the server side. + * @see ITaskFragmentOrganizer#onTaskFragmentError + */ + @NonNull + public WindowContainerTransaction setErrorCallbackToken(@NonNull IBinder errorCallbackToken) { + if (mErrorCallbackToken != null) { + throw new IllegalStateException("Can't set multiple error token for one transaction."); + } + mErrorCallbackToken = errorCallbackToken; + return this; + } + + /** + * Sets the {@link TaskFragmentOrganizer} that applies this {@link WindowContainerTransaction}. + * When this is set, the server side will not check for the permission of + * {@link android.Manifest.permission#MANAGE_ACTIVITY_TASKS}, but will ensure this WCT only + * contains operations that are allowed for this organizer, such as modifying TaskFragments that + * are organized by this organizer. + * @hide + */ + @NonNull + WindowContainerTransaction setTaskFragmentOrganizer(@NonNull ITaskFragmentOrganizer organizer) { + if (mTaskFragmentOrganizer != null) { + throw new IllegalStateException("Can't set multiple organizers for one transaction."); + } + mTaskFragmentOrganizer = organizer; + return this; + } + /** * Merges another WCT into this one. * @param transfer When true, this will transfer everything from other potentially leaving @@ -398,6 +608,23 @@ public final class WindowContainerTransaction implements Parcelable { mHierarchyOps.add(transfer ? other.mHierarchyOps.get(i) : new HierarchyOp(other.mHierarchyOps.get(i))); } + if (mErrorCallbackToken != null && other.mErrorCallbackToken != null && mErrorCallbackToken + != other.mErrorCallbackToken) { + throw new IllegalArgumentException("Can't merge two WCTs with different error token"); + } + final IBinder taskFragmentOrganizerAsBinder = mTaskFragmentOrganizer != null + ? mTaskFragmentOrganizer.asBinder() + : null; + final IBinder otherTaskFragmentOrganizerAsBinder = other.mTaskFragmentOrganizer != null + ? other.mTaskFragmentOrganizer.asBinder() + : null; + if (!Objects.equals(taskFragmentOrganizerAsBinder, otherTaskFragmentOrganizerAsBinder)) { + throw new IllegalArgumentException( + "Can't merge two WCTs from different TaskFragmentOrganizers"); + } + mErrorCallbackToken = mErrorCallbackToken != null + ? mErrorCallbackToken + : other.mErrorCallbackToken; } /** @hide */ @@ -415,10 +642,26 @@ public final class WindowContainerTransaction implements Parcelable { return mHierarchyOps; } + /** @hide */ + @Nullable + public IBinder getErrorCallbackToken() { + return mErrorCallbackToken; + } + + /** @hide */ + @Nullable + public ITaskFragmentOrganizer getTaskFragmentOrganizer() { + return mTaskFragmentOrganizer; + } + @Override @NonNull public String toString() { - return "WindowContainerTransaction { changes = " + mChanges + " hops = " + mHierarchyOps + return "WindowContainerTransaction {" + + " changes = " + mChanges + + " hops = " + mHierarchyOps + + " errorCallbackToken=" + mErrorCallbackToken + + " taskFragmentOrganizer=" + mTaskFragmentOrganizer + " }"; } @@ -427,6 +670,8 @@ public final class WindowContainerTransaction implements Parcelable { public void writeToParcel(@NonNull Parcel dest, int flags) { dest.writeMap(mChanges); dest.writeList(mHierarchyOps); + dest.writeStrongBinder(mErrorCallbackToken); + dest.writeStrongInterface(mTaskFragmentOrganizer); } @Override @@ -705,6 +950,13 @@ public final class WindowContainerTransaction implements Parcelable { public static final int HIERARCHY_OP_TYPE_SET_ADJACENT_ROOTS = 4; public static final int HIERARCHY_OP_TYPE_LAUNCH_TASK = 5; public static final int HIERARCHY_OP_TYPE_SET_LAUNCH_ADJACENT_FLAG_ROOT = 6; + public static final int HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT = 7; + public static final int HIERARCHY_OP_TYPE_DELETE_TASK_FRAGMENT = 8; + public static final int HIERARCHY_OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT = 9; + public static final int HIERARCHY_OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT = 10; + public static final int HIERARCHY_OP_TYPE_REPARENT_CHILDREN = 11; + public static final int HIERARCHY_OP_TYPE_PENDING_INTENT = 12; + public static final int HIERARCHY_OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS = 13; // The following key(s) are for use with mLaunchOptions: // When launching a task (eg. from recents), this is the taskId to be launched. @@ -713,75 +965,111 @@ public final class WindowContainerTransaction implements Parcelable { private final int mType; // Container we are performing the operation on. - private final IBinder mContainer; + @Nullable + private IBinder mContainer; // If this is same as mContainer, then only change position, don't reparent. - private final IBinder mReparent; + @Nullable + private IBinder mReparent; // Moves/reparents to top of parent when {@code true}, otherwise moves/reparents to bottom. - private final boolean mToTop; + private boolean mToTop; - final private int[] mWindowingModes; - final private int[] mActivityTypes; + private boolean mReparentTopOnly; - private final Bundle mLaunchOptions; + // TODO(b/207185041): Remove this once having a single-top root for split screen. + private boolean mMoveAdjacentTogether; + + @Nullable + private int[] mWindowingModes; + + @Nullable + private int[] mActivityTypes; + + @Nullable + private Bundle mLaunchOptions; + + @Nullable + private Intent mActivityIntent; + + // Used as options for WindowContainerTransaction#createTaskFragment(). + @Nullable + private TaskFragmentCreationParams mTaskFragmentCreationOptions; + + @Nullable + private PendingIntent mPendingIntent; public static HierarchyOp createForReparent( @NonNull IBinder container, @Nullable IBinder reparent, boolean toTop) { - return new HierarchyOp(HIERARCHY_OP_TYPE_REPARENT, - container, reparent, null, null, toTop, null); + return new HierarchyOp.Builder(HIERARCHY_OP_TYPE_REPARENT) + .setContainer(container) + .setReparentContainer(reparent) + .setToTop(toTop) + .build(); } public static HierarchyOp createForReorder(@NonNull IBinder container, boolean toTop) { - return new HierarchyOp(HIERARCHY_OP_TYPE_REORDER, - container, container, null, null, toTop, null); + return new HierarchyOp.Builder(HIERARCHY_OP_TYPE_REORDER) + .setContainer(container) + .setReparentContainer(container) + .setToTop(toTop) + .build(); } public static HierarchyOp createForChildrenTasksReparent(IBinder currentParent, - IBinder newParent, int[] windowingModes, int[] activityTypes, boolean onTop) { - return new HierarchyOp(HIERARCHY_OP_TYPE_CHILDREN_TASKS_REPARENT, - currentParent, newParent, windowingModes, activityTypes, onTop, null); + IBinder newParent, int[] windowingModes, int[] activityTypes, boolean onTop, + boolean reparentTopOnly) { + return new HierarchyOp.Builder(HIERARCHY_OP_TYPE_CHILDREN_TASKS_REPARENT) + .setContainer(currentParent) + .setReparentContainer(newParent) + .setWindowingModes(windowingModes) + .setActivityTypes(activityTypes) + .setToTop(onTop) + .setReparentTopOnly(reparentTopOnly) + .build(); } public static HierarchyOp createForSetLaunchRoot(IBinder container, int[] windowingModes, int[] activityTypes) { - return new HierarchyOp(HIERARCHY_OP_TYPE_SET_LAUNCH_ROOT, - container, null, windowingModes, activityTypes, false, null); + return new HierarchyOp.Builder(HIERARCHY_OP_TYPE_SET_LAUNCH_ROOT) + .setContainer(container) + .setWindowingModes(windowingModes) + .setActivityTypes(activityTypes) + .build(); } - public static HierarchyOp createForAdjacentRoots(IBinder root1, IBinder root2) { - return new HierarchyOp(HIERARCHY_OP_TYPE_SET_ADJACENT_ROOTS, - root1, root2, null, null, false, null); + /** Create a hierarchy op for setting adjacent root tasks. */ + public static HierarchyOp createForAdjacentRoots(IBinder root1, IBinder root2, + boolean moveTogether) { + return new HierarchyOp.Builder(HIERARCHY_OP_TYPE_SET_ADJACENT_ROOTS) + .setContainer(root1) + .setReparentContainer(root2) + .setMoveAdjacentTogether(moveTogether) + .build(); } /** Create a hierarchy op for launching a task. */ public static HierarchyOp createForTaskLaunch(int taskId, @Nullable Bundle options) { final Bundle fullOptions = options == null ? new Bundle() : options; fullOptions.putInt(LAUNCH_KEY_TASK_ID, taskId); - return new HierarchyOp(HIERARCHY_OP_TYPE_LAUNCH_TASK, null, null, null, null, true, - fullOptions); + return new HierarchyOp.Builder(HIERARCHY_OP_TYPE_LAUNCH_TASK) + .setToTop(true) + .setLaunchOptions(fullOptions) + .build(); } /** Create a hierarchy op for setting launch adjacent flag root. */ public static HierarchyOp createForSetLaunchAdjacentFlagRoot(IBinder container, boolean clearRoot) { - return new HierarchyOp(HIERARCHY_OP_TYPE_SET_LAUNCH_ADJACENT_FLAG_ROOT, container, null, - null, null, clearRoot, null); + return new HierarchyOp.Builder(HIERARCHY_OP_TYPE_SET_LAUNCH_ADJACENT_FLAG_ROOT) + .setContainer(container) + .setToTop(clearRoot) + .build(); } - - private HierarchyOp(int type, @Nullable IBinder container, @Nullable IBinder reparent, - int[] windowingModes, int[] activityTypes, boolean toTop, - @Nullable Bundle launchOptions) { + /** Only creates through {@link Builder}. */ + private HierarchyOp(int type) { mType = type; - mContainer = container; - mReparent = reparent; - mWindowingModes = windowingModes != null ? - Arrays.copyOf(windowingModes, windowingModes.length) : null; - mActivityTypes = activityTypes != null ? - Arrays.copyOf(activityTypes, activityTypes.length) : null; - mToTop = toTop; - mLaunchOptions = launchOptions; } public HierarchyOp(@NonNull HierarchyOp copy) { @@ -789,9 +1077,14 @@ public final class WindowContainerTransaction implements Parcelable { mContainer = copy.mContainer; mReparent = copy.mReparent; mToTop = copy.mToTop; + mReparentTopOnly = copy.mReparentTopOnly; + mMoveAdjacentTogether = copy.mMoveAdjacentTogether; mWindowingModes = copy.mWindowingModes; mActivityTypes = copy.mActivityTypes; mLaunchOptions = copy.mLaunchOptions; + mActivityIntent = copy.mActivityIntent; + mTaskFragmentCreationOptions = copy.mTaskFragmentCreationOptions; + mPendingIntent = copy.mPendingIntent; } protected HierarchyOp(Parcel in) { @@ -799,9 +1092,14 @@ public final class WindowContainerTransaction implements Parcelable { mContainer = in.readStrongBinder(); mReparent = in.readStrongBinder(); mToTop = in.readBoolean(); + mReparentTopOnly = in.readBoolean(); + mMoveAdjacentTogether = in.readBoolean(); mWindowingModes = in.createIntArray(); mActivityTypes = in.createIntArray(); mLaunchOptions = in.readBundle(); + mActivityIntent = in.readTypedObject(Intent.CREATOR); + mTaskFragmentCreationOptions = in.readTypedObject(TaskFragmentCreationParams.CREATOR); + mPendingIntent = in.readTypedObject(PendingIntent.CREATOR); } public int getType() { @@ -827,10 +1125,23 @@ public final class WindowContainerTransaction implements Parcelable { return mReparent; } + @NonNull + public IBinder getCallingActivity() { + return mReparent; + } + public boolean getToTop() { return mToTop; } + public boolean getReparentTopOnly() { + return mReparentTopOnly; + } + + public boolean getMoveAdjacentTogether() { + return mMoveAdjacentTogether; + } + public int[] getWindowingModes() { return mWindowingModes; } @@ -844,17 +1155,33 @@ public final class WindowContainerTransaction implements Parcelable { return mLaunchOptions; } + @Nullable + public Intent getActivityIntent() { + return mActivityIntent; + } + + @Nullable + public TaskFragmentCreationParams getTaskFragmentCreationOptions() { + return mTaskFragmentCreationOptions; + } + + @Nullable + public PendingIntent getPendingIntent() { + return mPendingIntent; + } + @Override public String toString() { switch (mType) { case HIERARCHY_OP_TYPE_CHILDREN_TASKS_REPARENT: return "{ChildrenTasksReparent: from=" + mContainer + " to=" + mReparent - + " mToTop=" + mToTop + " mWindowingMode=" + mWindowingModes - + " mActivityType=" + mActivityTypes + "}"; + + " mToTop=" + mToTop + " mReparentTopOnly=" + mReparentTopOnly + + " mWindowingMode=" + Arrays.toString(mWindowingModes) + + " mActivityType=" + Arrays.toString(mActivityTypes) + "}"; case HIERARCHY_OP_TYPE_SET_LAUNCH_ROOT: return "{SetLaunchRoot: container=" + mContainer - + " mWindowingMode=" + mWindowingModes - + " mActivityType=" + mActivityTypes + "}"; + + " mWindowingMode=" + Arrays.toString(mWindowingModes) + + " mActivityType=" + Arrays.toString(mActivityTypes) + "}"; case HIERARCHY_OP_TYPE_REPARENT: return "{reparent: " + mContainer + " to " + (mToTop ? "top of " : "bottom of ") + mReparent + "}"; @@ -862,16 +1189,34 @@ public final class WindowContainerTransaction implements Parcelable { return "{reorder: " + mContainer + " to " + (mToTop ? "top" : "bottom") + "}"; case HIERARCHY_OP_TYPE_SET_ADJACENT_ROOTS: return "{SetAdjacentRoot: container=" + mContainer - + " adjacentRoot=" + mReparent + "}"; + + " adjacentRoot=" + mReparent + " mMoveAdjacentTogether=" + + mMoveAdjacentTogether + "}"; case HIERARCHY_OP_TYPE_LAUNCH_TASK: return "{LaunchTask: " + mLaunchOptions + "}"; case HIERARCHY_OP_TYPE_SET_LAUNCH_ADJACENT_FLAG_ROOT: return "{SetAdjacentFlagRoot: container=" + mContainer + " clearRoot=" + mToTop + "}"; + case HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT: + return "{CreateTaskFragment: options=" + mTaskFragmentCreationOptions + "}"; + case HIERARCHY_OP_TYPE_DELETE_TASK_FRAGMENT: + return "{DeleteTaskFragment: taskFragment=" + mContainer + "}"; + case HIERARCHY_OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT: + return "{StartActivityInTaskFragment: fragmentToken=" + mContainer + " intent=" + + mActivityIntent + " options=" + mLaunchOptions + "}"; + case HIERARCHY_OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT: + return "{ReparentActivityToTaskFragment: fragmentToken=" + mReparent + + " activity=" + mContainer + "}"; + case HIERARCHY_OP_TYPE_REPARENT_CHILDREN: + return "{ReparentChildren: oldParent=" + mContainer + " newParent=" + mReparent + + "}"; + case HIERARCHY_OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS: + return "{SetAdjacentTaskFragments: container=" + mContainer + + " adjacentContainer=" + mReparent + "}"; default: return "{mType=" + mType + " container=" + mContainer + " reparent=" + mReparent - + " mToTop=" + mToTop + " mWindowingMode=" + mWindowingModes - + " mActivityType=" + mActivityTypes + "}"; + + " mToTop=" + mToTop + + " mWindowingMode=" + Arrays.toString(mWindowingModes) + + " mActivityType=" + Arrays.toString(mActivityTypes) + "}"; } } @@ -881,9 +1226,14 @@ public final class WindowContainerTransaction implements Parcelable { dest.writeStrongBinder(mContainer); dest.writeStrongBinder(mReparent); dest.writeBoolean(mToTop); + dest.writeBoolean(mReparentTopOnly); + dest.writeBoolean(mMoveAdjacentTogether); dest.writeIntArray(mWindowingModes); dest.writeIntArray(mActivityTypes); dest.writeBundle(mLaunchOptions); + dest.writeTypedObject(mActivityIntent, flags); + dest.writeTypedObject(mTaskFragmentCreationOptions, flags); + dest.writeTypedObject(mPendingIntent, flags); } @Override @@ -902,5 +1252,182 @@ public final class WindowContainerTransaction implements Parcelable { return new HierarchyOp[size]; } }; + + private static class Builder { + + private final int mType; + + @Nullable + private IBinder mContainer; + + @Nullable + private IBinder mReparent; + + private boolean mToTop; + + private boolean mReparentTopOnly; + + private boolean mMoveAdjacentTogether; + + @Nullable + private int[] mWindowingModes; + + @Nullable + private int[] mActivityTypes; + + @Nullable + private Bundle mLaunchOptions; + + @Nullable + private Intent mActivityIntent; + + @Nullable + private TaskFragmentCreationParams mTaskFragmentCreationOptions; + + @Nullable + private PendingIntent mPendingIntent; + + Builder(int type) { + mType = type; + } + + Builder setContainer(@Nullable IBinder container) { + mContainer = container; + return this; + } + + Builder setReparentContainer(@Nullable IBinder reparentContainer) { + mReparent = reparentContainer; + return this; + } + + Builder setToTop(boolean toTop) { + mToTop = toTop; + return this; + } + + Builder setReparentTopOnly(boolean reparentTopOnly) { + mReparentTopOnly = reparentTopOnly; + return this; + } + + Builder setMoveAdjacentTogether(boolean moveAdjacentTogether) { + mMoveAdjacentTogether = moveAdjacentTogether; + return this; + } + + Builder setWindowingModes(@Nullable int[] windowingModes) { + mWindowingModes = windowingModes; + return this; + } + + Builder setActivityTypes(@Nullable int[] activityTypes) { + mActivityTypes = activityTypes; + return this; + } + + Builder setLaunchOptions(@Nullable Bundle launchOptions) { + mLaunchOptions = launchOptions; + return this; + } + + Builder setActivityIntent(@Nullable Intent activityIntent) { + mActivityIntent = activityIntent; + return this; + } + + Builder setPendingIntent(@Nullable PendingIntent sender) { + mPendingIntent = sender; + return this; + } + + Builder setTaskFragmentCreationOptions( + @Nullable TaskFragmentCreationParams taskFragmentCreationOptions) { + mTaskFragmentCreationOptions = taskFragmentCreationOptions; + return this; + } + + HierarchyOp build() { + final HierarchyOp hierarchyOp = new HierarchyOp(mType); + hierarchyOp.mContainer = mContainer; + hierarchyOp.mReparent = mReparent; + hierarchyOp.mWindowingModes = mWindowingModes != null + ? Arrays.copyOf(mWindowingModes, mWindowingModes.length) + : null; + hierarchyOp.mActivityTypes = mActivityTypes != null + ? Arrays.copyOf(mActivityTypes, mActivityTypes.length) + : null; + hierarchyOp.mToTop = mToTop; + hierarchyOp.mReparentTopOnly = mReparentTopOnly; + hierarchyOp.mMoveAdjacentTogether = mMoveAdjacentTogether; + hierarchyOp.mLaunchOptions = mLaunchOptions; + hierarchyOp.mActivityIntent = mActivityIntent; + hierarchyOp.mPendingIntent = mPendingIntent; + hierarchyOp.mTaskFragmentCreationOptions = mTaskFragmentCreationOptions; + + return hierarchyOp; + } + } + } + + /** + * Helper class for building an options Bundle that can be used to set adjacent rules of + * TaskFragments. + */ + public static class TaskFragmentAdjacentParams { + private static final String DELAY_PRIMARY_LAST_ACTIVITY_REMOVAL = + "android:transaction.adjacent.option.delay_primary_removal"; + private static final String DELAY_SECONDARY_LAST_ACTIVITY_REMOVAL = + "android:transaction.adjacent.option.delay_secondary_removal"; + + private boolean mDelayPrimaryLastActivityRemoval; + private boolean mDelaySecondaryLastActivityRemoval; + + public TaskFragmentAdjacentParams() { + } + + public TaskFragmentAdjacentParams(@NonNull Bundle bundle) { + mDelayPrimaryLastActivityRemoval = bundle.getBoolean( + DELAY_PRIMARY_LAST_ACTIVITY_REMOVAL); + mDelaySecondaryLastActivityRemoval = bundle.getBoolean( + DELAY_SECONDARY_LAST_ACTIVITY_REMOVAL); + } + + /** @see #shouldDelayPrimaryLastActivityRemoval() */ + public void setShouldDelayPrimaryLastActivityRemoval(boolean delay) { + mDelayPrimaryLastActivityRemoval = delay; + } + + /** @see #shouldDelaySecondaryLastActivityRemoval() */ + public void setShouldDelaySecondaryLastActivityRemoval(boolean delay) { + mDelaySecondaryLastActivityRemoval = delay; + } + + /** + * Whether to delay the last activity of the primary adjacent TaskFragment being immediately + * removed while finishing. + *

    + * It is usually set to {@code true} to give organizer an opportunity to perform other + * actions or animations. An example is to finish together with the adjacent TaskFragment. + *

    + */ + public boolean shouldDelayPrimaryLastActivityRemoval() { + return mDelayPrimaryLastActivityRemoval; + } + + /** + * Similar to {@link #shouldDelayPrimaryLastActivityRemoval()}, but for the secondary + * TaskFragment. + */ + public boolean shouldDelaySecondaryLastActivityRemoval() { + return mDelaySecondaryLastActivityRemoval; + } + + Bundle toBundle() { + final Bundle b = new Bundle(); + b.putBoolean(DELAY_PRIMARY_LAST_ACTIVITY_REMOVAL, mDelayPrimaryLastActivityRemoval); + b.putBoolean(DELAY_SECONDARY_LAST_ACTIVITY_REMOVAL, mDelaySecondaryLastActivityRemoval); + return b; + } } } diff --git a/core/java/android/window/WindowContext.java b/core/java/android/window/WindowContext.java index 6d0a6bd559ae..cfccb712127e 100644 --- a/core/java/android/window/WindowContext.java +++ b/core/java/android/window/WindowContext.java @@ -26,6 +26,7 @@ import android.content.Context; import android.content.ContextWrapper; import android.content.res.Configuration; import android.os.Bundle; +import android.view.Display; import android.view.WindowManager; import com.android.internal.annotations.VisibleForTesting; @@ -42,23 +43,33 @@ import java.lang.ref.Reference; * @hide */ @UiContext -public class WindowContext extends ContextWrapper { +public class WindowContext extends ContextWrapper implements WindowProvider { private final WindowManager mWindowManager; - private final @WindowManager.LayoutParams.WindowType int mType; - private final @Nullable Bundle mOptions; + @WindowManager.LayoutParams.WindowType + private final int mType; + @Nullable + private final Bundle mOptions; private final ComponentCallbacksController mCallbacksController = new ComponentCallbacksController(); private final WindowContextController mController; /** - * Default constructor. Will generate a {@link WindowTokenClient} and attach this context to - * the token. + * Default implementation of {@link WindowContext} + *

    + * Note that the users should call {@link Context#createWindowContext(Display, int, Bundle)} + * to create a {@link WindowContext} instead of using this constructor + *

    + * Example usage: + *

    +     * Bundle options = new Bundle();
    +     * options.put(KEY_ROOT_DISPLAY_AREA_ID, displayAreaInfo.rootDisplayAreaId);
    +     * Context windowContext = context.createWindowContext(display, windowType, options);
    +     * 

    * - * @param base Base {@link Context} for this new instance. - * @param type Window type to be used with this context. + * @param base Base {@link Context} for this new instance. + * @param type Window type to be used with this context. * @param options A bundle used to pass window-related options. - * - * @hide + * @see DisplayAreaInfo#rootDisplayAreaId */ public WindowContext(@NonNull Context base, int type, @Nullable Bundle options) { super(base); @@ -104,10 +115,13 @@ public class WindowContext extends ContextWrapper { @Override public void destroy() { - mCallbacksController.clearCallbacks(); - // Called to the base ContextImpl to do final clean-up. - getBaseContext().destroy(); - Reference.reachabilityFence(this); + try { + mCallbacksController.clearCallbacks(); + // Called to the base ContextImpl to do final clean-up. + getBaseContext().destroy(); + } finally { + Reference.reachabilityFence(this); + } } @Override @@ -124,4 +138,15 @@ public class WindowContext extends ContextWrapper { void dispatchConfigurationChanged(@NonNull Configuration newConfig) { mCallbacksController.dispatchConfigurationChanged(newConfig); } + + @Override + public int getWindowType() { + return mType; + } + + @Nullable + @Override + public Bundle getWindowContextOptions() { + return mOptions; + } } diff --git a/core/java/android/window/WindowInfosListener.java b/core/java/android/window/WindowInfosListener.java new file mode 100644 index 000000000000..4376e3eb572e --- /dev/null +++ b/core/java/android/window/WindowInfosListener.java @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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.window; + +import android.view.InputWindowHandle; + +import libcore.util.NativeAllocationRegistry; + +/** + * Listener for getting {@link InputWindowHandle} updates from SurfaceFlinger. + * @hide + */ +public abstract class WindowInfosListener { + private final long mNativeListener; + + public WindowInfosListener() { + NativeAllocationRegistry registry = NativeAllocationRegistry.createMalloced( + WindowInfosListener.class.getClassLoader(), nativeGetFinalizer()); + + mNativeListener = nativeCreate(this); + registry.registerNativeAllocation(this, mNativeListener); + } + + /** + * Called when WindowInfos in SurfaceFlinger have changed. + * @param windowHandles Reverse Z ordered array of window information that was on screen, + * where the first value is the topmost window. + */ + public abstract void onWindowInfosChanged(InputWindowHandle[] windowHandles); + + /** + * Register the WindowInfosListener. + */ + public void register() { + nativeRegister(mNativeListener); + } + + /** + * Unregisters the WindowInfosListener. + */ + public void unregister() { + nativeUnregister(mNativeListener); + } + + private static native long nativeCreate(WindowInfosListener thiz); + private static native void nativeRegister(long ptr); + private static native void nativeUnregister(long ptr); + private static native long nativeGetFinalizer(); +} diff --git a/core/java/android/window/WindowOrganizer.java b/core/java/android/window/WindowOrganizer.java index 544d42240079..4ea5ea5694fa 100644 --- a/core/java/android/window/WindowOrganizer.java +++ b/core/java/android/window/WindowOrganizer.java @@ -25,6 +25,7 @@ import android.app.ActivityTaskManager; import android.os.IBinder; import android.os.RemoteException; import android.util.Singleton; +import android.view.RemoteAnimationAdapter; /** * Base class for organizing specific types of windows like Tasks and DisplayAreas @@ -36,9 +37,16 @@ public class WindowOrganizer { /** * Apply multiple WindowContainer operations at once. + * + * Note that using this API requires the caller to hold + * {@link android.Manifest.permission#MANAGE_ACTIVITY_TASKS}, unless the caller is using + * {@link TaskFragmentOrganizer}, in which case it is allowed to change TaskFragment that is + * created by itself. + * * @param t The transaction to apply. */ - @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) + @RequiresPermission(value = android.Manifest.permission.MANAGE_ACTIVITY_TASKS, + conditional = true) public void applyTransaction(@NonNull WindowContainerTransaction t) { try { if (!t.isEmpty()) { @@ -51,6 +59,12 @@ public class WindowOrganizer { /** * Apply multiple WindowContainer operations at once. + * + * Note that using this API requires the caller to hold + * {@link android.Manifest.permission#MANAGE_ACTIVITY_TASKS}, unless the caller is using + * {@link TaskFragmentOrganizer}, in which case it is allowed to change TaskFragment that is + * created by itself. + * * @param t The transaction to apply. * @param callback This transaction will use the synchronization scheme described in * BLASTSyncEngine.java. The SurfaceControl transaction containing the effects of this @@ -58,7 +72,8 @@ public class WindowOrganizer { * @return An ID for the sync operation which will later be passed to transactionReady callback. * This lets the caller differentiate overlapping sync operations. */ - @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) + @RequiresPermission(value = android.Manifest.permission.MANAGE_ACTIVITY_TASKS, + conditional = true) public int applySyncTransaction(@NonNull WindowContainerTransaction t, @NonNull WindowContainerTransactionCallback callback) { try { @@ -110,6 +125,27 @@ public class WindowOrganizer { } } + /** + * Start a legacy transition. + * @param type The type of the transition. This is ignored if a transitionToken is provided. + * @param adapter An existing transition to start. If null, a new transition is created. + * @param t The set of window operations that are part of this transition. + * @return true on success, false if a transition was already running. + * @hide + */ + @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) + @NonNull + public int startLegacyTransition(int type, @NonNull RemoteAnimationAdapter adapter, + @NonNull WindowContainerTransactionCallback syncCallback, + @NonNull WindowContainerTransaction t) { + try { + return getWindowOrganizerController().startLegacyTransition( + type, adapter, syncCallback.mInterface, t); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + /** * Register an ITransitionPlayer to handle transition animations. * @hide @@ -123,8 +159,19 @@ public class WindowOrganizer { } } - @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) - IWindowOrganizerController getWindowOrganizerController() { + /** + * @see TransitionMetrics + * @hide + */ + public static ITransitionMetricsReporter getTransitionMetricsReporter() { + try { + return getWindowOrganizerController().getTransitionMetricsReporter(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + static IWindowOrganizerController getWindowOrganizerController() { return IWindowOrganizerControllerSingleton.get(); } diff --git a/core/java/android/window/WindowProvider.java b/core/java/android/window/WindowProvider.java new file mode 100644 index 000000000000..b078b9362b90 --- /dev/null +++ b/core/java/android/window/WindowProvider.java @@ -0,0 +1,39 @@ +/* + * 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.window; + +import android.annotation.Nullable; +import android.os.Bundle; +import android.view.WindowManager.LayoutParams.WindowType; + +/** + * An interface to provide a non-activity window. + * Examples are {@link WindowContext} and {@link WindowProviderService}. + * + * @hide + */ +public interface WindowProvider { + /** @hide */ + String KEY_IS_WINDOW_PROVIDER_SERVICE = "android.windowContext.isWindowProviderService"; + + /** Gets the window type of this provider */ + @WindowType + int getWindowType(); + + /** Gets the launch options of this provider */ + @Nullable + Bundle getWindowContextOptions(); +} diff --git a/core/java/android/window/WindowProviderService.java b/core/java/android/window/WindowProviderService.java index b8619fbcf334..f8484d15344e 100644 --- a/core/java/android/window/WindowProviderService.java +++ b/core/java/android/window/WindowProviderService.java @@ -36,27 +36,45 @@ import android.view.WindowManager; import android.view.WindowManager.LayoutParams.WindowType; import android.view.WindowManagerImpl; -// TODO(b/159767464): handle #onConfigurationChanged(Configuration) /** * A {@link Service} responsible for showing a non-activity window, such as software keyboards or * accessibility overlay windows. This {@link Service} has similar behavior to * {@link WindowContext}, but is represented as {@link Service}. * * @see android.inputmethodservice.InputMethodService - * @see android.accessibilityservice.AccessibilityService * * @hide */ @TestApi @UiContext -public abstract class WindowProviderService extends Service { +public abstract class WindowProviderService extends Service implements WindowProvider { + private final Bundle mOptions; private final WindowTokenClient mWindowToken = new WindowTokenClient(); private final WindowContextController mController = new WindowContextController(mWindowToken); private WindowManager mWindowManager; + private boolean mInitialized; /** - * Returns the type of this {@link WindowProviderService}. + * Returns {@code true} if the {@code windowContextOptions} declares that it is a + * {@link WindowProviderService}. + * + * @hide + */ + public static boolean isWindowProviderService(@Nullable Bundle windowContextOptions) { + if (windowContextOptions == null) { + return false; + } + return (windowContextOptions.getBoolean(KEY_IS_WINDOW_PROVIDER_SERVICE, false)); + } + + public WindowProviderService() { + mOptions = new Bundle(); + mOptions.putBoolean(KEY_IS_WINDOW_PROVIDER_SERVICE, true); + } + + /** + * Returns the window type of this {@link WindowProviderService}. * Each inheriting class must implement this method to provide the type of the window. It is * used similar to {@code type} of {@link Context#createWindowContext(int, Bundle)} * @@ -68,15 +86,24 @@ public abstract class WindowProviderService extends Service { @SuppressLint("OnNameExpected") // Suppress the lint because it is not a callback and users should provide window type // so we cannot make it final. - public abstract @WindowType int getWindowType(); + @WindowType + @Override + public abstract int getWindowType(); /** * Returns the option of this {@link WindowProviderService}. - * Default is {@code null}. The inheriting class can implement this method to provide the - * customization {@code option} of the window. It is used similar to {@code options} of - * {@link Context#createWindowContext(int, Bundle)} - * - * @see Context#createWindowContext(int, Bundle) + *

    + * The inheriting class can implement this method to provide the customization {@code option} of + * the window, but must be based on this method's returned value. + * It is used similar to {@code options} of {@link Context#createWindowContext(int, Bundle)} + *

    + *
    +     * public Bundle getWindowContextOptions() {
    +     *     final Bundle options = super.getWindowContextOptions();
    +     *     options.put(KEY_ROOT_DISPLAY_AREA_ID, displayAreaInfo.rootDisplayAreaId);
    +     *     return options;
    +     * }
    +     * 
    * * @hide */ @@ -85,8 +112,24 @@ public abstract class WindowProviderService extends Service { // Suppress the lint because it is not a callback and users may override this API to provide // launch option. Also, the return value of this API is null by default. @Nullable + @CallSuper + @Override public Bundle getWindowContextOptions() { - return null; + return mOptions; + } + + /** + * Returns the display ID to launch this {@link WindowProviderService}. + * + * @hide + */ + @TestApi + @SuppressLint({"OnNameExpected"}) + // Suppress the lint because it is not a callback and users may override this API to provide + // display. + @NonNull + public int getInitialDisplayId() { + return DEFAULT_DISPLAY; } /** @@ -104,19 +147,22 @@ public abstract class WindowProviderService extends Service { public final Context createServiceBaseContext(ActivityThread mainThread, LoadedApk packageInfo) { final Context context = super.createServiceBaseContext(mainThread, packageInfo); - // Always associate with the default display at initialization. - final Display defaultDisplay = context.getSystemService(DisplayManager.class) - .getDisplay(DEFAULT_DISPLAY); - return context.createTokenContext(mWindowToken, defaultDisplay); + final Display display = context.getSystemService(DisplayManager.class) + .getDisplay(getInitialDisplayId()); + return context.createTokenContext(mWindowToken, display); } - @CallSuper + /** @hide */ @Override - public void onCreate() { - super.onCreate(); - mWindowToken.attachContext(this); - mController.attachToDisplayArea(getWindowType(), getDisplayId(), getWindowContextOptions()); - mWindowManager = WindowManagerImpl.createWindowContextWindowManager(this); + protected void attachBaseContext(Context newBase) { + super.attachBaseContext(newBase); + if (!mInitialized) { + mWindowToken.attachContext(this); + mController.attachToDisplayArea(getWindowType(), getDisplayId(), + getWindowContextOptions()); + mWindowManager = WindowManagerImpl.createWindowContextWindowManager(this); + mInitialized = true; + } } @SuppressLint("OnNameExpected") diff --git a/core/java/android/window/WindowTokenClient.java b/core/java/android/window/WindowTokenClient.java index 876272b2b87e..547535d90e5a 100644 --- a/core/java/android/window/WindowTokenClient.java +++ b/core/java/android/window/WindowTokenClient.java @@ -15,15 +15,25 @@ */ package android.window; +import static android.window.ConfigurationHelper.freeTextLayoutCachesIfNeeded; +import static android.window.ConfigurationHelper.isDifferentDisplay; +import static android.window.ConfigurationHelper.shouldUpdateResources; + +import android.annotation.BinderThread; +import android.annotation.MainThread; import android.annotation.NonNull; import android.annotation.Nullable; -import android.app.ActivityThread; import android.app.IWindowToken; import android.app.ResourcesManager; import android.content.Context; import android.content.res.Configuration; +import android.inputmethodservice.AbstractInputMethodService; +import android.os.Build; import android.os.Bundle; +import android.os.Debug; +import android.os.Handler; import android.os.IBinder; +import android.os.Looper; import android.os.RemoteException; import android.util.Log; import android.view.IWindowManager; @@ -46,6 +56,8 @@ import java.lang.ref.WeakReference; * @hide */ public class WindowTokenClient extends IWindowToken.Stub { + private static final String TAG = WindowTokenClient.class.getSimpleName(); + /** * Attached {@link Context} for this window token to update configuration and resources. * Initialized by {@link #attachContext(Context)}. @@ -62,6 +74,8 @@ public class WindowTokenClient extends IWindowToken.Stub { private boolean mAttachToWindowContainer; + private final Handler mHandler = new Handler(Looper.getMainLooper()); + /** * Attaches {@code context} to this {@link WindowTokenClient}. Each {@link WindowTokenClient} * can only attach one {@link Context}. @@ -77,6 +91,9 @@ public class WindowTokenClient extends IWindowToken.Stub { throw new IllegalStateException("Context is already attached."); } mContextRef = new WeakReference<>(context); + mConfiguration.setTo(context.getResources().getConfiguration()); + mShouldDumpConfigForIme = Build.IS_DEBUGGABLE + && context instanceof AbstractInputMethodService; } /** @@ -95,7 +112,7 @@ public class WindowTokenClient extends IWindowToken.Stub { if (configuration == null) { return false; } - onConfigurationChanged(configuration, displayId); + onConfigurationChanged(configuration, displayId, false /* shouldReportConfigChange */); mAttachToWindowContainer = true; return true; } catch (RemoteException e) { @@ -120,7 +137,8 @@ public class WindowTokenClient extends IWindowToken.Stub { if (configuration == null) { return false; } - onConfigurationChanged(configuration, displayId); + mHandler.post(() -> onConfigurationChanged(configuration, displayId, + false /* shouldReportConfigChange */)); mAttachToWindowContainer = true; return true; } catch (RemoteException e) { @@ -167,36 +185,85 @@ public class WindowTokenClient extends IWindowToken.Stub { * @param newConfig the updated {@link Configuration} * @param newDisplayId the updated {@link android.view.Display} ID */ - @VisibleForTesting + @BinderThread @Override public void onConfigurationChanged(Configuration newConfig, int newDisplayId) { + mHandler.post(() -> onConfigurationChanged(newConfig, newDisplayId, + true /* shouldReportConfigChange */)); + } + + // TODO(b/192048581): rewrite this method based on WindowContext and WindowProviderService + // are inherited from WindowProvider. + /** + * Called when {@link Configuration} updates from the server side receive. + * + * Similar to {@link #onConfigurationChanged(Configuration, int)}, but adds a flag to control + * whether to dispatch configuration update or not. + */ + @MainThread + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) + public void onConfigurationChanged(Configuration newConfig, int newDisplayId, + boolean shouldReportConfigChange) { final Context context = mContextRef.get(); if (context == null) { return; } - final int currentDisplayId = context.getDisplayId(); - final boolean displayChanged = newDisplayId != currentDisplayId; - final Configuration config = context.getResources().getConfiguration(); - final boolean configChanged = config.diff(newConfig) != 0; - if (displayChanged || configChanged) { + final boolean displayChanged = isDifferentDisplay(context.getDisplayId(), newDisplayId); + final boolean shouldUpdateResources = shouldUpdateResources(this, mConfiguration, + newConfig, newConfig /* overrideConfig */, displayChanged, + null /* configChanged */); + + if (!shouldUpdateResources && mShouldDumpConfigForIme) { + Log.d(TAG, "Configuration not dispatch to IME because configuration is up" + + " to date. Current config=" + context.getResources().getConfiguration() + + ", reported config=" + mConfiguration + + ", updated config=" + newConfig); + } + + if (shouldUpdateResources) { // TODO(ag/9789103): update resource manager logic to track non-activity tokens mResourcesManager.updateResourcesForActivity(this, newConfig, newDisplayId); - if (context instanceof WindowContext) { - ActivityThread.currentActivityThread().getHandler().post( - () -> ((WindowContext) context).dispatchConfigurationChanged(newConfig)); + + if (shouldReportConfigChange && context instanceof WindowContext) { + final WindowContext windowContext = (WindowContext) context; + windowContext.dispatchConfigurationChanged(newConfig); + } + + final int diff = mConfiguration.diffPublicOnly(newConfig); + if (shouldReportConfigChange && diff != 0 + && context instanceof WindowProviderService) { + final WindowProviderService windowProviderService = (WindowProviderService) context; + windowProviderService.onConfigurationChanged(newConfig); } + freeTextLayoutCachesIfNeeded(diff); + if (mShouldDumpConfigForIme) { + if (!shouldReportConfigChange) { + Log.d(TAG, "Only apply configuration update to Resources because " + + "shouldReportConfigChange is false.\n" + Debug.getCallers(5)); + } else if (diff == 0) { + Log.d(TAG, "Configuration not dispatch to IME because configuration has no " + + " public difference with updated config. " + + " Current config=" + context.getResources().getConfiguration() + + ", reported config=" + mConfiguration + + ", updated config=" + newConfig); + } + } + mConfiguration.setTo(newConfig); } if (displayChanged) { context.updateDisplay(newDisplayId); } } + @BinderThread @Override public void onWindowTokenRemoved() { - final Context context = mContextRef.get(); - if (context != null) { - context.destroy(); - mContextRef.clear(); - } + mHandler.post(() -> { + final Context context = mContextRef.get(); + if (context != null) { + context.destroy(); + mContextRef.clear(); + } + }); } } diff --git a/core/java/com/android/internal/accessibility/dialog/AccessibilityShortcutChooserActivity.java b/core/java/com/android/internal/accessibility/dialog/AccessibilityShortcutChooserActivity.java index 0b92b93f2c88..874e3f4ae26a 100644 --- a/core/java/com/android/internal/accessibility/dialog/AccessibilityShortcutChooserActivity.java +++ b/core/java/com/android/internal/accessibility/dialog/AccessibilityShortcutChooserActivity.java @@ -47,6 +47,8 @@ import java.util.List; public class AccessibilityShortcutChooserActivity extends Activity { @ShortcutType private final int mShortcutType = ACCESSIBILITY_SHORTCUT_KEY; + private static final String KEY_ACCESSIBILITY_SHORTCUT_MENU_MODE = + "accessibility_shortcut_menu_mode"; private final List mTargets = new ArrayList<>(); private AlertDialog mMenuDialog; private AlertDialog mPermissionDialog; @@ -66,14 +68,30 @@ public class AccessibilityShortcutChooserActivity extends Activity { mMenuDialog = createMenuDialog(); mMenuDialog.setOnShowListener(dialog -> updateDialogListeners()); mMenuDialog.show(); + + if (savedInstanceState != null) { + final int restoreShortcutMenuMode = + savedInstanceState.getInt(KEY_ACCESSIBILITY_SHORTCUT_MENU_MODE, + ShortcutMenuMode.LAUNCH); + if (restoreShortcutMenuMode == ShortcutMenuMode.EDIT) { + onEditButtonClicked(); + } + } } @Override protected void onDestroy() { + mMenuDialog.setOnDismissListener(null); mMenuDialog.dismiss(); super.onDestroy(); } + @Override + protected void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + outState.putInt(KEY_ACCESSIBILITY_SHORTCUT_MENU_MODE, mTargetAdapter.getShortcutMenuMode()); + } + private void onTargetSelected(AdapterView parent, View view, int position, long id) { final AccessibilityTarget target = mTargets.get(position); target.onSelected(); diff --git a/core/java/com/android/internal/accessibility/util/AccessibilityStatsLogUtils.java b/core/java/com/android/internal/accessibility/util/AccessibilityStatsLogUtils.java index c57afbc67494..179ac8b1c528 100644 --- a/core/java/com/android/internal/accessibility/util/AccessibilityStatsLogUtils.java +++ b/core/java/com/android/internal/accessibility/util/AccessibilityStatsLogUtils.java @@ -17,6 +17,7 @@ package com.android.internal.accessibility.util; import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU; +import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_GESTURE; import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_ALL; import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN; import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW; @@ -30,6 +31,7 @@ import static com.android.internal.util.FrameworkStatsLog.ACCESSIBILITY_SHORTCUT import static com.android.internal.util.FrameworkStatsLog.ACCESSIBILITY_SHORTCUT_REPORTED__SHORTCUT_TYPE__A11Y_BUTTON; import static com.android.internal.util.FrameworkStatsLog.ACCESSIBILITY_SHORTCUT_REPORTED__SHORTCUT_TYPE__A11Y_BUTTON_LONG_PRESS; import static com.android.internal.util.FrameworkStatsLog.ACCESSIBILITY_SHORTCUT_REPORTED__SHORTCUT_TYPE__A11Y_FLOATING_MENU; +import static com.android.internal.util.FrameworkStatsLog.ACCESSIBILITY_SHORTCUT_REPORTED__SHORTCUT_TYPE__A11Y_GESTURE; import static com.android.internal.util.FrameworkStatsLog.ACCESSIBILITY_SHORTCUT_REPORTED__SHORTCUT_TYPE__TRIPLE_TAP; import static com.android.internal.util.FrameworkStatsLog.ACCESSIBILITY_SHORTCUT_REPORTED__SHORTCUT_TYPE__UNKNOWN_TYPE; import static com.android.internal.util.FrameworkStatsLog.ACCESSIBILITY_SHORTCUT_REPORTED__SHORTCUT_TYPE__VOLUME_KEY; @@ -152,19 +154,29 @@ public final class AccessibilityStatsLogUtils { convertToLoggingMagnificationMode(mode)); } - private static boolean isFloatingMenuEnabled(Context context) { + private static boolean isAccessibilityFloatingMenuEnabled(Context context) { return Settings.Secure.getInt(context.getContentResolver(), Settings.Secure.ACCESSIBILITY_BUTTON_MODE, /* def= */ -1) == ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU; } + private static boolean isAccessibilityGestureEnabled(Context context) { + return Settings.Secure.getInt(context.getContentResolver(), + Settings.Secure.ACCESSIBILITY_BUTTON_MODE, /* def= */ -1) + == ACCESSIBILITY_BUTTON_MODE_GESTURE; + } + private static int convertToLoggingShortcutType(Context context, @ShortcutType int shortcutType) { switch (shortcutType) { case ACCESSIBILITY_BUTTON: - return isFloatingMenuEnabled(context) - ? ACCESSIBILITY_SHORTCUT_REPORTED__SHORTCUT_TYPE__A11Y_FLOATING_MENU - : ACCESSIBILITY_SHORTCUT_REPORTED__SHORTCUT_TYPE__A11Y_BUTTON; + if (isAccessibilityFloatingMenuEnabled(context)) { + return ACCESSIBILITY_SHORTCUT_REPORTED__SHORTCUT_TYPE__A11Y_FLOATING_MENU; + } else if (isAccessibilityGestureEnabled(context)) { + return ACCESSIBILITY_SHORTCUT_REPORTED__SHORTCUT_TYPE__A11Y_GESTURE; + } else { + return ACCESSIBILITY_SHORTCUT_REPORTED__SHORTCUT_TYPE__A11Y_BUTTON; + } case ACCESSIBILITY_SHORTCUT_KEY: return ACCESSIBILITY_SHORTCUT_REPORTED__SHORTCUT_TYPE__VOLUME_KEY; } diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java index 786af5f0823e..7bb1ed8abc0a 100644 --- a/core/java/com/android/internal/app/ChooserActivity.java +++ b/core/java/com/android/internal/app/ChooserActivity.java @@ -163,9 +163,6 @@ public class ChooserActivity extends ResolverActivity implements private AppPredictor mWorkAppPredictor; private boolean mShouldDisplayLandscape; - private static final int MAX_TARGETS_PER_ROW_PORTRAIT = 4; - private static final int MAX_TARGETS_PER_ROW_LANDSCAPE = 8; - @UnsupportedAppUsage public ChooserActivity() { } @@ -275,6 +272,7 @@ public class ChooserActivity extends ResolverActivity implements private int mCurrAvailableWidth = 0; private int mLastNumberOfChildren = -1; + private int mMaxTargetsPerRow = 1; private static final String TARGET_DETAILS_FRAGMENT_TAG = "targetDetailsFragment"; @@ -741,8 +739,9 @@ public class ChooserActivity extends ResolverActivity implements mCallerChooserTargets = targets; } - mShouldDisplayLandscape = shouldDisplayLandscape( - getResources().getConfiguration().orientation); + mMaxTargetsPerRow = getResources().getInteger(R.integer.config_chooser_max_targets_per_row); + mShouldDisplayLandscape = + shouldDisplayLandscape(getResources().getConfiguration().orientation); setRetainInOnStop(intent.getBooleanExtra(EXTRA_PRIVATE_RETAIN_IN_ON_STOP, false)); super.onCreate(savedInstanceState, target, title, defaultTitleRes, initialIntents, null, false); @@ -916,7 +915,7 @@ public class ChooserActivity extends ResolverActivity implements adapter, getPersonalProfileUserHandle(), /* workProfileUserHandle= */ null, - isSendAction(getTargetIntent()), getMaxTargetsPerRow()); + isSendAction(getTargetIntent()), mMaxTargetsPerRow); } private ChooserMultiProfilePagerAdapter createChooserMultiProfilePagerAdapterForTwoProfiles( @@ -945,7 +944,7 @@ public class ChooserActivity extends ResolverActivity implements selectedProfile, getPersonalProfileUserHandle(), getWorkProfileUserHandle(), - isSendAction(getTargetIntent()), getMaxTargetsPerRow()); + isSendAction(getTargetIntent()), mMaxTargetsPerRow); } private int findSelectedProfile() { @@ -1107,6 +1106,7 @@ public class ChooserActivity extends ResolverActivity implements } mShouldDisplayLandscape = shouldDisplayLandscape(newConfig.orientation); + mMaxTargetsPerRow = getResources().getInteger(R.integer.config_chooser_max_targets_per_row); adjustPreviewWidth(newConfig.orientation, null); updateStickyContentPreview(); } @@ -2690,7 +2690,7 @@ public class ChooserActivity extends ResolverActivity implements // and b/150936654 recyclerView.setAdapter(gridAdapter); ((GridLayoutManager) recyclerView.getLayoutManager()).setSpanCount( - getMaxTargetsPerRow()); + mMaxTargetsPerRow); } UserHandle currentUserHandle = mChooserMultiProfilePagerAdapter.getCurrentUserHandle(); @@ -2855,7 +2855,7 @@ public class ChooserActivity extends ResolverActivity implements @Override // ChooserListCommunicator public int getMaxRankedTargets() { - return getMaxTargetsPerRow(); + return mMaxTargetsPerRow; } @Override // ChooserListCommunicator @@ -3203,13 +3203,6 @@ public class ChooserActivity extends ResolverActivity implements } } - int getMaxTargetsPerRow() { - int maxTargets = MAX_TARGETS_PER_ROW_PORTRAIT; - if (mShouldDisplayLandscape) { - maxTargets = MAX_TARGETS_PER_ROW_LANDSCAPE; - } - return maxTargets; - } /** * Adapter for all types of items and targets in ShareSheet. * Note that ranked sections like Direct Share - while appearing grid-like - are handled on the @@ -3277,7 +3270,11 @@ public class ChooserActivity extends ResolverActivity implements return false; } - int newWidth = width / getMaxTargetsPerRow(); + // Limit width to the maximum width of the chooser activity + int maxWidth = getResources().getDimensionPixelSize(R.dimen.chooser_width); + width = Math.min(maxWidth, width); + + int newWidth = width / mMaxTargetsPerRow; if (newWidth != mChooserTargetWidth) { mChooserTargetWidth = newWidth; return true; @@ -3312,7 +3309,7 @@ public class ChooserActivity extends ResolverActivity implements + getAzLabelRowCount() + Math.ceil( (float) mChooserListAdapter.getAlphaTargetCount() - / getMaxTargetsPerRow()) + / mMaxTargetsPerRow) ); } @@ -3352,7 +3349,7 @@ public class ChooserActivity extends ResolverActivity implements public int getCallerAndRankedTargetRowCount() { return (int) Math.ceil( ((float) mChooserListAdapter.getCallerTargetCount() - + mChooserListAdapter.getRankedTargetCount()) / getMaxTargetsPerRow()); + + mChooserListAdapter.getRankedTargetCount()) / mMaxTargetsPerRow); } // There can be at most one row in the listview, that is internally @@ -3551,7 +3548,7 @@ public class ChooserActivity extends ResolverActivity implements parentGroup.addView(row2); mDirectShareViewHolder = new DirectShareViewHolder(parentGroup, - Lists.newArrayList(row1, row2), getMaxTargetsPerRow(), viewType); + Lists.newArrayList(row1, row2), mMaxTargetsPerRow, viewType); loadViewsIntoGroup(mDirectShareViewHolder); return mDirectShareViewHolder; @@ -3559,7 +3556,7 @@ public class ChooserActivity extends ResolverActivity implements ViewGroup row = (ViewGroup) mLayoutInflater.inflate(R.layout.chooser_row, parent, false); ItemGroupViewHolder holder = - new SingleRowViewHolder(row, getMaxTargetsPerRow(), viewType); + new SingleRowViewHolder(row, mMaxTargetsPerRow, viewType); loadViewsIntoGroup(holder); return holder; @@ -3651,7 +3648,7 @@ public class ChooserActivity extends ResolverActivity implements final int serviceCount = mChooserListAdapter.getServiceTargetCount(); final int serviceRows = (int) Math.ceil((float) serviceCount / getMaxRankedTargets()); if (position < serviceRows) { - return position * getMaxTargetsPerRow(); + return position * mMaxTargetsPerRow; } position -= serviceRows; @@ -3660,7 +3657,7 @@ public class ChooserActivity extends ResolverActivity implements + mChooserListAdapter.getRankedTargetCount(); final int callerAndRankedRows = getCallerAndRankedTargetRowCount(); if (position < callerAndRankedRows) { - return serviceCount + position * getMaxTargetsPerRow(); + return serviceCount + position * mMaxTargetsPerRow; } position -= getAzLabelRowCount() + callerAndRankedRows; @@ -3673,7 +3670,7 @@ public class ChooserActivity extends ResolverActivity implements if (mDirectShareViewHolder != null && canExpandDirectShare) { mDirectShareViewHolder.handleScroll( mChooserMultiProfilePagerAdapter.getActiveAdapterView(), y, oldy, - getMaxTargetsPerRow()); + mMaxTargetsPerRow); } } diff --git a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl index c8a4425409e8..998526209c72 100644 --- a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl +++ b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl @@ -272,4 +272,14 @@ interface IVoiceInteractionManagerService { void triggerHardwareRecognitionEventForTest( in SoundTrigger.KeyphraseRecognitionEvent event, in IHotwordRecognitionStatusCallback callback); + + /** + * Starts to listen the status of visible activity. + */ + void startListeningVisibleActivityChanged(in IBinder token); + + /** + * Stops to listen the status of visible activity. + */ + void stopListeningVisibleActivityChanged(in IBinder token); } diff --git a/core/java/com/android/internal/app/LocalePickerWithRegion.java b/core/java/com/android/internal/app/LocalePickerWithRegion.java index d0719eeca04e..b4ae56f23443 100644 --- a/core/java/com/android/internal/app/LocalePickerWithRegion.java +++ b/core/java/com/android/internal/app/LocalePickerWithRegion.java @@ -158,6 +158,14 @@ public class LocalePickerWithRegion extends ListFragment implements SearchView.O setListAdapter(mAdapter); } + @Override + public void onViewCreated(View view, Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + // In order to make the list view work with CollapsingToolbarLayout, + // we have to enable the nested scrolling feature of the list view. + getListView().setNestedScrollingEnabled(true); + } + @Override public boolean onOptionsItemSelected(MenuItem menuItem) { int id = menuItem.getItemId(); diff --git a/core/java/com/android/internal/inputmethod/InputMethodDebug.java b/core/java/com/android/internal/inputmethod/InputMethodDebug.java index a00b993749a5..bf094dbd8f1e 100644 --- a/core/java/com/android/internal/inputmethod/InputMethodDebug.java +++ b/core/java/com/android/internal/inputmethod/InputMethodDebug.java @@ -236,6 +236,8 @@ public final class InputMethodDebug { return "HIDE_TOGGLE_SOFT_INPUT"; case SoftInputShowHideReason.SHOW_SOFT_INPUT_BY_INSETS_API: return "SHOW_SOFT_INPUT_BY_INSETS_API"; + case SoftInputShowHideReason.HIDE_DISPLAY_IME_POLICY_HIDE: + return "HIDE_DISPLAY_IME_POLICY_HIDE"; default: return "Unknown=" + reason; } diff --git a/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java b/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java index e3713a3b8971..9e5776292031 100644 --- a/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java +++ b/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java @@ -19,6 +19,7 @@ package com.android.internal.inputmethod; import static java.lang.annotation.RetentionPolicy.SOURCE; import android.annotation.IntDef; +import android.view.WindowManager; import android.view.WindowManager.LayoutParams; import java.lang.annotation.Retention; @@ -53,7 +54,8 @@ import java.lang.annotation.Retention; SoftInputShowHideReason.SHOW_RESTORE_IME_VISIBILITY, SoftInputShowHideReason.SHOW_TOGGLE_SOFT_INPUT, SoftInputShowHideReason.HIDE_TOGGLE_SOFT_INPUT, - SoftInputShowHideReason.SHOW_SOFT_INPUT_BY_INSETS_API}) + SoftInputShowHideReason.SHOW_SOFT_INPUT_BY_INSETS_API, + SoftInputShowHideReason.HIDE_DISPLAY_IME_POLICY_HIDE}) public @interface SoftInputShowHideReason { /** Show soft input by {@link android.view.inputmethod.InputMethodManager#showSoftInput}. */ int SHOW_SOFT_INPUT = 0; @@ -195,4 +197,10 @@ public @interface SoftInputShowHideReason { * {@link android.view.InsetsController#show(int)}; */ int SHOW_SOFT_INPUT_BY_INSETS_API = 25; + + /** + * Hide soft input if Ime policy has been set to {@link WindowManager#DISPLAY_IME_POLICY_HIDE}. + * See also {@code InputMethodManagerService#mImeHiddenByDisplayPolicy}. + */ + int HIDE_DISPLAY_IME_POLICY_HIDE = 26; } diff --git a/core/java/com/android/internal/jank/FrameTracker.java b/core/java/com/android/internal/jank/FrameTracker.java index d12c870d2591..d14054d4f9f7 100644 --- a/core/java/com/android/internal/jank/FrameTracker.java +++ b/core/java/com/android/internal/jank/FrameTracker.java @@ -45,6 +45,7 @@ import android.view.ThreadedRenderer; import android.view.ViewRootImpl; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.jank.InteractionJankMonitor.Configuration; import com.android.internal.jank.InteractionJankMonitor.Session; import com.android.internal.util.FrameworkStatsLog; @@ -70,6 +71,7 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener static final int REASON_CANCEL_NORMAL = 16; static final int REASON_CANCEL_NOT_BEGUN = 17; static final int REASON_CANCEL_SAME_VSYNC = 18; + static final int REASON_CANCEL_TIMEOUT = 19; /** @hide */ @IntDef({ @@ -97,6 +99,10 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener private final ViewRootImpl.SurfaceChangedCallback mSurfaceChangedCallback; private final Handler mHandler; private final ChoreographerWrapper mChoreographer; + private final Object mLock = InteractionJankMonitor.getInstance().getLock(); + + @VisibleForTesting + public final boolean mSurfaceOnly; private long mBeginVsyncId = INVALID_ID; private long mEndVsyncId = INVALID_ID; @@ -138,90 +144,104 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener } public FrameTracker(@NonNull Session session, @NonNull Handler handler, - @NonNull ThreadedRendererWrapper renderer, @NonNull ViewRootWrapper viewRootWrapper, + @Nullable ThreadedRendererWrapper renderer, @Nullable ViewRootWrapper viewRootWrapper, @NonNull SurfaceControlWrapper surfaceControlWrapper, @NonNull ChoreographerWrapper choreographer, - @NonNull FrameMetricsWrapper metrics, int traceThresholdMissedFrames, - int traceThresholdFrameTimeMillis, @Nullable FrameTrackerListener listener) { + @Nullable FrameMetricsWrapper metrics, + int traceThresholdMissedFrames, int traceThresholdFrameTimeMillis, + @Nullable FrameTrackerListener listener, @NonNull Configuration config) { + mSurfaceOnly = config.isSurfaceOnly(); mSession = session; - mRendererWrapper = renderer; - mMetricsWrapper = metrics; - mViewRoot = viewRootWrapper; + mHandler = handler; mChoreographer = choreographer; mSurfaceControlWrapper = surfaceControlWrapper; - mHandler = handler; - mObserver = new HardwareRendererObserver( - this, mMetricsWrapper.getTiming(), handler, false /*waitForPresentTime*/); + + // HWUI instrumentation init. + mRendererWrapper = mSurfaceOnly ? null : renderer; + mMetricsWrapper = mSurfaceOnly ? null : metrics; + mViewRoot = mSurfaceOnly ? null : viewRootWrapper; + mObserver = mSurfaceOnly + ? null + : new HardwareRendererObserver(this, mMetricsWrapper.getTiming(), + handler, /* waitForPresentTime= */ false); + mTraceThresholdMissedFrames = traceThresholdMissedFrames; mTraceThresholdFrameTimeMillis = traceThresholdFrameTimeMillis; mListener = listener; - // If the surface isn't valid yet, wait until it's created. - if (viewRootWrapper.getSurfaceControl().isValid()) { - mSurfaceControl = viewRootWrapper.getSurfaceControl(); - } - mSurfaceChangedCallback = new ViewRootImpl.SurfaceChangedCallback() { - @Override - public void surfaceCreated(SurfaceControl.Transaction t) { - synchronized (FrameTracker.this) { - if (mSurfaceControl == null) { - mSurfaceControl = viewRootWrapper.getSurfaceControl(); - if (mBeginVsyncId != INVALID_ID) { - mSurfaceControlWrapper.addJankStatsListener( - FrameTracker.this, mSurfaceControl); - postTraceStartMarker(); + if (mSurfaceOnly) { + mSurfaceControl = config.getSurfaceControl(); + mSurfaceChangedCallback = null; + } else { + // HWUI instrumentation init. + // If the surface isn't valid yet, wait until it's created. + if (mViewRoot.getSurfaceControl().isValid()) { + mSurfaceControl = mViewRoot.getSurfaceControl(); + } + + mSurfaceChangedCallback = new ViewRootImpl.SurfaceChangedCallback() { + @Override + public void surfaceCreated(SurfaceControl.Transaction t) { + synchronized (mLock) { + if (mSurfaceControl == null) { + mSurfaceControl = mViewRoot.getSurfaceControl(); + if (mBeginVsyncId != INVALID_ID) { + mSurfaceControlWrapper.addJankStatsListener( + FrameTracker.this, mSurfaceControl); + postTraceStartMarker(); + } } } } - } - @Override - public void surfaceReplaced(SurfaceControl.Transaction t) { - } + @Override + public void surfaceReplaced(SurfaceControl.Transaction t) { + } - @Override - public void surfaceDestroyed() { - - // Wait a while to give the system a chance for the remaining frames to arrive, then - // force finish the session. - mHandler.postDelayed(() -> { - synchronized (FrameTracker.this) { - if (DEBUG) { - Log.d(TAG, "surfaceDestroyed: " + mSession.getName() - + ", finalized=" + mMetricsFinalized - + ", info=" + mJankInfos.size() - + ", vsync=" + mBeginVsyncId + "-" + mEndVsyncId); - } - if (!mMetricsFinalized) { - end(REASON_END_SURFACE_DESTROYED); - finish(mJankInfos.size() - 1); + @Override + public void surfaceDestroyed() { + + // Wait a while to give the system a chance for the remaining + // frames to arrive, then force finish the session. + mHandler.postDelayed(() -> { + synchronized (mLock) { + if (DEBUG) { + Log.d(TAG, "surfaceDestroyed: " + mSession.getName() + + ", finalized=" + mMetricsFinalized + + ", info=" + mJankInfos.size() + + ", vsync=" + mBeginVsyncId); + } + if (!mMetricsFinalized) { + end(REASON_END_SURFACE_DESTROYED); + finish(mJankInfos.size() - 1); + } } - } - }, 50); - } - }; - - // This callback has a reference to FrameTracker, remember to remove it to avoid leakage. - viewRootWrapper.addSurfaceChangedCallback(mSurfaceChangedCallback); + }, 50); + } + }; + // This callback has a reference to FrameTracker, + // remember to remove it to avoid leakage. + mViewRoot.addSurfaceChangedCallback(mSurfaceChangedCallback); + } } /** * Begin a trace session of the CUJ. */ - public synchronized void begin() { - mBeginVsyncId = mChoreographer.getVsyncId() + 1; - if (mSurfaceControl != null) { - postTraceStartMarker(); - } - mRendererWrapper.addObserver(mObserver); - if (DEBUG) { - Log.d(TAG, "begin: " + mSession.getName() + ", begin=" + mBeginVsyncId); - } - if (mSurfaceControl != null) { - mSurfaceControlWrapper.addJankStatsListener(this, mSurfaceControl); - } - if (mListener != null) { - mListener.onCujEvents(mSession, ACTION_SESSION_BEGIN); + public void begin() { + synchronized (mLock) { + mBeginVsyncId = mChoreographer.getVsyncId() + 1; + if (DEBUG) { + Log.d(TAG, "begin: " + mSession.getName() + ", begin=" + mBeginVsyncId); + } + if (mSurfaceControl != null) { + postTraceStartMarker(); + mSurfaceControlWrapper.addJankStatsListener(this, mSurfaceControl); + } + if (!mSurfaceOnly) { + mRendererWrapper.addObserver(mObserver); + } + notifyCujEvent(ACTION_SESSION_BEGIN); } } @@ -231,7 +251,7 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener @VisibleForTesting public void postTraceStartMarker() { mChoreographer.mChoreographer.postCallback(Choreographer.CALLBACK_INPUT, () -> { - synchronized (FrameTracker.this) { + synchronized (mLock) { if (mCancelled || mEndVsyncId != INVALID_ID) { return; } @@ -244,86 +264,98 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener /** * End the trace session of the CUJ. */ - public synchronized void end(@Reasons int reason) { - if (mEndVsyncId != INVALID_ID) return; - mEndVsyncId = mChoreographer.getVsyncId(); - - // Cancel the session if: - // 1. The session begins and ends at the same vsync id. - // 2. The session never begun. - if (mBeginVsyncId == INVALID_ID) { - cancel(REASON_CANCEL_NOT_BEGUN); - } else if (mEndVsyncId <= mBeginVsyncId) { - cancel(REASON_CANCEL_SAME_VSYNC); - } else { - if (DEBUG) { - Log.d(TAG, "end: " + mSession.getName() - + ", end=" + mEndVsyncId + ", reason=" + reason); - } - Trace.endAsyncSection(mSession.getName(), (int) mBeginVsyncId); - mSession.setReason(reason); - if (mListener != null) { - mListener.onCujEvents(mSession, ACTION_SESSION_END); + public boolean end(@Reasons int reason) { + synchronized (mLock) { + if (mCancelled || mEndVsyncId != INVALID_ID) return false; + mEndVsyncId = mChoreographer.getVsyncId(); + // Cancel the session if: + // 1. The session begins and ends at the same vsync id. + // 2. The session never begun. + if (mBeginVsyncId == INVALID_ID) { + return cancel(REASON_CANCEL_NOT_BEGUN); + } else if (mEndVsyncId <= mBeginVsyncId) { + return cancel(REASON_CANCEL_SAME_VSYNC); + } else { + if (DEBUG) { + Log.d(TAG, "end: " + mSession.getName() + + ", end=" + mEndVsyncId + ", reason=" + reason); + } + Trace.endAsyncSection(mSession.getName(), (int) mBeginVsyncId); + mSession.setReason(reason); + + // We don't remove observer here, + // will remove it when all the frame metrics in this duration are called back. + // See onFrameMetricsAvailable for the logic of removing the observer. + // Waiting at most 10 seconds for all callbacks to finish. + mWaitForFinishTimedOut = () -> { + Log.e(TAG, "force finish cuj because of time out:" + mSession.getName()); + finish(mJankInfos.size() - 1); + }; + mHandler.postDelayed(mWaitForFinishTimedOut, TimeUnit.SECONDS.toMillis(10)); + notifyCujEvent(ACTION_SESSION_END); + return true; } - // We don't remove observer here, - // will remove it when all the frame metrics in this duration are called back. - // See onFrameMetricsAvailable for the logic of removing the observer. - // Waiting at most 10 seconds for all callbacks to finish. - mWaitForFinishTimedOut = () -> { - Log.e(TAG, "force finish cuj because of time out:" + mSession.getName()); - finish(mJankInfos.size() - 1); - }; - mHandler.postDelayed(mWaitForFinishTimedOut, TimeUnit.SECONDS.toMillis(10)); } } /** * Cancel the trace session of the CUJ. */ - public synchronized void cancel(@Reasons int reason) { - // We don't need to end the trace section if it never begun. - if (mTracingStarted) { - Trace.endAsyncSection(mSession.getName(), (int) mBeginVsyncId); - } - mCancelled = true; + public boolean cancel(@Reasons int reason) { + synchronized (mLock) { + final boolean cancelFromEnd = + reason == REASON_CANCEL_NOT_BEGUN || reason == REASON_CANCEL_SAME_VSYNC; + if (mCancelled || (mEndVsyncId != INVALID_ID && !cancelFromEnd)) return false; + mCancelled = true; + // We don't need to end the trace section if it never begun. + if (mTracingStarted) { + Trace.endAsyncSection(mSession.getName(), (int) mBeginVsyncId); + } - // Always remove the observers in cancel call to avoid leakage. - removeObservers(); + // Always remove the observers in cancel call to avoid leakage. + removeObservers(); - if (DEBUG) { - Log.d(TAG, "cancel: " + mSession.getName() - + ", begin=" + mBeginVsyncId + ", end=" + mEndVsyncId + ", reason=" + reason); - } + if (DEBUG) { + Log.d(TAG, "cancel: " + mSession.getName() + ", begin=" + mBeginVsyncId + + ", end=" + mEndVsyncId + ", reason=" + reason); + } - mSession.setReason(reason); - // Notify the listener the session has been cancelled. - // We don't notify the listeners if the session never begun. - if (mListener != null) { - mListener.onCujEvents(mSession, ACTION_SESSION_CANCEL); + mSession.setReason(reason); + // Notify the listener the session has been cancelled. + // We don't notify the listeners if the session never begun. + notifyCujEvent(ACTION_SESSION_CANCEL); + return true; } } - @Override - public synchronized void onJankDataAvailable(SurfaceControl.JankData[] jankData) { - if (mCancelled) { - return; - } + private void notifyCujEvent(String action) { + if (mListener == null) return; + mListener.onCujEvents(mSession, action); + } - for (SurfaceControl.JankData jankStat : jankData) { - if (!isInRange(jankStat.frameVsyncId)) { - continue; + @Override + public void onJankDataAvailable(SurfaceControl.JankData[] jankData) { + synchronized (mLock) { + if (mCancelled) { + return; } - JankInfo info = findJankInfo(jankStat.frameVsyncId); - if (info != null) { - info.surfaceControlCallbackFired = true; - info.jankType = jankStat.jankType; - } else { - mJankInfos.put((int) jankStat.frameVsyncId, - JankInfo.createFromSurfaceControlCallback( - jankStat.frameVsyncId, jankStat.jankType)); + + for (SurfaceControl.JankData jankStat : jankData) { + if (!isInRange(jankStat.frameVsyncId)) { + continue; + } + JankInfo info = findJankInfo(jankStat.frameVsyncId); + if (info != null) { + info.surfaceControlCallbackFired = true; + info.jankType = jankStat.jankType; + } else { + mJankInfos.put((int) jankStat.frameVsyncId, + JankInfo.createFromSurfaceControlCallback( + jankStat.frameVsyncId, jankStat.jankType)); + } } + processJankInfos(); } - processJankInfos(); } private @Nullable JankInfo findJankInfo(long frameVsyncId) { @@ -338,31 +370,34 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener } @Override - public synchronized void onFrameMetricsAvailable(int dropCountSinceLastInvocation) { - if (mCancelled) { - return; - } + public void onFrameMetricsAvailable(int dropCountSinceLastInvocation) { + synchronized (mLock) { + if (mCancelled) { + return; + } - // Since this callback might come a little bit late after the end() call. - // We should keep tracking the begin / end timestamp. - // Then compare with vsync timestamp to check if the frame is in the duration of the CUJ. - long totalDurationNanos = mMetricsWrapper.getMetric(FrameMetrics.TOTAL_DURATION); - boolean isFirstFrame = mMetricsWrapper.getMetric(FrameMetrics.FIRST_DRAW_FRAME) == 1; - long frameVsyncId = mMetricsWrapper.getTiming()[FrameMetrics.Index.FRAME_TIMELINE_VSYNC_ID]; + // Since this callback might come a little bit late after the end() call. + // We should keep tracking the begin / end timestamp that we can compare with + // vsync timestamp to check if the frame is in the duration of the CUJ. + long totalDurationNanos = mMetricsWrapper.getMetric(FrameMetrics.TOTAL_DURATION); + boolean isFirstFrame = mMetricsWrapper.getMetric(FrameMetrics.FIRST_DRAW_FRAME) == 1; + long frameVsyncId = + mMetricsWrapper.getTiming()[FrameMetrics.Index.FRAME_TIMELINE_VSYNC_ID]; - if (!isInRange(frameVsyncId)) { - return; - } - JankInfo info = findJankInfo(frameVsyncId); - if (info != null) { - info.hwuiCallbackFired = true; - info.totalDurationNanos = totalDurationNanos; - info.isFirstFrame = isFirstFrame; - } else { - mJankInfos.put((int) frameVsyncId, JankInfo.createFromHwuiCallback( - frameVsyncId, totalDurationNanos, isFirstFrame)); + if (!isInRange(frameVsyncId)) { + return; + } + JankInfo info = findJankInfo(frameVsyncId); + if (info != null) { + info.hwuiCallbackFired = true; + info.totalDurationNanos = totalDurationNanos; + info.isFirstFrame = isFirstFrame; + } else { + mJankInfos.put((int) frameVsyncId, JankInfo.createFromHwuiCallback( + frameVsyncId, totalDurationNanos, isFirstFrame)); + } + processJankInfos(); } - processJankInfos(); } /** @@ -385,7 +420,7 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener for (int i = mJankInfos.size() - 1; i >= 0; i--) { JankInfo info = mJankInfos.valueAt(i); if (info.frameVsyncId >= mEndVsyncId) { - if (info.hwuiCallbackFired && info.surfaceControlCallbackFired) { + if (isLastIndexCandidate(info)) { lastIndex = i; } } else { @@ -403,6 +438,12 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener finish(indexOnOrAfterEnd); } + private boolean isLastIndexCandidate(JankInfo info) { + return mSurfaceOnly + ? info.surfaceControlCallbackFired + : info.hwuiCallbackFired && info.surfaceControlCallbackFired; + } + private void finish(int indexOnOrAfterEnd) { mHandler.removeCallbacks(mWaitForFinishTimedOut); mWaitForFinishTimedOut = null; @@ -419,7 +460,8 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener for (int i = 0; i <= indexOnOrAfterEnd; i++) { JankInfo info = mJankInfos.valueAt(i); - if (info.isFirstFrame) { + final boolean isFirstDrawn = !mSurfaceOnly && info.isFirstFrame; + if (isFirstDrawn) { continue; } if (info.surfaceControlCallbackFired) { @@ -444,11 +486,11 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener } // TODO (b/174755489): Early latch currently gets fired way too often, so we have // to ignore it for now. - if (!info.hwuiCallbackFired) { + if (!mSurfaceOnly && !info.hwuiCallbackFired) { Log.w(TAG, "Missing HWUI jank callback for vsyncId: " + info.frameVsyncId); } } - if (info.hwuiCallbackFired) { + if (!mSurfaceOnly && info.hwuiCallbackFired) { maxFrameTimeNanos = Math.max(info.totalDurationNanos, maxFrameTimeNanos); if (!info.surfaceControlCallbackFired) { Log.w(TAG, "Missing SF jank callback for vsyncId: " + info.frameVsyncId); @@ -469,11 +511,7 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener (int) (maxFrameTimeNanos / NANOS_IN_MILLISECOND)); // Trigger perfetto if necessary. - boolean overMissedFramesThreshold = mTraceThresholdMissedFrames != -1 - && missedFramesCount >= mTraceThresholdMissedFrames; - boolean overFrameTimeThreshold = mTraceThresholdFrameTimeMillis != -1 - && maxFrameTimeNanos >= mTraceThresholdFrameTimeMillis * NANOS_IN_MILLISECOND; - if (overMissedFramesThreshold || overFrameTimeThreshold) { + if (shouldTriggerPerfetto(missedFramesCount, (int) maxFrameTimeNanos)) { triggerPerfetto(); } if (mSession.logToStatsd()) { @@ -482,12 +520,10 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener mSession.getStatsdInteractionType(), totalFramesCount, missedFramesCount, - maxFrameTimeNanos, + maxFrameTimeNanos, /* will be 0 if mSurfaceOnly == true */ missedSfFramesCount, missedAppFramesCount); - if (mListener != null) { - mListener.onCujEvents(mSession, ACTION_METRICS_LOGGED); - } + notifyCujEvent(ACTION_METRICS_LOGGED); } if (DEBUG) { Log.i(TAG, "finish: CUJ=" + mSession.getName() @@ -500,15 +536,26 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener } } + private boolean shouldTriggerPerfetto(int missedFramesCount, int maxFrameTimeNanos) { + boolean overMissedFramesThreshold = mTraceThresholdMissedFrames != -1 + && missedFramesCount >= mTraceThresholdMissedFrames; + boolean overFrameTimeThreshold = !mSurfaceOnly && mTraceThresholdFrameTimeMillis != -1 + && maxFrameTimeNanos >= mTraceThresholdFrameTimeMillis * NANOS_IN_MILLISECOND; + return overMissedFramesThreshold || overFrameTimeThreshold; + } + /** * Remove all the registered listeners, observers and callbacks. */ @VisibleForTesting public void removeObservers() { - mRendererWrapper.removeObserver(mObserver); mSurfaceControlWrapper.removeJankStatsListener(this); - if (mSurfaceChangedCallback != null) { - mViewRoot.removeSurfaceChangedCallback(mSurfaceChangedCallback); + if (!mSurfaceOnly) { + // HWUI part. + mRendererWrapper.removeObserver(mObserver); + if (mSurfaceChangedCallback != null) { + mViewRoot.removeSurfaceChangedCallback(mSurfaceChangedCallback); + } } } diff --git a/core/java/com/android/internal/jank/InteractionJankMonitor.java b/core/java/com/android/internal/jank/InteractionJankMonitor.java index 610cd7339001..ea38db304e6d 100644 --- a/core/java/com/android/internal/jank/InteractionJankMonitor.java +++ b/core/java/com/android/internal/jank/InteractionJankMonitor.java @@ -18,11 +18,11 @@ package com.android.internal.jank; import static android.content.Intent.FLAG_RECEIVER_REGISTERED_ONLY; -import static com.android.internal.jank.FrameTracker.ChoreographerWrapper; import static com.android.internal.jank.FrameTracker.REASON_CANCEL_NORMAL; import static com.android.internal.jank.FrameTracker.REASON_CANCEL_NOT_BEGUN; +import static com.android.internal.jank.FrameTracker.REASON_CANCEL_TIMEOUT; import static com.android.internal.jank.FrameTracker.REASON_END_NORMAL; -import static com.android.internal.jank.FrameTracker.SurfaceControlWrapper; +import static com.android.internal.jank.FrameTracker.REASON_END_UNKNOWN; import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_ALL_APPS_SCROLL; import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_APP_CLOSE_TO_HOME; import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_APP_CLOSE_TO_PIP; @@ -41,6 +41,7 @@ import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_IN import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LOCKSCREEN_TRANSITION_TO_AOD; import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LOCKSCREEN_UNLOCK_ANIMATION; import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__NOTIFICATION_SHADE_SWIPE; +import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__PIP_TRANSITION; import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SETTINGS_PAGE_SCROLL; import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_APP_LAUNCH; import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_APP_LAUNCH_FROM_HISTORY_BUTTON; @@ -57,7 +58,11 @@ import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_IN import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_ROW_EXPAND; import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_ROW_SWIPE; import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_SCROLL_FLING; +import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SPLASHSCREEN_AVD; +import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SPLASHSCREEN_EXIT_ANIM; import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__STATUS_BAR_APP_LAUNCH_FROM_CALL_CHIP; +import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__USER_SWITCH; +import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__WALLPAPER_TRANSITION; import android.annotation.IntDef; import android.annotation.NonNull; @@ -72,11 +77,15 @@ import android.text.TextUtils; import android.util.Log; import android.util.SparseArray; import android.view.Choreographer; +import android.view.SurfaceControl; import android.view.View; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.jank.FrameTracker.ChoreographerWrapper; import com.android.internal.jank.FrameTracker.FrameMetricsWrapper; import com.android.internal.jank.FrameTracker.FrameTrackerListener; +import com.android.internal.jank.FrameTracker.Reasons; +import com.android.internal.jank.FrameTracker.SurfaceControlWrapper; import com.android.internal.jank.FrameTracker.ThreadedRendererWrapper; import com.android.internal.jank.FrameTracker.ViewRootWrapper; import com.android.internal.util.PerfettoTrigger; @@ -163,6 +172,11 @@ public class InteractionJankMonitor { public static final int CUJ_SHADE_APP_LAUNCH_FROM_QS_TILE = 32; public static final int CUJ_SHADE_APP_LAUNCH_FROM_SETTINGS_BUTTON = 33; public static final int CUJ_STATUS_BAR_APP_LAUNCH_FROM_CALL_CHIP = 34; + public static final int CUJ_PIP_TRANSITION = 35; + public static final int CUJ_WALLPAPER_TRANSITION = 36; + public static final int CUJ_USER_SWITCH = 37; + public static final int CUJ_SPLASHSCREEN_AVD = 38; + public static final int CUJ_SPLASHSCREEN_EXIT_ANIM = 39; private static final int NO_STATSD_LOGGING = -1; @@ -206,6 +220,11 @@ public class InteractionJankMonitor { UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_APP_LAUNCH_FROM_QS_TILE, UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_APP_LAUNCH_FROM_SETTINGS_BUTTON, UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__STATUS_BAR_APP_LAUNCH_FROM_CALL_CHIP, + UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__PIP_TRANSITION, + UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__WALLPAPER_TRANSITION, + UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__USER_SWITCH, + UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SPLASHSCREEN_AVD, + UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SPLASHSCREEN_EXIT_ANIM, }; private static volatile InteractionJankMonitor sInstance; @@ -213,10 +232,11 @@ public class InteractionJankMonitor { private final DeviceConfig.OnPropertiesChangedListener mPropertiesChangedListener = this::updateProperties; - private FrameMetricsWrapper mMetrics; - private SparseArray mRunningTrackers; - private SparseArray mTimeoutActions; - private HandlerThread mWorker; + private final FrameMetricsWrapper mMetrics; + private final SparseArray mRunningTrackers; + private final SparseArray mTimeoutActions; + private final HandlerThread mWorker; + private final Object mLock = new Object(); private boolean mEnabled = DEFAULT_ENABLED; private int mSamplingInterval = DEFAULT_SAMPLING_INTERVAL; @@ -260,6 +280,11 @@ public class InteractionJankMonitor { CUJ_SHADE_APP_LAUNCH_FROM_QS_TILE, CUJ_SHADE_APP_LAUNCH_FROM_SETTINGS_BUTTON, CUJ_STATUS_BAR_APP_LAUNCH_FROM_CALL_CHIP, + CUJ_PIP_TRANSITION, + CUJ_WALLPAPER_TRANSITION, + CUJ_USER_SWITCH, + CUJ_SPLASHSCREEN_AVD, + CUJ_SPLASHSCREEN_EXIT_ANIM, }) @Retention(RetentionPolicy.SOURCE) public @interface CujType { @@ -309,25 +334,36 @@ public class InteractionJankMonitor { mPropertiesChangedListener); } + Object getLock() { + return mLock; + } + /** - * Create a {@link FrameTracker} instance. + * Creates a {@link FrameTracker} instance. * + * @param config the config used in instrumenting * @param session the session associates with this tracker * @return instance of the FrameTracker */ @VisibleForTesting - public FrameTracker createFrameTracker(Configuration conf, Session session) { - final View v = conf.mView; - final Context c = v.getContext().getApplicationContext(); - final ThreadedRendererWrapper r = new ThreadedRendererWrapper(v.getThreadedRenderer()); - final ViewRootWrapper vr = new ViewRootWrapper(v.getViewRootImpl()); - final SurfaceControlWrapper sc = new SurfaceControlWrapper(); - final ChoreographerWrapper cg = new ChoreographerWrapper(Choreographer.getInstance()); - - synchronized (this) { - FrameTrackerListener eventsListener = (s, act) -> handleCujEvents(c, act, s); - return new FrameTracker(session, mWorker.getThreadHandler(), r, vr, sc, cg, mMetrics, - mTraceThresholdMissedFrames, mTraceThresholdFrameTimeMillis, eventsListener); + public FrameTracker createFrameTracker(Configuration config, Session session) { + final View view = config.mView; + final ThreadedRendererWrapper threadedRenderer = + view == null ? null : new ThreadedRendererWrapper(view.getThreadedRenderer()); + final ViewRootWrapper viewRoot = + view == null ? null : new ViewRootWrapper(view.getViewRootImpl()); + + final SurfaceControlWrapper surfaceControl = new SurfaceControlWrapper(); + final ChoreographerWrapper choreographer = + new ChoreographerWrapper(Choreographer.getInstance()); + + synchronized (mLock) { + FrameTrackerListener eventsListener = + (s, act) -> handleCujEvents(config.getContext(), act, s); + return new FrameTracker(session, mWorker.getThreadHandler(), + threadedRenderer, viewRoot, surfaceControl, choreographer, mMetrics, + mTraceThresholdMissedFrames, mTraceThresholdFrameTimeMillis, + eventsListener, config); } } @@ -341,7 +377,13 @@ public class InteractionJankMonitor { // Notify the receivers if necessary. if (session.shouldNotify()) { - notifyEvents(context, action, session); + if (context != null) { + notifyEvents(context, action, session); + } else { + throw new IllegalArgumentException( + "Can't notify cuj events due to lack of context: cuj=" + + session.getName() + ", action=" + action); + } } } @@ -349,11 +391,16 @@ public class InteractionJankMonitor { final boolean badEnd = action.equals(ACTION_SESSION_END) && session.getReason() != REASON_END_NORMAL; final boolean badCancel = action.equals(ACTION_SESSION_CANCEL) - && session.getReason() != REASON_CANCEL_NORMAL; + && !(session.getReason() == REASON_CANCEL_NORMAL + || session.getReason() == REASON_CANCEL_TIMEOUT); return badEnd || badCancel; } - private void notifyEvents(Context context, String action, Session session) { + /** + * Notifies who may interest in some CUJ events. + */ + @VisibleForTesting + public void notifyEvents(Context context, String action, Session session) { if (action.equals(ACTION_SESSION_CANCEL) && session.getReason() == REASON_CANCEL_NOT_BEGUN) { return; @@ -366,7 +413,7 @@ public class InteractionJankMonitor { } private void removeTimeout(@CujType int cujType) { - synchronized (this) { + synchronized (mLock) { Runnable timeout = mTimeoutActions.get(cujType); if (timeout != null) { mWorker.getThreadHandler().removeCallbacks(timeout); @@ -376,7 +423,7 @@ public class InteractionJankMonitor { } /** - * Begin a trace session. + * Begins a trace session. * * @param v an attached view. * @param cujType the specific {@link InteractionJankMonitor.CujType}. @@ -385,8 +432,7 @@ public class InteractionJankMonitor { public boolean begin(View v, @CujType int cujType) { try { return beginInternal( - new Configuration.Builder(cujType) - .setView(v) + Configuration.Builder.withView(cujType, v) .build()); } catch (IllegalArgumentException ex) { Log.d(TAG, "Build configuration failed!", ex); @@ -395,7 +441,7 @@ public class InteractionJankMonitor { } /** - * Begin a trace session. + * Begins a trace session. * * @param builder the builder of the configurations for instrumenting the CUJ. * @return boolean true if the tracker is started successfully, false otherwise. @@ -410,17 +456,9 @@ public class InteractionJankMonitor { } private boolean beginInternal(@NonNull Configuration conf) { - synchronized (this) { + synchronized (mLock) { int cujType = conf.mCujType; - boolean shouldSample = ThreadLocalRandom.current().nextInt() % mSamplingInterval == 0; - if (!mEnabled || !shouldSample) { - if (DEBUG) { - Log.d(TAG, "Skip monitoring cuj: " + getNameOfCuj(cujType) - + ", enable=" + mEnabled + ", debuggable=" + DEFAULT_ENABLED - + ", sample=" + shouldSample + ", interval=" + mSamplingInterval); - } - return false; - } + if (!shouldMonitor(cujType)) return false; FrameTracker tracker = getTracker(cujType); // Skip subsequent calls if we already have an ongoing tracing. if (tracker != null) return false; @@ -431,67 +469,103 @@ public class InteractionJankMonitor { tracker.begin(); // Cancel the trace if we don't get an end() call in specified duration. - Runnable timeoutAction = () -> cancel(cujType); - mTimeoutActions.put(cujType, timeoutAction); - mWorker.getThreadHandler().postDelayed(timeoutAction, conf.mTimeout); + scheduleTimeoutAction( + cujType, conf.mTimeout, () -> cancel(cujType, REASON_CANCEL_TIMEOUT)); return true; } } /** - * End a trace session. + * Check if the monitoring is enabled and if it should be sampled. + */ + @SuppressWarnings("RandomModInteger") + @VisibleForTesting + public boolean shouldMonitor(@CujType int cujType) { + boolean shouldSample = ThreadLocalRandom.current().nextInt() % mSamplingInterval == 0; + if (!mEnabled || !shouldSample) { + if (DEBUG) { + Log.d(TAG, "Skip monitoring cuj: " + getNameOfCuj(cujType) + + ", enable=" + mEnabled + ", debuggable=" + DEFAULT_ENABLED + + ", sample=" + shouldSample + ", interval=" + mSamplingInterval); + } + return false; + } + return true; + } + + /** + * Schedules a timeout action. + * @param cuj cuj type + * @param timeout duration to timeout + * @param action action once timeout + */ + @VisibleForTesting + public void scheduleTimeoutAction(@CujType int cuj, long timeout, Runnable action) { + mTimeoutActions.put(cuj, action); + mWorker.getThreadHandler().postDelayed(action, timeout); + } + + /** + * Ends a trace session. * * @param cujType the specific {@link InteractionJankMonitor.CujType}. * @return boolean true if the tracker is ended successfully, false otherwise. */ public boolean end(@CujType int cujType) { - //TODO (163505250): This should be no-op if not in droid food rom. - synchronized (this) { - + synchronized (mLock) { // remove the timeout action first. removeTimeout(cujType); FrameTracker tracker = getTracker(cujType); // Skip this call since we haven't started a trace yet. if (tracker == null) return false; - tracker.end(FrameTracker.REASON_END_NORMAL); - removeTracker(cujType); + // if the end call doesn't return true, another thread is handling end of the cuj. + if (tracker.end(REASON_END_NORMAL)) { + removeTracker(cujType); + } return true; } } /** - * Cancel the trace session. + * Cancels the trace session. * * @return boolean true if the tracker is cancelled successfully, false otherwise. */ public boolean cancel(@CujType int cujType) { - //TODO (163505250): This should be no-op if not in droid food rom. - synchronized (this) { + return cancel(cujType, REASON_CANCEL_NORMAL); + } + + /** + * Cancels the trace session. + * + * @return boolean true if the tracker is cancelled successfully, false otherwise. + */ + @VisibleForTesting + public boolean cancel(@CujType int cujType, @Reasons int reason) { + synchronized (mLock) { // remove the timeout action first. removeTimeout(cujType); FrameTracker tracker = getTracker(cujType); // Skip this call since we haven't started a trace yet. if (tracker == null) return false; - tracker.cancel(FrameTracker.REASON_CANCEL_NORMAL); - removeTracker(cujType); + // if the cancel call doesn't return true, another thread is handling cancel of the cuj. + if (tracker.cancel(reason)) { + removeTracker(cujType); + } return true; } } private FrameTracker getTracker(@CujType int cuj) { - synchronized (this) { - return mRunningTrackers.get(cuj); - } + return mRunningTrackers.get(cuj); } private void removeTracker(@CujType int cuj) { - synchronized (this) { - mRunningTrackers.remove(cuj); - } + mRunningTrackers.remove(cuj); } private void updateProperties(DeviceConfig.Properties properties) { - synchronized (this) { + synchronized (mLock) { mSamplingInterval = properties.getInt(SETTINGS_SAMPLING_INTERVAL_KEY, DEFAULT_SAMPLING_INTERVAL); mEnabled = properties.getBoolean(SETTINGS_ENABLED_KEY, DEFAULT_ENABLED); @@ -509,14 +583,12 @@ public class InteractionJankMonitor { } /** - * Trigger the perfetto daemon to collect and upload data. + * Triggers the perfetto daemon to collect and upload data. */ @VisibleForTesting public void trigger(Session session) { - synchronized (this) { - mWorker.getThreadHandler().post( - () -> PerfettoTrigger.trigger(session.getPerfettoTrigger())); - } + mWorker.getThreadHandler().post( + () -> PerfettoTrigger.trigger(session.getPerfettoTrigger())); } /** @@ -608,6 +680,16 @@ public class InteractionJankMonitor { return "SHADE_APP_LAUNCH_FROM_SETTINGS_BUTTON"; case CUJ_STATUS_BAR_APP_LAUNCH_FROM_CALL_CHIP: return "STATUS_BAR_APP_LAUNCH_FROM_CALL_CHIP"; + case CUJ_PIP_TRANSITION: + return "PIP_TRANSITION"; + case CUJ_WALLPAPER_TRANSITION: + return "WALLPAPER_TRANSITION"; + case CUJ_USER_SWITCH: + return "USER_SWITCH"; + case CUJ_SPLASHSCREEN_AVD: + return "SPLASHSCREEN_AVD"; + case CUJ_SPLASHSCREEN_EXIT_ANIM: + return "SPLASHSCREEN_EXIT_ANIM"; } return "UNKNOWN"; } @@ -618,32 +700,65 @@ public class InteractionJankMonitor { */ public static class Configuration { private final View mView; + private final Context mContext; private final long mTimeout; private final String mTag; + private final boolean mSurfaceOnly; + private final SurfaceControl mSurfaceControl; private final @CujType int mCujType; /** - * A builder for building Configuration.
    + * A builder for building Configuration. {@link #setView(View)} is essential + * if {@link #setSurfaceOnly(boolean)} is not set, otherwise both + * {@link #setSurfaceControl(SurfaceControl)} and {@link #setContext(Context)} + * are necessary
    * It may refer to an attached view, don't use static reference for any purpose. */ public static class Builder { private View mAttrView = null; + private Context mAttrContext = null; private long mAttrTimeout = DEFAULT_TIMEOUT_MS; private String mAttrTag = ""; + private boolean mAttrSurfaceOnly; + private SurfaceControl mAttrSurfaceControl; private @CujType int mAttrCujType; /** + * Creates a builder which instruments only surface. * @param cuj The enum defined in {@link InteractionJankMonitor.CujType}. + * @param context context + * @param surfaceControl surface control + * @return builder */ - public Builder(@CujType int cuj) { + public static Builder withSurface(@CujType int cuj, @NonNull Context context, + @NonNull SurfaceControl surfaceControl) { + return new Builder(cuj) + .setContext(context) + .setSurfaceControl(surfaceControl) + .setSurfaceOnly(true); + } + + /** + * Creates a builder which instruments both surface and view. + * @param cuj The enum defined in {@link InteractionJankMonitor.CujType}. + * @param view view + * @return builder + */ + public static Builder withView(@CujType int cuj, @NonNull View view) { + return new Builder(cuj).setView(view) + .setContext(view.getContext()); + } + + private Builder(@CujType int cuj) { mAttrCujType = cuj; } /** + * Specifies a view, must be set if {@link #setSurfaceOnly(boolean)} is set to false. * @param view an attached view * @return builder */ - public Builder setView(@NonNull View view) { + private Builder setView(@NonNull View view) { mAttrView = view; return this; } @@ -669,20 +784,56 @@ public class InteractionJankMonitor { } /** - * Build the {@link Configuration} instance + * Indicates if only instrument with surface, + * if true, must also setup with {@link #setContext(Context)} + * and {@link #setSurfaceControl(SurfaceControl)}. + * @param surfaceOnly true if only instrument with surface, false otherwise + * @return builder Surface only builder. + */ + private Builder setSurfaceOnly(boolean surfaceOnly) { + mAttrSurfaceOnly = surfaceOnly; + return this; + } + + /** + * Specifies a context, must set if {@link #setSurfaceOnly(boolean)} is set. + */ + private Builder setContext(Context context) { + mAttrContext = context; + return this; + } + + /** + * Specifies a surface control, must be set if {@link #setSurfaceOnly(boolean)} is set. + */ + private Builder setSurfaceControl(SurfaceControl surfaceControl) { + mAttrSurfaceControl = surfaceControl; + return this; + } + + /** + * Builds the {@link Configuration} instance * @return the instance of {@link Configuration} * @throws IllegalArgumentException if any invalid attribute is set */ public Configuration build() throws IllegalArgumentException { - return new Configuration(mAttrCujType, mAttrView, mAttrTag, mAttrTimeout); + return new Configuration( + mAttrCujType, mAttrView, mAttrTag, mAttrTimeout, + mAttrSurfaceOnly, mAttrContext, mAttrSurfaceControl); } } - private Configuration(@CujType int cuj, View view, String tag, long timeout) { + private Configuration(@CujType int cuj, View view, String tag, long timeout, + boolean surfaceOnly, Context context, SurfaceControl surfaceControl) { mCujType = cuj; mTag = tag; mTimeout = timeout; mView = view; + mSurfaceOnly = surfaceOnly; + mContext = context != null + ? context + : (view != null ? view.getContext().getApplicationContext() : null); + mSurfaceControl = surfaceControl; validate(); } @@ -698,14 +849,47 @@ public class InteractionJankMonitor { shouldThrow = true; msg.append("Invalid timeout value; "); } - if (mView == null || !mView.isAttachedToWindow()) { - shouldThrow = true; - msg.append("Null view or view is not attached yet; "); + if (mSurfaceOnly) { + if (mContext == null) { + shouldThrow = true; + msg.append("Must pass in a context if only instrument surface; "); + } + if (mSurfaceControl == null || !mSurfaceControl.isValid()) { + shouldThrow = true; + msg.append("Must pass in a valid surface control if only instrument surface; "); + } + } else { + if (mView == null || !mView.isAttachedToWindow()) { + shouldThrow = true; + msg.append("Null view or unattached view while instrumenting view; "); + } } if (shouldThrow) { throw new IllegalArgumentException(msg.toString()); } } + + /** + * @return true if only instrumenting surface, false otherwise + */ + public boolean isSurfaceOnly() { + return mSurfaceOnly; + } + + /** + * @return the surafce control which is instrumenting + */ + public SurfaceControl getSurfaceControl() { + return mSurfaceControl; + } + + View getView() { + return mView; + } + + Context getContext() { + return mContext; + } } /** @@ -715,8 +899,8 @@ public class InteractionJankMonitor { @CujType private final int mCujType; private final long mTimeStamp; - @FrameTracker.Reasons - private int mReason = FrameTracker.REASON_END_UNKNOWN; + @Reasons + private int mReason = REASON_END_UNKNOWN; private final boolean mShouldNotify; private final String mName; @@ -756,15 +940,15 @@ public class InteractionJankMonitor { return mTimeStamp; } - public void setReason(@FrameTracker.Reasons int reason) { + public void setReason(@Reasons int reason) { mReason = reason; } - public int getReason() { + public @Reasons int getReason() { return mReason; } - /** Determine if should notify the receivers of cuj events */ + /** Determines if should notify the receivers of cuj events */ public boolean shouldNotify() { return mShouldNotify; } diff --git a/core/java/com/android/internal/notification/NotificationAccessConfirmationActivityContract.java b/core/java/com/android/internal/notification/NotificationAccessConfirmationActivityContract.java index 4ce6f609ef73..3eb980465214 100644 --- a/core/java/com/android/internal/notification/NotificationAccessConfirmationActivityContract.java +++ b/core/java/com/android/internal/notification/NotificationAccessConfirmationActivityContract.java @@ -17,19 +17,27 @@ package com.android.internal.notification; import android.content.ComponentName; +import android.content.Context; import android.content.Intent; +import com.android.internal.R; + +/** + * This class provides methods to create intents for NotificationAccessConfirmationActivity. + */ public final class NotificationAccessConfirmationActivityContract { - private static final ComponentName COMPONENT_NAME = new ComponentName( - "com.android.settings", - "com.android.settings.notification.NotificationAccessConfirmationActivity"); public static final String EXTRA_USER_ID = "user_id"; public static final String EXTRA_COMPONENT_NAME = "component_name"; public static final String EXTRA_PACKAGE_TITLE = "package_title"; - public static Intent launcherIntent(int userId, ComponentName component, String packageTitle) { + /** + * Creates a launcher intent for NotificationAccessConfirmationActivity. + */ + public static Intent launcherIntent(Context context, int userId, ComponentName component, + String packageTitle) { return new Intent() - .setComponent(COMPONENT_NAME) + .setComponent(ComponentName.unflattenFromString(context.getString( + R.string.config_notificationAccessConfirmationActivity))) .putExtra(EXTRA_USER_ID, userId) .putExtra(EXTRA_COMPONENT_NAME, component) .putExtra(EXTRA_PACKAGE_TITLE, packageTitle); diff --git a/core/java/com/android/internal/os/AmbientDisplayPowerCalculator.java b/core/java/com/android/internal/os/AmbientDisplayPowerCalculator.java index 0307268a28b5..94430704468f 100644 --- a/core/java/com/android/internal/os/AmbientDisplayPowerCalculator.java +++ b/core/java/com/android/internal/os/AmbientDisplayPowerCalculator.java @@ -16,6 +16,8 @@ package com.android.internal.os; +import static com.android.internal.os.PowerProfile.POWER_GROUP_DISPLAY_AMBIENT; + import android.os.BatteryConsumer; import android.os.BatteryStats; import android.os.BatteryUsageStats; @@ -29,11 +31,15 @@ import java.util.List; * Estimates power consumed by the ambient display */ public class AmbientDisplayPowerCalculator extends PowerCalculator { - private final UsageBasedPowerEstimator mPowerEstimator; + private final UsageBasedPowerEstimator[] mPowerEstimators; public AmbientDisplayPowerCalculator(PowerProfile powerProfile) { - mPowerEstimator = new UsageBasedPowerEstimator( - powerProfile.getAveragePower(PowerProfile.POWER_AMBIENT_DISPLAY)); + final int numDisplays = powerProfile.getNumDisplays(); + mPowerEstimators = new UsageBasedPowerEstimator[numDisplays]; + for (int display = 0; display < numDisplays; display++) { + mPowerEstimators[display] = new UsageBasedPowerEstimator( + powerProfile.getAveragePowerForOrdinal(POWER_GROUP_DISPLAY_AMBIENT, display)); + } } /** @@ -47,8 +53,8 @@ public class AmbientDisplayPowerCalculator extends PowerCalculator { final int powerModel = getPowerModel(measuredEnergyUC, query); final long durationMs = calculateDuration(batteryStats, rawRealtimeUs, BatteryStats.STATS_SINCE_CHARGED); - final double powerMah = getMeasuredOrEstimatedPower(powerModel, - measuredEnergyUC, mPowerEstimator, durationMs); + final double powerMah = calculateTotalPower(powerModel, batteryStats, rawRealtimeUs, + measuredEnergyUC); builder.getAggregateBatteryConsumerBuilder( BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE) .setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_AMBIENT_DISPLAY, durationMs) @@ -68,9 +74,8 @@ public class AmbientDisplayPowerCalculator extends PowerCalculator { final long measuredEnergyUC = batteryStats.getScreenDozeMeasuredBatteryConsumptionUC(); final long durationMs = calculateDuration(batteryStats, rawRealtimeUs, statsType); final int powerModel = getPowerModel(measuredEnergyUC); - final double powerMah = getMeasuredOrEstimatedPower(powerModel, - batteryStats.getScreenDozeMeasuredBatteryConsumptionUC(), - mPowerEstimator, durationMs); + final double powerMah = calculateTotalPower(powerModel, batteryStats, rawRealtimeUs, + measuredEnergyUC); if (powerMah > 0) { BatterySipper bs = new BatterySipper(BatterySipper.DrainType.AMBIENT_DISPLAY, null, 0); bs.usagePowerMah = powerMah; @@ -83,4 +88,26 @@ public class AmbientDisplayPowerCalculator extends PowerCalculator { private long calculateDuration(BatteryStats batteryStats, long rawRealtimeUs, int statsType) { return batteryStats.getScreenDozeTime(rawRealtimeUs, statsType) / 1000; } + + private double calculateTotalPower(@BatteryConsumer.PowerModel int powerModel, + BatteryStats batteryStats, long rawRealtimeUs, long consumptionUC) { + switch (powerModel) { + case BatteryConsumer.POWER_MODEL_MEASURED_ENERGY: + return uCtoMah(consumptionUC); + case BatteryConsumer.POWER_MODEL_POWER_PROFILE: + default: + return calculateEstimatedPower(batteryStats, rawRealtimeUs); + } + } + + private double calculateEstimatedPower(BatteryStats batteryStats, long rawRealtimeUs) { + final int numDisplays = mPowerEstimators.length; + double power = 0; + for (int display = 0; display < numDisplays; display++) { + final long dozeTime = batteryStats.getDisplayScreenDozeTime(display, rawRealtimeUs) + / 1000; + power += mPowerEstimators[display].calculatePower(dozeTime); + } + return power; + } } diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java index a817119a735f..169eff009bff 100644 --- a/core/java/com/android/internal/os/BatteryStatsImpl.java +++ b/core/java/com/android/internal/os/BatteryStatsImpl.java @@ -690,7 +690,7 @@ public class BatteryStatsImpl extends BatteryStats { * Schedule a sync because of a screen state change. */ Future scheduleSyncDueToScreenStateChange(int flags, boolean onBattery, - boolean onBatteryScreenOff, int screenState); + boolean onBatteryScreenOff, int screenState, int[] perDisplayScreenStates); Future scheduleCpuSyncDueToWakelockChange(long delayMillis); void cancelCpuSyncDueToWakelockChange(); Future scheduleSyncDueToBatteryLevelChange(long delayMillis); @@ -851,17 +851,91 @@ public class BatteryStatsImpl extends BatteryStats { public boolean mRecordAllHistory; boolean mNoAutoReset; + /** + * Overall screen state. For multidisplay devices, this represents the current highest screen + * state of the displays. + */ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) protected int mScreenState = Display.STATE_UNKNOWN; + /** + * Overall screen on timer. For multidisplay devices, this represents the time spent with at + * least one display in the screen on state. + */ StopwatchTimer mScreenOnTimer; + /** + * Overall screen doze timer. For multidisplay devices, this represents the time spent with + * screen doze being the highest screen state. + */ StopwatchTimer mScreenDozeTimer; - + /** + * Overall screen brightness bin. For multidisplay devices, this represents the current + * brightest screen. + */ int mScreenBrightnessBin = -1; + /** + * Overall screen brightness timers. For multidisplay devices, the {@link mScreenBrightnessBin} + * timer will be active at any given time + */ final StopwatchTimer[] mScreenBrightnessTimer = new StopwatchTimer[NUM_SCREEN_BRIGHTNESS_BINS]; boolean mPretendScreenOff; + private static class DisplayBatteryStats { + /** + * Per display screen state. + */ + public int screenState = Display.STATE_UNKNOWN; + /** + * Per display screen on timers. + */ + public StopwatchTimer screenOnTimer; + /** + * Per display screen doze timers. + */ + public StopwatchTimer screenDozeTimer; + /** + * Per display screen brightness bins. + */ + public int screenBrightnessBin = -1; + /** + * Per display screen brightness timers. + */ + public StopwatchTimer[] screenBrightnessTimers = + new StopwatchTimer[NUM_SCREEN_BRIGHTNESS_BINS]; + /** + * Per display screen state the last time {@link #updateDisplayMeasuredEnergyStatsLocked} + * was called. + */ + public int screenStateAtLastEnergyMeasurement = Display.STATE_UNKNOWN; + + DisplayBatteryStats(Clocks clocks, TimeBase timeBase) { + screenOnTimer = new StopwatchTimer(clocks, null, -1, null, + timeBase); + screenDozeTimer = new StopwatchTimer(clocks, null, -1, null, + timeBase); + for (int i = 0; i < NUM_SCREEN_BRIGHTNESS_BINS; i++) { + screenBrightnessTimers[i] = new StopwatchTimer(clocks, null, -100 - i, null, + timeBase); + } + } + + /** + * Reset display timers. + */ + public void reset(long elapsedRealtimeUs) { + screenOnTimer.reset(false, elapsedRealtimeUs); + screenDozeTimer.reset(false, elapsedRealtimeUs); + for (int i = 0; i < NUM_SCREEN_BRIGHTNESS_BINS; i++) { + screenBrightnessTimers[i].reset(false, elapsedRealtimeUs); + } + } + } + + DisplayBatteryStats[] mPerDisplayBatteryStats; + + private int mDisplayMismatchWtfCount = 0; + boolean mInteractive; StopwatchTimer mInteractiveTimer; @@ -1006,8 +1080,6 @@ public class BatteryStatsImpl extends BatteryStats { @GuardedBy("this") @VisibleForTesting protected @Nullable MeasuredEnergyStats mGlobalMeasuredEnergyStats; - /** Last known screen state. Needed for apportioning display energy. */ - int mScreenStateAtLastEnergyMeasurement = Display.STATE_UNKNOWN; /** Bluetooth Power calculator for attributing measured bluetooth charge consumption to uids */ @Nullable BluetoothPowerCalculator mBluetoothPowerCalculator = null; /** Cpu Power calculator for attributing measured cpu charge consumption to uids */ @@ -4308,8 +4380,10 @@ public class BatteryStatsImpl extends BatteryStats { public void setPretendScreenOff(boolean pretendScreenOff) { if (mPretendScreenOff != pretendScreenOff) { mPretendScreenOff = pretendScreenOff; - noteScreenStateLocked(pretendScreenOff ? Display.STATE_OFF : Display.STATE_ON, - mClocks.elapsedRealtime(), mClocks.uptimeMillis(), mClocks.currentTimeMillis()); + final int primaryScreenState = mPerDisplayBatteryStats[0].screenState; + noteScreenStateLocked(0, primaryScreenState, + mClocks.elapsedRealtime(), mClocks.uptimeMillis(), + mClocks.currentTimeMillis()); } } @@ -4907,29 +4981,158 @@ public class BatteryStatsImpl extends BatteryStats { } @GuardedBy("this") - public void noteScreenStateLocked(int state) { - noteScreenStateLocked(state, mClocks.elapsedRealtime(), mClocks.uptimeMillis(), + public void noteScreenStateLocked(int display, int state) { + noteScreenStateLocked(display, state, mClocks.elapsedRealtime(), mClocks.uptimeMillis(), mClocks.currentTimeMillis()); } @GuardedBy("this") - public void noteScreenStateLocked(int state, + public void noteScreenStateLocked(int display, int displayState, long elapsedRealtimeMs, long uptimeMs, long currentTimeMs) { - state = mPretendScreenOff ? Display.STATE_OFF : state; - // Battery stats relies on there being 4 states. To accommodate this, new states beyond the // original 4 are mapped to one of the originals. - if (state > MAX_TRACKED_SCREEN_STATE) { - switch (state) { - case Display.STATE_VR: - state = Display.STATE_ON; + if (displayState > MAX_TRACKED_SCREEN_STATE) { + if (Display.isOnState(displayState)) { + displayState = Display.STATE_ON; + } else if (Display.isDozeState(displayState)) { + if (Display.isSuspendedState(displayState)) { + displayState = Display.STATE_DOZE_SUSPEND; + } else { + displayState = Display.STATE_DOZE; + } + } else if (Display.isOffState(displayState)) { + displayState = Display.STATE_OFF; + } else { + Slog.wtf(TAG, "Unknown screen state (not mapped): " + displayState); + displayState = Display.STATE_UNKNOWN; + } + } + // As of this point, displayState should be mapped to one of: + // - Display.STATE_ON, + // - Display.STATE_DOZE + // - Display.STATE_DOZE_SUSPEND + // - Display.STATE_OFF + // - Display.STATE_UNKNOWN + + int state; + int overallBin = mScreenBrightnessBin; + int externalUpdateFlag = 0; + boolean shouldScheduleSync = false; + final int numDisplay = mPerDisplayBatteryStats.length; + if (display < 0 || display >= numDisplay) { + Slog.wtf(TAG, "Unexpected note screen state for display " + display + " (only " + + mPerDisplayBatteryStats.length + " displays exist...)"); + return; + } + final DisplayBatteryStats displayStats = mPerDisplayBatteryStats[display]; + final int oldDisplayState = displayStats.screenState; + + if (oldDisplayState == displayState) { + // Nothing changed + state = mScreenState; + } else { + displayStats.screenState = displayState; + + // Stop timer for previous display state. + switch (oldDisplayState) { + case Display.STATE_ON: + displayStats.screenOnTimer.stopRunningLocked(elapsedRealtimeMs); + final int bin = displayStats.screenBrightnessBin; + if (bin >= 0) { + displayStats.screenBrightnessTimers[bin].stopRunningLocked( + elapsedRealtimeMs); + } + overallBin = evaluateOverallScreenBrightnessBinLocked(); + shouldScheduleSync = true; + break; + case Display.STATE_DOZE: + // Transition from doze to doze suspend can be ignored. + if (displayState == Display.STATE_DOZE_SUSPEND) break; + displayStats.screenDozeTimer.stopRunningLocked(elapsedRealtimeMs); + shouldScheduleSync = true; + break; + case Display.STATE_DOZE_SUSPEND: + // Transition from doze suspend to doze can be ignored. + if (displayState == Display.STATE_DOZE) break; + displayStats.screenDozeTimer.stopRunningLocked(elapsedRealtimeMs); + shouldScheduleSync = true; + break; + case Display.STATE_OFF: // fallthrough + case Display.STATE_UNKNOWN: + // Not tracked by timers. break; default: - Slog.wtf(TAG, "Unknown screen state (not mapped): " + state); + Slog.wtf(TAG, + "Attempted to stop timer for unexpected display state " + display); + } + + // Start timer for new display state. + switch (displayState) { + case Display.STATE_ON: + displayStats.screenOnTimer.startRunningLocked(elapsedRealtimeMs); + final int bin = displayStats.screenBrightnessBin; + if (bin >= 0) { + displayStats.screenBrightnessTimers[bin].startRunningLocked( + elapsedRealtimeMs); + } + overallBin = evaluateOverallScreenBrightnessBinLocked(); + shouldScheduleSync = true; + break; + case Display.STATE_DOZE: + // Transition from doze suspend to doze can be ignored. + if (oldDisplayState == Display.STATE_DOZE_SUSPEND) break; + displayStats.screenDozeTimer.startRunningLocked(elapsedRealtimeMs); + shouldScheduleSync = true; break; + case Display.STATE_DOZE_SUSPEND: + // Transition from doze to doze suspend can be ignored. + if (oldDisplayState == Display.STATE_DOZE) break; + displayStats.screenDozeTimer.startRunningLocked(elapsedRealtimeMs); + shouldScheduleSync = true; + break; + case Display.STATE_OFF: // fallthrough + case Display.STATE_UNKNOWN: + // Not tracked by timers. + break; + default: + Slog.wtf(TAG, + "Attempted to start timer for unexpected display state " + displayState + + " for display " + display); + } + + if (shouldScheduleSync + && mGlobalMeasuredEnergyStats != null + && mGlobalMeasuredEnergyStats.isStandardBucketSupported( + MeasuredEnergyStats.POWER_BUCKET_SCREEN_ON)) { + // Display measured energy stats is available. Prepare to schedule an + // external sync. + externalUpdateFlag |= ExternalStatsSync.UPDATE_DISPLAY; + } + + // Reevaluate most important display screen state. + state = Display.STATE_UNKNOWN; + for (int i = 0; i < numDisplay; i++) { + final int tempState = mPerDisplayBatteryStats[i].screenState; + if (tempState == Display.STATE_ON + || state == Display.STATE_ON) { + state = Display.STATE_ON; + } else if (tempState == Display.STATE_DOZE + || state == Display.STATE_DOZE) { + state = Display.STATE_DOZE; + } else if (tempState == Display.STATE_DOZE_SUSPEND + || state == Display.STATE_DOZE_SUSPEND) { + state = Display.STATE_DOZE_SUSPEND; + } else if (tempState == Display.STATE_OFF + || state == Display.STATE_OFF) { + state = Display.STATE_OFF; + } } } + final boolean batteryRunning = mOnBatteryTimeBase.isRunning(); + final boolean batteryScreenOffRunning = mOnBatteryScreenOffTimeBase.isRunning(); + + state = mPretendScreenOff ? Display.STATE_OFF : state; if (mScreenState != state) { recordDailyStatsIfNeededLocked(true, currentTimeMs); final int oldState = mScreenState; @@ -4983,11 +5186,11 @@ public class BatteryStatsImpl extends BatteryStats { + Display.stateToString(state)); addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); } - // TODO: (Probably overkill) Have mGlobalMeasuredEnergyStats store supported flags and - // only update DISPLAY if it is. Currently overkill since CPU is scheduled anyway. - final int updateFlag = ExternalStatsSync.UPDATE_CPU | ExternalStatsSync.UPDATE_DISPLAY; - mExternalSync.scheduleSyncDueToScreenStateChange(updateFlag, - mOnBatteryTimeBase.isRunning(), mOnBatteryScreenOffTimeBase.isRunning(), state); + + // Per screen state Cpu stats needed. Prepare to schedule an external sync. + externalUpdateFlag |= ExternalStatsSync.UPDATE_CPU; + shouldScheduleSync = true; + if (Display.isOnState(state)) { updateTimeBasesLocked(mOnBatteryTimeBase.isRunning(), state, uptimeMs * 1000, elapsedRealtimeMs * 1000); @@ -5005,33 +5208,116 @@ public class BatteryStatsImpl extends BatteryStats { updateDischargeScreenLevelsLocked(oldState, state); } } + + // Changing display states might have changed the screen used to determine the overall + // brightness. + maybeUpdateOverallScreenBrightness(overallBin, elapsedRealtimeMs, uptimeMs); + + if (shouldScheduleSync) { + final int numDisplays = mPerDisplayBatteryStats.length; + final int[] displayStates = new int[numDisplays]; + for (int i = 0; i < numDisplays; i++) { + displayStates[i] = mPerDisplayBatteryStats[i].screenState; + } + mExternalSync.scheduleSyncDueToScreenStateChange(externalUpdateFlag, + batteryRunning, batteryScreenOffRunning, state, displayStates); + } } @UnsupportedAppUsage public void noteScreenBrightnessLocked(int brightness) { - noteScreenBrightnessLocked(brightness, mClocks.elapsedRealtime(), mClocks.uptimeMillis()); + noteScreenBrightnessLocked(0, brightness); + } + + /** + * Note screen brightness change for a display. + */ + public void noteScreenBrightnessLocked(int display, int brightness) { + noteScreenBrightnessLocked(display, brightness, mClocks.elapsedRealtime(), + mClocks.uptimeMillis()); } - public void noteScreenBrightnessLocked(int brightness, long elapsedRealtimeMs, long uptimeMs) { + + /** + * Note screen brightness change for a display. + */ + public void noteScreenBrightnessLocked(int display, int brightness, long elapsedRealtimeMs, + long uptimeMs) { // Bin the brightness. int bin = brightness / (256/NUM_SCREEN_BRIGHTNESS_BINS); if (bin < 0) bin = 0; else if (bin >= NUM_SCREEN_BRIGHTNESS_BINS) bin = NUM_SCREEN_BRIGHTNESS_BINS-1; - if (mScreenBrightnessBin != bin) { - mHistoryCur.states = (mHistoryCur.states&~HistoryItem.STATE_BRIGHTNESS_MASK) - | (bin << HistoryItem.STATE_BRIGHTNESS_SHIFT); - if (DEBUG_HISTORY) Slog.v(TAG, "Screen brightness " + bin + " to: " - + Integer.toHexString(mHistoryCur.states)); - addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); + + final int overallBin; + + final int numDisplays = mPerDisplayBatteryStats.length; + if (display < 0 || display >= numDisplays) { + Slog.wtf(TAG, "Unexpected note screen brightness for display " + display + " (only " + + mPerDisplayBatteryStats.length + " displays exist...)"); + return; + } + + final DisplayBatteryStats displayStats = mPerDisplayBatteryStats[display]; + final int oldBin = displayStats.screenBrightnessBin; + if (oldBin == bin) { + // Nothing changed + overallBin = mScreenBrightnessBin; + } else { + displayStats.screenBrightnessBin = bin; + if (displayStats.screenState == Display.STATE_ON) { + if (oldBin >= 0) { + displayStats.screenBrightnessTimers[oldBin].stopRunningLocked( + elapsedRealtimeMs); + } + displayStats.screenBrightnessTimers[bin].startRunningLocked( + elapsedRealtimeMs); + } + overallBin = evaluateOverallScreenBrightnessBinLocked(); + } + + maybeUpdateOverallScreenBrightness(overallBin, elapsedRealtimeMs, uptimeMs); + } + + private int evaluateOverallScreenBrightnessBinLocked() { + int overallBin = -1; + final int numDisplays = getDisplayCount(); + for (int display = 0; display < numDisplays; display++) { + final int displayBrightnessBin; + if (mPerDisplayBatteryStats[display].screenState == Display.STATE_ON) { + displayBrightnessBin = mPerDisplayBatteryStats[display].screenBrightnessBin; + } else { + displayBrightnessBin = -1; + } + if (displayBrightnessBin > overallBin) { + overallBin = displayBrightnessBin; + } + } + return overallBin; + } + + private void maybeUpdateOverallScreenBrightness(int overallBin, long elapsedRealtimeMs, + long uptimeMs) { + if (mScreenBrightnessBin != overallBin) { + if (overallBin >= 0) { + mHistoryCur.states = (mHistoryCur.states & ~HistoryItem.STATE_BRIGHTNESS_MASK) + | (overallBin << HistoryItem.STATE_BRIGHTNESS_SHIFT); + if (DEBUG_HISTORY) { + Slog.v(TAG, "Screen brightness " + overallBin + " to: " + + Integer.toHexString(mHistoryCur.states)); + } + addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); + } if (mScreenState == Display.STATE_ON) { if (mScreenBrightnessBin >= 0) { mScreenBrightnessTimer[mScreenBrightnessBin] .stopRunningLocked(elapsedRealtimeMs); } - mScreenBrightnessTimer[bin] - .startRunningLocked(elapsedRealtimeMs); + if (overallBin >= 0) { + mScreenBrightnessTimer[overallBin] + .startRunningLocked(elapsedRealtimeMs); + } } - mScreenBrightnessBin = bin; + mScreenBrightnessBin = overallBin; } } @@ -6693,6 +6979,31 @@ public class BatteryStatsImpl extends BatteryStats { return mScreenBrightnessTimer[brightnessBin]; } + @Override + public int getDisplayCount() { + return mPerDisplayBatteryStats.length; + } + + @Override + public long getDisplayScreenOnTime(int display, long elapsedRealtimeUs) { + return mPerDisplayBatteryStats[display].screenOnTimer.getTotalTimeLocked(elapsedRealtimeUs, + STATS_SINCE_CHARGED); + } + + @Override + public long getDisplayScreenDozeTime(int display, long elapsedRealtimeUs) { + return mPerDisplayBatteryStats[display].screenDozeTimer.getTotalTimeLocked( + elapsedRealtimeUs, STATS_SINCE_CHARGED); + } + + @Override + public long getDisplayScreenBrightnessTime(int display, int brightnessBin, + long elapsedRealtimeUs) { + final DisplayBatteryStats displayStats = mPerDisplayBatteryStats[display]; + return displayStats.screenBrightnessTimers[brightnessBin].getTotalTimeLocked( + elapsedRealtimeUs, STATS_SINCE_CHARGED); + } + @Override public long getInteractiveTime(long elapsedRealtimeUs, int which) { return mInteractiveTimer.getTotalTimeLocked(elapsedRealtimeUs, which); } @@ -10694,6 +11005,10 @@ public class BatteryStatsImpl extends BatteryStats { mScreenBrightnessTimer[i] = new StopwatchTimer(mClocks, null, -100-i, null, mOnBatteryTimeBase); } + + mPerDisplayBatteryStats = new DisplayBatteryStats[1]; + mPerDisplayBatteryStats[0] = new DisplayBatteryStats(mClocks, mOnBatteryTimeBase); + mInteractiveTimer = new StopwatchTimer(mClocks, null, -10, null, mOnBatteryTimeBase); mPowerSaveModeEnabledTimer = new StopwatchTimer(mClocks, null, -2, null, mOnBatteryTimeBase); @@ -10806,6 +11121,8 @@ public class BatteryStatsImpl extends BatteryStats { // Initialize the estimated battery capacity to a known preset one. mEstimatedBatteryCapacityMah = (int) mPowerProfile.getBatteryCapacity(); } + + setDisplayCountLocked(mPowerProfile.getNumDisplays()); } PowerProfile getPowerProfile() { @@ -10838,6 +11155,16 @@ public class BatteryStatsImpl extends BatteryStats { mExternalSync = sync; } + /** + * Initialize and set multi display timers and states. + */ + public void setDisplayCountLocked(int numDisplays) { + mPerDisplayBatteryStats = new DisplayBatteryStats[numDisplays]; + for (int i = 0; i < numDisplays; i++) { + mPerDisplayBatteryStats[i] = new DisplayBatteryStats(mClocks, mOnBatteryTimeBase); + } + } + public void updateDailyDeadlineLocked() { // Get the current time. long currentTimeMs = mDailyStartTimeMs = mClocks.currentTimeMillis(); @@ -11314,6 +11641,11 @@ public class BatteryStatsImpl extends BatteryStats { mScreenBrightnessTimer[i].reset(false, elapsedRealtimeUs); } + final int numDisplays = mPerDisplayBatteryStats.length; + for (int i = 0; i < numDisplays; i++) { + mPerDisplayBatteryStats[i].reset(elapsedRealtimeUs); + } + if (mPowerProfile != null) { mEstimatedBatteryCapacityMah = (int) mPowerProfile.getBatteryCapacity(); } else { @@ -12597,22 +12929,43 @@ public class BatteryStatsImpl extends BatteryStats { * is always 0 when the screen is not "ON" and whenever the rail energy is 0 (if supported). * To the extent that those assumptions are violated, the algorithm will err. * - * @param chargeUC amount of charge (microcoulombs) used by Display since this was last called. - * @param screenState screen state at the time this data collection was scheduled + * @param chargesUC amount of charge (microcoulombs) used by each Display since this was last + * called. + * @param screenStates each screen state at the time this data collection was scheduled */ @GuardedBy("this") - public void updateDisplayMeasuredEnergyStatsLocked(long chargeUC, int screenState, + public void updateDisplayMeasuredEnergyStatsLocked(long[] chargesUC, int[] screenStates, long elapsedRealtimeMs) { - if (DEBUG_ENERGY) Slog.d(TAG, "Updating display stats: " + chargeUC); + if (DEBUG_ENERGY) Slog.d(TAG, "Updating display stats: " + Arrays.toString(chargesUC)); if (mGlobalMeasuredEnergyStats == null) { return; } - final @StandardPowerBucket int powerBucket = - MeasuredEnergyStats.getDisplayPowerBucket(mScreenStateAtLastEnergyMeasurement); - mScreenStateAtLastEnergyMeasurement = screenState; + final int numDisplays; + if (mPerDisplayBatteryStats.length == screenStates.length) { + numDisplays = screenStates.length; + } else { + // if this point is reached, it will be reached every display state change. + // Rate limit the wtf logging to once every 100 display updates. + if (mDisplayMismatchWtfCount++ % 100 == 0) { + Slog.wtf(TAG, "Mismatch between PowerProfile reported display count (" + + mPerDisplayBatteryStats.length + + ") and PowerStatsHal reported display count (" + screenStates.length + + ")"); + } + // Keep the show going, use the shorter of the two. + numDisplays = mPerDisplayBatteryStats.length < screenStates.length + ? mPerDisplayBatteryStats.length : screenStates.length; + } - if (!mOnBatteryInternal || chargeUC <= 0) { + final int[] oldScreenStates = new int[numDisplays]; + for (int i = 0; i < numDisplays; i++) { + final int screenState = screenStates[i]; + oldScreenStates[i] = mPerDisplayBatteryStats[i].screenStateAtLastEnergyMeasurement; + mPerDisplayBatteryStats[i].screenStateAtLastEnergyMeasurement = screenState; + } + + if (!mOnBatteryInternal) { // There's nothing further to update. return; } @@ -12627,17 +12980,31 @@ public class BatteryStatsImpl extends BatteryStats { return; } - mGlobalMeasuredEnergyStats.updateStandardBucket(powerBucket, chargeUC); + long totalScreenOnChargeUC = 0; + for (int i = 0; i < numDisplays; i++) { + final long chargeUC = chargesUC[i]; + if (chargeUC <= 0) { + // There's nothing further to update. + continue; + } + + final @StandardPowerBucket int powerBucket = + MeasuredEnergyStats.getDisplayPowerBucket(oldScreenStates[i]); + mGlobalMeasuredEnergyStats.updateStandardBucket(powerBucket, chargeUC); + if (powerBucket == MeasuredEnergyStats.POWER_BUCKET_SCREEN_ON) { + totalScreenOnChargeUC += chargeUC; + } + } // Now we blame individual apps, but only if the display was ON. - if (powerBucket != MeasuredEnergyStats.POWER_BUCKET_SCREEN_ON) { + if (totalScreenOnChargeUC <= 0) { return; } // TODO(b/175726779): Consider unifying the code with the non-rail display power blaming. // NOTE: fg time is NOT pooled. If two uids are both somehow in fg, then that time is // 'double counted' and will simply exceed the realtime that elapsed. - // If multidisplay becomes a reality, this is probably more reasonable than pooling. + // TODO(b/175726779): collect per display uid visibility for display power attribution. // Collect total time since mark so that we can normalize power. final SparseDoubleArray fgTimeUsArray = new SparseDoubleArray(); @@ -12650,7 +13017,8 @@ public class BatteryStatsImpl extends BatteryStats { if (fgTimeUs == 0) continue; fgTimeUsArray.put(uid.getUid(), (double) fgTimeUs); } - distributeEnergyToUidsLocked(powerBucket, chargeUC, fgTimeUsArray, 0); + distributeEnergyToUidsLocked(MeasuredEnergyStats.POWER_BUCKET_SCREEN_ON, + totalScreenOnChargeUC, fgTimeUsArray, 0); } /** @@ -14556,7 +14924,12 @@ public class BatteryStatsImpl extends BatteryStats { public void initMeasuredEnergyStatsLocked(@Nullable boolean[] supportedStandardBuckets, String[] customBucketNames) { boolean supportedBucketMismatch = false; - mScreenStateAtLastEnergyMeasurement = mScreenState; + + final int numDisplays = mPerDisplayBatteryStats.length; + for (int i = 0; i < numDisplays; i++) { + final int screenState = mPerDisplayBatteryStats[i].screenState; + mPerDisplayBatteryStats[i].screenStateAtLastEnergyMeasurement = screenState; + } if (supportedStandardBuckets == null) { if (mGlobalMeasuredEnergyStats != null) { diff --git a/core/java/com/android/internal/os/PowerCalculator.java b/core/java/com/android/internal/os/PowerCalculator.java index 4979ecbae8cb..93d562c571f8 100644 --- a/core/java/com/android/internal/os/PowerCalculator.java +++ b/core/java/com/android/internal/os/PowerCalculator.java @@ -132,32 +132,6 @@ public abstract class PowerCalculator { : BatteryConsumer.POWER_MODEL_POWER_PROFILE; } - /** - * Returns either the measured energy converted to mAh or a usage-based estimate. - */ - protected static double getMeasuredOrEstimatedPower(@BatteryConsumer.PowerModel int powerModel, - long measuredEnergyUC, UsageBasedPowerEstimator powerEstimator, long durationMs) { - switch (powerModel) { - case BatteryConsumer.POWER_MODEL_MEASURED_ENERGY: - return uCtoMah(measuredEnergyUC); - case BatteryConsumer.POWER_MODEL_POWER_PROFILE: - default: - return powerEstimator.calculatePower(durationMs); - } - } - - /** - * Returns either the measured energy converted to mAh or a usage-based estimate. - */ - protected static double getMeasuredOrEstimatedPower( - long measuredEnergyUC, UsageBasedPowerEstimator powerEstimator, long durationMs) { - if (measuredEnergyUC != BatteryStats.POWER_DATA_UNAVAILABLE) { - return uCtoMah(measuredEnergyUC); - } else { - return powerEstimator.calculatePower(durationMs); - } - } - /** * Prints formatted amount of power in milli-amp-hours. */ diff --git a/core/java/com/android/internal/os/PowerProfile.java b/core/java/com/android/internal/os/PowerProfile.java index add2304afe9d..4d19b35b1e16 100644 --- a/core/java/com/android/internal/os/PowerProfile.java +++ b/core/java/com/android/internal/os/PowerProfile.java @@ -17,10 +17,12 @@ package com.android.internal.os; +import android.annotation.StringDef; import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.Resources; import android.content.res.XmlResourceParser; +import android.util.Slog; import android.util.proto.ProtoOutputStream; import com.android.internal.annotations.VisibleForTesting; @@ -30,6 +32,8 @@ import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import java.io.IOException; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.HashMap; @@ -40,6 +44,8 @@ import java.util.HashMap; */ public class PowerProfile { + public static final String TAG = "PowerProfile"; + /* * POWER_CPU_SUSPEND: Power consumption when CPU is in power collapse mode. * POWER_CPU_IDLE: Power consumption when CPU is awake (when a wake lock is held). This should @@ -145,12 +151,18 @@ public class PowerProfile { /** * Power consumption when screen is in doze/ambient/always-on mode, including backlight power. + * + * @deprecated Use {@link #POWER_GROUP_DISPLAY_AMBIENT} instead. */ + @Deprecated public static final String POWER_AMBIENT_DISPLAY = "ambient.on"; /** * Power consumption when screen is on, not including the backlight power. + * + * @deprecated Use {@link #POWER_GROUP_DISPLAY_SCREEN_ON} instead. */ + @Deprecated @UnsupportedAppUsage public static final String POWER_SCREEN_ON = "screen.on"; @@ -175,7 +187,10 @@ public class PowerProfile { /** * Power consumption at full backlight brightness. If the backlight is at * 50% brightness, then this should be multiplied by 0.5 + * + * @deprecated Use {@link #POWER_GROUP_DISPLAY_SCREEN_FULL} instead. */ + @Deprecated @UnsupportedAppUsage public static final String POWER_SCREEN_FULL = "screen.full"; @@ -220,6 +235,29 @@ public class PowerProfile { */ public static final String POWER_BATTERY_CAPACITY = "battery.capacity"; + /** + * Power consumption when a screen is in doze/ambient/always-on mode, including backlight power. + */ + public static final String POWER_GROUP_DISPLAY_AMBIENT = "ambient.on.display"; + + /** + * Power consumption when a screen is on, not including the backlight power. + */ + public static final String POWER_GROUP_DISPLAY_SCREEN_ON = "screen.on.display"; + + /** + * Power consumption of a screen at full backlight brightness. + */ + public static final String POWER_GROUP_DISPLAY_SCREEN_FULL = "screen.full.display"; + + @StringDef(prefix = { "POWER_GROUP_" }, value = { + POWER_GROUP_DISPLAY_AMBIENT, + POWER_GROUP_DISPLAY_SCREEN_ON, + POWER_GROUP_DISPLAY_SCREEN_FULL, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface PowerGroup {} + /** * A map from Power Use Item to its power consumption. */ @@ -255,6 +293,7 @@ public class PowerProfile { readPowerValuesFromXml(context, forTest); } initCpuClusters(); + initDisplays(); } } @@ -424,6 +463,58 @@ public class PowerProfile { return 0; } + private int mNumDisplays; + + private void initDisplays() { + // Figure out how many displays are listed in the power profile. + mNumDisplays = 0; + while (!Double.isNaN( + getAveragePowerForOrdinal(POWER_GROUP_DISPLAY_AMBIENT, mNumDisplays, Double.NaN)) + || !Double.isNaN( + getAveragePowerForOrdinal(POWER_GROUP_DISPLAY_SCREEN_ON, mNumDisplays, Double.NaN)) + || !Double.isNaN( + getAveragePowerForOrdinal(POWER_GROUP_DISPLAY_SCREEN_FULL, mNumDisplays, + Double.NaN))) { + mNumDisplays++; + } + + // Handle legacy display power constants. + final Double deprecatedAmbientDisplay = sPowerItemMap.get(POWER_AMBIENT_DISPLAY); + boolean legacy = false; + if (deprecatedAmbientDisplay != null && mNumDisplays == 0) { + final String key = getOrdinalPowerType(POWER_GROUP_DISPLAY_AMBIENT, 0); + Slog.w(TAG, POWER_AMBIENT_DISPLAY + " is deprecated! Use " + key + " instead."); + sPowerItemMap.put(key, deprecatedAmbientDisplay); + legacy = true; + } + + final Double deprecatedScreenOn = sPowerItemMap.get(POWER_SCREEN_ON); + if (deprecatedScreenOn != null && mNumDisplays == 0) { + final String key = getOrdinalPowerType(POWER_GROUP_DISPLAY_SCREEN_ON, 0); + Slog.w(TAG, POWER_SCREEN_ON + " is deprecated! Use " + key + " instead."); + sPowerItemMap.put(key, deprecatedScreenOn); + legacy = true; + } + + final Double deprecatedScreenFull = sPowerItemMap.get(POWER_SCREEN_FULL); + if (deprecatedScreenFull != null && mNumDisplays == 0) { + final String key = getOrdinalPowerType(POWER_GROUP_DISPLAY_SCREEN_FULL, 0); + Slog.w(TAG, POWER_SCREEN_FULL + " is deprecated! Use " + key + " instead."); + sPowerItemMap.put(key, deprecatedScreenFull); + legacy = true; + } + if (legacy) { + mNumDisplays = 1; + } + } + + /** + * Returns the number built in displays on the device as defined in the power_profile.xml. + */ + public int getNumDisplays() { + return mNumDisplays; + } + /** * Returns the number of memory bandwidth buckets defined in power_profile.xml, or a * default value if the subsystem has no recorded value. @@ -495,6 +586,32 @@ public class PowerProfile { } } + /** + * Returns the average current in mA consumed by an ordinaled subsystem, or the given + * default value if the subsystem has no recorded value. + * + * @param group the subsystem {@link PowerGroup}. + * @param ordinal which entity in the {@link PowerGroup}. + * @param defaultValue the value to return if the subsystem has no recorded value. + * @return the average current in milliAmps. + */ + public double getAveragePowerForOrdinal(@PowerGroup String group, int ordinal, + double defaultValue) { + final String type = getOrdinalPowerType(group, ordinal); + return getAveragePowerOrDefault(type, defaultValue); + } + + /** + * Returns the average current in mA consumed by an ordinaled subsystem. + * + * @param group the subsystem {@link PowerGroup}. + * @param ordinal which entity in the {@link PowerGroup}. + * @return the average current in milliAmps. + */ + public double getAveragePowerForOrdinal(@PowerGroup String group, int ordinal) { + return getAveragePowerForOrdinal(group, ordinal, 0); + } + /** * Returns the battery capacity, if available, in milli Amp Hours. If not available, * it returns zero. @@ -682,4 +799,9 @@ public class PowerProfile { } } } + + // Creates the key for an ordinaled power constant from the group and ordinal. + private static String getOrdinalPowerType(@PowerGroup String group, int ordinal) { + return group + ordinal; + } } diff --git a/core/java/com/android/internal/os/ScreenPowerCalculator.java b/core/java/com/android/internal/os/ScreenPowerCalculator.java index 1b3bc234fc0f..2b634598bbbc 100644 --- a/core/java/com/android/internal/os/ScreenPowerCalculator.java +++ b/core/java/com/android/internal/os/ScreenPowerCalculator.java @@ -16,6 +16,9 @@ package com.android.internal.os; +import static com.android.internal.os.PowerProfile.POWER_GROUP_DISPLAY_SCREEN_FULL; +import static com.android.internal.os.PowerProfile.POWER_GROUP_DISPLAY_SCREEN_ON; + import android.os.BatteryConsumer; import android.os.BatteryStats; import android.os.BatteryUsageStats; @@ -41,8 +44,8 @@ public class ScreenPowerCalculator extends PowerCalculator { // Minimum amount of time the screen should be on to start smearing drain to apps public static final long MIN_ACTIVE_TIME_FOR_SMEARING = 10 * DateUtils.MINUTE_IN_MILLIS; - private final UsageBasedPowerEstimator mScreenOnPowerEstimator; - private final UsageBasedPowerEstimator mScreenFullPowerEstimator; + private final UsageBasedPowerEstimator[] mScreenOnPowerEstimators; + private final UsageBasedPowerEstimator[] mScreenFullPowerEstimators; private static class PowerAndDuration { public long durationMs; @@ -50,10 +53,16 @@ public class ScreenPowerCalculator extends PowerCalculator { } public ScreenPowerCalculator(PowerProfile powerProfile) { - mScreenOnPowerEstimator = new UsageBasedPowerEstimator( - powerProfile.getAveragePower(PowerProfile.POWER_SCREEN_ON)); - mScreenFullPowerEstimator = new UsageBasedPowerEstimator( - powerProfile.getAveragePower(PowerProfile.POWER_SCREEN_FULL)); + final int numDisplays = powerProfile.getNumDisplays(); + mScreenOnPowerEstimators = new UsageBasedPowerEstimator[numDisplays]; + mScreenFullPowerEstimators = new UsageBasedPowerEstimator[numDisplays]; + for (int display = 0; display < numDisplays; display++) { + mScreenOnPowerEstimators[display] = new UsageBasedPowerEstimator( + powerProfile.getAveragePowerForOrdinal(POWER_GROUP_DISPLAY_SCREEN_ON, display)); + mScreenFullPowerEstimators[display] = new UsageBasedPowerEstimator( + powerProfile.getAveragePowerForOrdinal(POWER_GROUP_DISPLAY_SCREEN_FULL, + display)); + } } @Override @@ -168,7 +177,7 @@ public class ScreenPowerCalculator extends PowerCalculator { case BatteryConsumer.POWER_MODEL_POWER_PROFILE: default: totalPowerAndDuration.powerMah = calculateTotalPowerFromBrightness(batteryStats, - rawRealtimeUs, statsType, totalPowerAndDuration.durationMs); + rawRealtimeUs); } } @@ -190,19 +199,25 @@ public class ScreenPowerCalculator extends PowerCalculator { return batteryStats.getScreenOnTime(rawRealtimeUs, statsType) / 1000; } - private double calculateTotalPowerFromBrightness(BatteryStats batteryStats, long rawRealtimeUs, - int statsType, long durationMs) { - double power = mScreenOnPowerEstimator.calculatePower(durationMs); - for (int i = 0; i < BatteryStats.NUM_SCREEN_BRIGHTNESS_BINS; i++) { - final long brightnessTime = - batteryStats.getScreenBrightnessTime(i, rawRealtimeUs, statsType) / 1000; - final double binPowerMah = mScreenFullPowerEstimator.calculatePower(brightnessTime) - * (i + 0.5f) / BatteryStats.NUM_SCREEN_BRIGHTNESS_BINS; - if (DEBUG && binPowerMah != 0) { - Slog.d(TAG, "Screen bin #" + i + ": time=" + brightnessTime - + " power=" + formatCharge(binPowerMah)); + private double calculateTotalPowerFromBrightness(BatteryStats batteryStats, + long rawRealtimeUs) { + final int numDisplays = mScreenOnPowerEstimators.length; + double power = 0; + for (int display = 0; display < numDisplays; display++) { + final long displayTime = batteryStats.getDisplayScreenOnTime(display, rawRealtimeUs) + / 1000; + power += mScreenOnPowerEstimators[display].calculatePower(displayTime); + for (int bin = 0; bin < BatteryStats.NUM_SCREEN_BRIGHTNESS_BINS; bin++) { + final long brightnessTime = batteryStats.getDisplayScreenBrightnessTime(display, + bin, rawRealtimeUs) / 1000; + final double binPowerMah = mScreenFullPowerEstimators[display].calculatePower( + brightnessTime) * (bin + 0.5f) / BatteryStats.NUM_SCREEN_BRIGHTNESS_BINS; + if (DEBUG && binPowerMah != 0) { + Slog.d(TAG, "Screen bin #" + bin + ": time=" + brightnessTime + + " power=" + formatCharge(binPowerMah)); + } + power += binPowerMah; } - power += binPowerMah; } return power; } diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java index 98e63f7b9fa0..552777430347 100644 --- a/core/java/com/android/internal/os/ZygoteInit.java +++ b/core/java/com/android/internal/os/ZygoteInit.java @@ -789,7 +789,7 @@ public class ZygoteInit { "--setuid=1000", "--setgid=1000", "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1023," - + "1024,1032,1065,3001,3002,3003,3006,3007,3009,3010,3011", + + "1024,1032,1065,3001,3002,3003,3006,3007,3009,3010,3011,3012", "--capabilities=" + capabilities + "," + capabilities, "--nice-name=system_server", "--runtime-args", diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java index 424632fe82eb..6541b14b9070 100644 --- a/core/java/com/android/internal/policy/DecorView.java +++ b/core/java/com/android/internal/policy/DecorView.java @@ -270,8 +270,6 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind private Drawable mCaptionBackgroundDrawable; private Drawable mUserCaptionBackgroundDrawable; - private float mAvailableWidth; - String mLogTag = TAG; private final Rect mFloatingInsets = new Rect(); private boolean mApplyFloatingVerticalInsets = false; @@ -315,8 +313,6 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind mSemiTransparentBarColor = context.getResources().getColor( R.color.system_bar_background_semi_transparent, null /* theme */); - updateAvailableWidth(); - setWindow(window); updateLogTag(params); @@ -697,7 +693,8 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - final DisplayMetrics metrics = getContext().getResources().getDisplayMetrics(); + final Resources res = getContext().getResources(); + final DisplayMetrics metrics = res.getDisplayMetrics(); final boolean isPortrait = getResources().getConfiguration().orientation == ORIENTATION_PORTRAIT; @@ -767,17 +764,19 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind if (!fixedWidth && widthMode == AT_MOST) { final TypedValue tv = isPortrait ? mWindow.mMinWidthMinor : mWindow.mMinWidthMajor; + final float availableWidth = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, + res.getConfiguration().screenWidthDp, metrics); if (tv.type != TypedValue.TYPE_NULL) { final int min; if (tv.type == TypedValue.TYPE_DIMENSION) { - min = (int)tv.getDimension(metrics); + min = (int) tv.getDimension(metrics); } else if (tv.type == TypedValue.TYPE_FRACTION) { - min = (int)tv.getFraction(mAvailableWidth, mAvailableWidth); + min = (int) tv.getFraction(availableWidth, availableWidth); } else { min = 0; } if (DEBUG_MEASURE) Log.d(mLogTag, "Adjust for min width: " + min + ", value::" - + tv.coerceToString() + ", mAvailableWidth=" + mAvailableWidth); + + tv.coerceToString() + ", mAvailableWidth=" + availableWidth); if (width < min) { widthMeasureSpec = MeasureSpec.makeMeasureSpec(min, EXACTLY); @@ -2144,7 +2143,6 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind updateDecorCaptionStatus(newConfig); - updateAvailableWidth(); initializeElevation(); } @@ -2616,12 +2614,6 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind mLogTag = TAG + "[" + getTitleSuffix(params) + "]"; } - private void updateAvailableWidth() { - Resources res = getResources(); - mAvailableWidth = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, - res.getConfiguration().screenWidthDp, res.getDisplayMetrics()); - } - /** * @hide */ diff --git a/core/java/com/android/internal/policy/IKeyguardStateCallback.aidl b/core/java/com/android/internal/policy/IKeyguardStateCallback.aidl index 8e454db4cb04..419b1f8feac7 100644 --- a/core/java/com/android/internal/policy/IKeyguardStateCallback.aidl +++ b/core/java/com/android/internal/policy/IKeyguardStateCallback.aidl @@ -20,5 +20,4 @@ interface IKeyguardStateCallback { void onSimSecureStateChanged(boolean simSecure); void onInputRestrictedStateChanged(boolean inputRestricted); void onTrustedChanged(boolean trusted); - void onHasLockscreenWallpaperChanged(boolean hasLockscreenWallpaper); } \ No newline at end of file diff --git a/core/java/com/android/internal/policy/ScreenDecorationsUtils.java b/core/java/com/android/internal/policy/ScreenDecorationsUtils.java index 52172cf04362..ec6283922807 100644 --- a/core/java/com/android/internal/policy/ScreenDecorationsUtils.java +++ b/core/java/com/android/internal/policy/ScreenDecorationsUtils.java @@ -16,7 +16,9 @@ package com.android.internal.policy; +import android.content.Context; import android.content.res.Resources; +import android.view.RoundedCorners; import com.android.internal.R; @@ -29,23 +31,28 @@ public class ScreenDecorationsUtils { * Corner radius that should be used on windows in order to cover the display. * These values are expressed in pixels because they should not respect display or font * scaling, this means that we don't have to reload them on config changes. + * + * Note that if the context is not an UI context(not associated with Display), it will use + * default display. */ - public static float getWindowCornerRadius(Resources resources) { + public static float getWindowCornerRadius(Context context) { + final Resources resources = context.getResources(); if (!supportsRoundedCornersOnWindows(resources)) { return 0f; } - + // Use Context#getDisplayNoVerify() in case the context is not an UI context. + final String displayUniqueId = context.getDisplayNoVerify().getUniqueId(); // Radius that should be used in case top or bottom aren't defined. - float defaultRadius = resources.getDimension(R.dimen.rounded_corner_radius) - - resources.getDimension(R.dimen.rounded_corner_radius_adjustment); + float defaultRadius = RoundedCorners.getRoundedCornerRadius(resources, displayUniqueId) + - RoundedCorners.getRoundedCornerRadiusAdjustment(resources, displayUniqueId); - float topRadius = resources.getDimension(R.dimen.rounded_corner_radius_top) - - resources.getDimension(R.dimen.rounded_corner_radius_top_adjustment); + float topRadius = RoundedCorners.getRoundedCornerTopRadius(resources, displayUniqueId) + - RoundedCorners.getRoundedCornerRadiusTopAdjustment(resources, displayUniqueId); if (topRadius == 0f) { topRadius = defaultRadius; } - float bottomRadius = resources.getDimension(R.dimen.rounded_corner_radius_bottom) - - resources.getDimension(R.dimen.rounded_corner_radius_bottom_adjustment); + float bottomRadius = RoundedCorners.getRoundedCornerBottomRadius(resources, displayUniqueId) + - RoundedCorners.getRoundedCornerRadiusBottomAdjustment(resources, displayUniqueId); if (bottomRadius == 0f) { bottomRadius = defaultRadius; } diff --git a/core/java/com/android/internal/policy/SystemBarUtils.java b/core/java/com/android/internal/policy/SystemBarUtils.java new file mode 100644 index 000000000000..6bf1333097f7 --- /dev/null +++ b/core/java/com/android/internal/policy/SystemBarUtils.java @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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.policy; + +import android.content.Context; +import android.content.res.Resources; +import android.graphics.Insets; +import android.util.RotationUtils; +import android.view.DisplayCutout; +import android.view.Surface; + +import com.android.internal.R; + +/** + * Utility functions for system bars used by both window manager and System UI. + * + * @hide + */ +public final class SystemBarUtils { + + /** + * Gets the status bar height. + */ + public static int getStatusBarHeight(Context context) { + return getStatusBarHeight(context.getResources(), context.getDisplay().getCutout()); + } + + /** + * Gets the status bar height with a specific display cutout. + */ + public static int getStatusBarHeight(Resources res, DisplayCutout cutout) { + final int defaultSize = res.getDimensionPixelSize(R.dimen.status_bar_height); + final int safeInsetTop = cutout == null ? 0 : cutout.getSafeInsetTop(); + final int waterfallInsetTop = cutout == null ? 0 : cutout.getWaterfallInsets().top; + // The status bar height should be: + // Max(top cutout size, (status bar default height + waterfall top size)) + return Math.max(safeInsetTop, defaultSize + waterfallInsetTop); + } + + /** + * Gets the status bar height for a specific rotation. + */ + public static int getStatusBarHeightForRotation( + Context context, @Surface.Rotation int targetRot) { + final int rotation = context.getDisplay().getRotation(); + final DisplayCutout cutout = context.getDisplay().getCutout(); + + Insets insets = cutout == null ? Insets.NONE : Insets.of(cutout.getSafeInsets()); + Insets waterfallInsets = cutout == null ? Insets.NONE : cutout.getWaterfallInsets(); + // rotate insets to target rotation if needed. + if (rotation != targetRot) { + if (!insets.equals(Insets.NONE)) { + insets = RotationUtils.rotateInsets( + insets, RotationUtils.deltaRotation(rotation, targetRot)); + } + if (!waterfallInsets.equals(Insets.NONE)) { + waterfallInsets = RotationUtils.rotateInsets( + waterfallInsets, RotationUtils.deltaRotation(rotation, targetRot)); + } + } + final int defaultSize = + context.getResources().getDimensionPixelSize(R.dimen.status_bar_height); + // The status bar height should be: + // Max(top cutout size, (status bar default height + waterfall top size)) + return Math.max(insets.top, defaultSize + waterfallInsets.top); + } + + /** + * Gets the height of area above QQS where battery/time go in notification panel. The height + * equals to status bar height if status bar height is bigger than the + * {@link R.dimen#quick_qs_offset_height}. + */ + public static int getQuickQsOffsetHeight(Context context) { + final int defaultSize = context.getResources().getDimensionPixelSize( + R.dimen.quick_qs_offset_height); + final int statusBarHeight = getStatusBarHeight(context); + // Equals to status bar height if status bar height is bigger. + return Math.max(defaultSize, statusBarHeight); + } +} diff --git a/core/java/com/android/internal/policy/TransitionAnimation.java b/core/java/com/android/internal/policy/TransitionAnimation.java index 60a8d802861f..d3224b13e312 100644 --- a/core/java/com/android/internal/policy/TransitionAnimation.java +++ b/core/java/com/android/internal/policy/TransitionAnimation.java @@ -16,16 +16,20 @@ package com.android.internal.policy; +import static android.view.WindowManager.TRANSIT_CLOSE; import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION; import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_SUBTLE_ANIMATION; import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE; import static android.view.WindowManager.TRANSIT_OLD_ACTIVITY_CLOSE; import static android.view.WindowManager.TRANSIT_OLD_ACTIVITY_OPEN; +import static android.view.WindowManager.TRANSIT_OLD_NONE; import static android.view.WindowManager.TRANSIT_OLD_TRANSLUCENT_ACTIVITY_CLOSE; import static android.view.WindowManager.TRANSIT_OLD_TRANSLUCENT_ACTIVITY_OPEN; import static android.view.WindowManager.TRANSIT_OLD_WALLPAPER_INTRA_CLOSE; import static android.view.WindowManager.TRANSIT_OLD_WALLPAPER_INTRA_OPEN; +import static android.view.WindowManager.TRANSIT_OPEN; +import android.annotation.DrawableRes; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityManager; @@ -34,12 +38,18 @@ import android.content.res.Configuration; import android.content.res.ResourceId; import android.content.res.Resources; import android.content.res.TypedArray; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Picture; import android.graphics.Rect; +import android.graphics.drawable.Drawable; import android.hardware.HardwareBuffer; import android.os.SystemProperties; import android.util.Slog; import android.view.WindowManager.LayoutParams; import android.view.WindowManager.TransitionOldType; +import android.view.WindowManager.TransitionType; import android.view.animation.AlphaAnimation; import android.view.animation.Animation; import android.view.animation.AnimationSet; @@ -56,11 +66,17 @@ import java.util.List; /** @hide */ public class TransitionAnimation { + public static final int WALLPAPER_TRANSITION_NONE = 0; + public static final int WALLPAPER_TRANSITION_OPEN = 1; + public static final int WALLPAPER_TRANSITION_CLOSE = 2; + public static final int WALLPAPER_TRANSITION_INTRA_OPEN = 3; + public static final int WALLPAPER_TRANSITION_INTRA_CLOSE = 4; + // These are the possible states for the enter/exit activities during a thumbnail transition - public static final int THUMBNAIL_TRANSITION_ENTER_SCALE_UP = 0; - public static final int THUMBNAIL_TRANSITION_EXIT_SCALE_UP = 1; - public static final int THUMBNAIL_TRANSITION_ENTER_SCALE_DOWN = 2; - public static final int THUMBNAIL_TRANSITION_EXIT_SCALE_DOWN = 3; + private static final int THUMBNAIL_TRANSITION_ENTER_SCALE_UP = 0; + private static final int THUMBNAIL_TRANSITION_EXIT_SCALE_UP = 1; + private static final int THUMBNAIL_TRANSITION_ENTER_SCALE_DOWN = 2; + private static final int THUMBNAIL_TRANSITION_EXIT_SCALE_DOWN = 3; /** * Maximum duration for the clip reveal animation. This is used when there is a lot of movement @@ -72,9 +88,15 @@ public class TransitionAnimation { public static final int DEFAULT_APP_TRANSITION_DURATION = 336; + /** Fraction of animation at which the recents thumbnail stays completely transparent */ + private static final float RECENTS_THUMBNAIL_FADEIN_FRACTION = 0.5f; /** Fraction of animation at which the recents thumbnail becomes completely transparent */ private static final float RECENTS_THUMBNAIL_FADEOUT_FRACTION = 0.5f; + /** Interpolator to be used for animations that respond directly to a touch */ + static final Interpolator TOUCH_RESPONSE_INTERPOLATOR = + new PathInterpolator(0.3f, 0f, 0.1f, 1f); + private static final String DEFAULT_PACKAGE = "android"; private final Context mContext; @@ -86,7 +108,9 @@ public class TransitionAnimation { new PathInterpolator(0.3f, 0f, 0.1f, 1f); private final Interpolator mClipHorizontalInterpolator = new PathInterpolator(0, 0, 0.4f, 1f); private final Interpolator mDecelerateInterpolator; + private final Interpolator mFastOutLinearInInterpolator; private final Interpolator mLinearOutSlowInInterpolator; + private final Interpolator mThumbnailFadeInInterpolator; private final Interpolator mThumbnailFadeOutInterpolator; private final Rect mTmpFromClipRect = new Rect(); private final Rect mTmpToClipRect = new Rect(); @@ -107,8 +131,19 @@ public class TransitionAnimation { mDecelerateInterpolator = AnimationUtils.loadInterpolator(context, com.android.internal.R.interpolator.decelerate_cubic); + mFastOutLinearInInterpolator = AnimationUtils.loadInterpolator(context, + com.android.internal.R.interpolator.fast_out_linear_in); mLinearOutSlowInInterpolator = AnimationUtils.loadInterpolator(context, com.android.internal.R.interpolator.linear_out_slow_in); + mThumbnailFadeInInterpolator = input -> { + // Linear response for first fraction, then complete after that. + if (input < RECENTS_THUMBNAIL_FADEIN_FRACTION) { + return 0f; + } + float t = (input - RECENTS_THUMBNAIL_FADEIN_FRACTION) + / (1f - RECENTS_THUMBNAIL_FADEIN_FRACTION); + return mFastOutLinearInInterpolator.getInterpolation(t); + }; mThumbnailFadeOutInterpolator = input -> { // Linear response for first fraction, then complete after that. if (input < RECENTS_THUMBNAIL_FADEOUT_FRACTION) { @@ -181,6 +216,13 @@ public class TransitionAnimation { DEFAULT_PACKAGE, com.android.internal.R.anim.cross_profile_apps_thumbnail_enter); } + @Nullable + public Animation createCrossProfileAppsThumbnailAnimationLocked(Rect appRect) { + final Animation animation = loadCrossProfileAppThumbnailEnterAnimation(); + return prepareThumbnailAnimationWithDuration(animation, appRect.width(), + appRect.height(), 0, null); + } + /** Load animation by resource Id from specific package. */ @Nullable public Animation loadAnimationRes(String packageName, int resId) { @@ -347,8 +389,15 @@ public class TransitionAnimation { } } - public Animation createClipRevealAnimationLocked(int transit, boolean enter, Rect appFrame, - Rect displayFrame, Rect startRect) { + public Animation createClipRevealAnimationLocked(@TransitionType int transit, + int wallpaperTransit, boolean enter, Rect appFrame, Rect displayFrame, Rect startRect) { + return createClipRevealAnimationLockedCompat( + getTransitCompatType(transit, wallpaperTransit), enter, appFrame, displayFrame, + startRect); + } + + public Animation createClipRevealAnimationLockedCompat(@TransitionOldType int transit, + boolean enter, Rect appFrame, Rect displayFrame, Rect startRect) { final Animation anim; if (enter) { final int appWidth = appFrame.width(); @@ -458,8 +507,14 @@ public class TransitionAnimation { return anim; } - public Animation createScaleUpAnimationLocked(int transit, boolean enter, - Rect containingFrame, Rect startRect) { + public Animation createScaleUpAnimationLocked(@TransitionType int transit, int wallpaperTransit, + boolean enter, Rect containingFrame, Rect startRect) { + return createScaleUpAnimationLockedCompat(getTransitCompatType(transit, wallpaperTransit), + enter, containingFrame, startRect); + } + + public Animation createScaleUpAnimationLockedCompat(@TransitionOldType int transit, + boolean enter, Rect containingFrame, Rect startRect) { Animation a; setupDefaultNextAppTransitionStartRect(startRect, mTmpRect); final int appWidth = containingFrame.width(); @@ -514,12 +569,19 @@ public class TransitionAnimation { return a; } + public Animation createThumbnailEnterExitAnimationLocked(boolean enter, boolean scaleUp, + Rect containingFrame, @TransitionType int transit, int wallpaperTransit, + HardwareBuffer thumbnailHeader, Rect startRect) { + return createThumbnailEnterExitAnimationLockedCompat(enter, scaleUp, containingFrame, + getTransitCompatType(transit, wallpaperTransit), thumbnailHeader, startRect); + } + /** * This animation is created when we are doing a thumbnail transition, for the activity that is * leaving, and the activity that is entering. */ - public Animation createThumbnailEnterExitAnimationLocked(int thumbTransitState, - Rect containingFrame, int transit, HardwareBuffer thumbnailHeader, + public Animation createThumbnailEnterExitAnimationLockedCompat(boolean enter, boolean scaleUp, + Rect containingFrame, @TransitionOldType int transit, HardwareBuffer thumbnailHeader, Rect startRect) { final int appWidth = containingFrame.width(); final int appHeight = containingFrame.height(); @@ -529,6 +591,7 @@ public class TransitionAnimation { final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1; final int thumbHeightI = thumbnailHeader != null ? thumbnailHeader.getHeight() : appHeight; final float thumbHeight = thumbHeightI > 0 ? thumbHeightI : 1; + final int thumbTransitState = getThumbnailTransitionState(enter, scaleUp); switch (thumbTransitState) { case THUMBNAIL_TRANSITION_ENTER_SCALE_UP: { @@ -587,8 +650,8 @@ public class TransitionAnimation { * This alternate animation is created when we are doing a thumbnail transition, for the * activity that is leaving, and the activity that is entering. */ - public Animation createAspectScaledThumbnailEnterExitAnimationLocked(int thumbTransitState, - int orientation, int transit, Rect containingFrame, Rect contentInsets, + public Animation createAspectScaledThumbnailEnterExitAnimationLocked(boolean enter, + boolean scaleUp, int orientation, int transit, Rect containingFrame, Rect contentInsets, @Nullable Rect surfaceInsets, @Nullable Rect stableInsets, boolean freeform, Rect startRect, Rect defaultStartRect) { Animation a; @@ -601,11 +664,11 @@ public class TransitionAnimation { final float thumbHeight = thumbHeightI > 0 ? thumbHeightI : 1; final int thumbStartX = mTmpRect.left - containingFrame.left - contentInsets.left; final int thumbStartY = mTmpRect.top - containingFrame.top; + final int thumbTransitState = getThumbnailTransitionState(enter, scaleUp); switch (thumbTransitState) { case THUMBNAIL_TRANSITION_ENTER_SCALE_UP: case THUMBNAIL_TRANSITION_EXIT_SCALE_DOWN: { - final boolean scaleUp = thumbTransitState == THUMBNAIL_TRANSITION_ENTER_SCALE_UP; if (freeform && scaleUp) { a = createAspectScaledThumbnailEnterFreeformAnimationLocked( containingFrame, surfaceInsets, startRect, defaultStartRect); @@ -719,11 +782,152 @@ public class TransitionAnimation { THUMBNAIL_APP_TRANSITION_DURATION, mTouchResponseInterpolator); } + /** + * This animation runs for the thumbnail that gets cross faded with the enter/exit activity + * when a thumbnail is specified with the pending animation override. + */ + public Animation createThumbnailAspectScaleAnimationLocked(Rect appRect, + @Nullable Rect contentInsets, HardwareBuffer thumbnailHeader, int orientation, + Rect startRect, Rect defaultStartRect, boolean scaleUp) { + Animation a; + final int thumbWidthI = thumbnailHeader.getWidth(); + final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1; + final int thumbHeightI = thumbnailHeader.getHeight(); + final int appWidth = appRect.width(); + + float scaleW = appWidth / thumbWidth; + getNextAppTransitionStartRect(startRect, defaultStartRect, mTmpRect); + final float fromX; + float fromY; + final float toX; + float toY; + final float pivotX; + final float pivotY; + if (shouldScaleDownThumbnailTransition(orientation)) { + fromX = mTmpRect.left; + fromY = mTmpRect.top; + + // For the curved translate animation to work, the pivot points needs to be at the + // same absolute position as the one from the real surface. + toX = mTmpRect.width() / 2 * (scaleW - 1f) + appRect.left; + toY = appRect.height() / 2 * (1 - 1 / scaleW) + appRect.top; + pivotX = mTmpRect.width() / 2; + pivotY = appRect.height() / 2 / scaleW; + if (mGridLayoutRecentsEnabled) { + // In the grid layout, the header is displayed above the thumbnail instead of + // overlapping it. + fromY -= thumbHeightI; + toY -= thumbHeightI * scaleW; + } + } else { + pivotX = 0; + pivotY = 0; + fromX = mTmpRect.left; + fromY = mTmpRect.top; + toX = appRect.left; + toY = appRect.top; + } + if (scaleUp) { + // Animation up from the thumbnail to the full screen + Animation scale = new ScaleAnimation(1f, scaleW, 1f, scaleW, pivotX, pivotY); + scale.setInterpolator(TOUCH_RESPONSE_INTERPOLATOR); + scale.setDuration(THUMBNAIL_APP_TRANSITION_DURATION); + Animation alpha = new AlphaAnimation(1f, 0f); + alpha.setInterpolator(mThumbnailFadeOutInterpolator); + alpha.setDuration(THUMBNAIL_APP_TRANSITION_DURATION); + Animation translate = createCurvedMotion(fromX, toX, fromY, toY); + translate.setInterpolator(TOUCH_RESPONSE_INTERPOLATOR); + translate.setDuration(THUMBNAIL_APP_TRANSITION_DURATION); + + mTmpFromClipRect.set(0, 0, thumbWidthI, thumbHeightI); + mTmpToClipRect.set(appRect); + + // Containing frame is in screen space, but we need the clip rect in the + // app space. + mTmpToClipRect.offsetTo(0, 0); + mTmpToClipRect.right = (int) (mTmpToClipRect.right / scaleW); + mTmpToClipRect.bottom = (int) (mTmpToClipRect.bottom / scaleW); + + if (contentInsets != null) { + mTmpToClipRect.inset((int) (-contentInsets.left * scaleW), + (int) (-contentInsets.top * scaleW), + (int) (-contentInsets.right * scaleW), + (int) (-contentInsets.bottom * scaleW)); + } + + Animation clipAnim = new ClipRectAnimation(mTmpFromClipRect, mTmpToClipRect); + clipAnim.setInterpolator(TOUCH_RESPONSE_INTERPOLATOR); + clipAnim.setDuration(THUMBNAIL_APP_TRANSITION_DURATION); + + // This AnimationSet uses the Interpolators assigned above. + AnimationSet set = new AnimationSet(false); + set.addAnimation(scale); + if (!mGridLayoutRecentsEnabled) { + // In the grid layout, the header should be shown for the whole animation. + set.addAnimation(alpha); + } + set.addAnimation(translate); + set.addAnimation(clipAnim); + a = set; + } else { + // Animation down from the full screen to the thumbnail + Animation scale = new ScaleAnimation(scaleW, 1f, scaleW, 1f, pivotX, pivotY); + scale.setInterpolator(TOUCH_RESPONSE_INTERPOLATOR); + scale.setDuration(THUMBNAIL_APP_TRANSITION_DURATION); + Animation alpha = new AlphaAnimation(0f, 1f); + alpha.setInterpolator(mThumbnailFadeInInterpolator); + alpha.setDuration(THUMBNAIL_APP_TRANSITION_DURATION); + Animation translate = createCurvedMotion(toX, fromX, toY, fromY); + translate.setInterpolator(TOUCH_RESPONSE_INTERPOLATOR); + translate.setDuration(THUMBNAIL_APP_TRANSITION_DURATION); + + // This AnimationSet uses the Interpolators assigned above. + AnimationSet set = new AnimationSet(false); + set.addAnimation(scale); + if (!mGridLayoutRecentsEnabled) { + // In the grid layout, the header should be shown for the whole animation. + set.addAnimation(alpha); + } + set.addAnimation(translate); + a = set; + + } + return prepareThumbnailAnimationWithDuration(a, appWidth, appRect.height(), 0, + null); + } + + /** + * Creates an overlay with a background color and a thumbnail for the cross profile apps + * animation. + */ + public HardwareBuffer createCrossProfileAppsThumbnail( + @DrawableRes int thumbnailDrawableRes, Rect frame) { + final int width = frame.width(); + final int height = frame.height(); + + final Picture picture = new Picture(); + final Canvas canvas = picture.beginRecording(width, height); + canvas.drawColor(Color.argb(0.6f, 0, 0, 0)); + final int thumbnailSize = mContext.getResources().getDimensionPixelSize( + com.android.internal.R.dimen.cross_profile_apps_thumbnail_size); + final Drawable drawable = mContext.getDrawable(thumbnailDrawableRes); + drawable.setBounds( + (width - thumbnailSize) / 2, + (height - thumbnailSize) / 2, + (width + thumbnailSize) / 2, + (height + thumbnailSize) / 2); + drawable.setTint(mContext.getColor(android.R.color.white)); + drawable.draw(canvas); + picture.endRecording(); + + return Bitmap.createBitmap(picture).getHardwareBuffer(); + } + /** * Prepares the specified animation with a standard duration, interpolator, etc. */ private Animation prepareThumbnailAnimation(Animation a, int appWidth, int appHeight, - int transit) { + @TransitionOldType int transit) { // Pick the desired duration. If this is an inter-activity transition, // it is the standard duration for that. Otherwise we use the longer // task transition duration. @@ -820,6 +1024,22 @@ public class TransitionAnimation { return anim; } + private static @TransitionOldType int getTransitCompatType(@TransitionType int transit, + int wallpaperTransit) { + if (wallpaperTransit == WALLPAPER_TRANSITION_INTRA_OPEN) { + return TRANSIT_OLD_WALLPAPER_INTRA_OPEN; + } else if (wallpaperTransit == WALLPAPER_TRANSITION_INTRA_CLOSE) { + return TRANSIT_OLD_WALLPAPER_INTRA_CLOSE; + } else if (transit == TRANSIT_OPEN) { + return TRANSIT_OLD_ACTIVITY_OPEN; + } else if (transit == TRANSIT_CLOSE) { + return TRANSIT_OLD_ACTIVITY_CLOSE; + } + + // We only do some special handle for above type, so use type NONE for default behavior. + return TRANSIT_OLD_NONE; + } + /** * Calculates the duration for the clip reveal animation. If the clip is "cut off", meaning that * the start rect is outside of the target rect, and there is a lot of movement going on. @@ -842,11 +1062,34 @@ public class TransitionAnimation { * (MAX_CLIP_REVEAL_TRANSITION_DURATION - DEFAULT_APP_TRANSITION_DURATION)); } + /** + * Return the current thumbnail transition state. + */ + private int getThumbnailTransitionState(boolean enter, boolean scaleUp) { + if (enter) { + if (scaleUp) { + return THUMBNAIL_TRANSITION_ENTER_SCALE_UP; + } else { + return THUMBNAIL_TRANSITION_ENTER_SCALE_DOWN; + } + } else { + if (scaleUp) { + return THUMBNAIL_TRANSITION_EXIT_SCALE_UP; + } else { + return THUMBNAIL_TRANSITION_EXIT_SCALE_DOWN; + } + } + } + /** * Prepares the specified animation with a standard duration, interpolator, etc. */ - private static Animation prepareThumbnailAnimationWithDuration(Animation a, int appWidth, + public static Animation prepareThumbnailAnimationWithDuration(Animation a, int appWidth, int appHeight, long duration, Interpolator interpolator) { + if (a == null) { + return null; + } + if (duration > 0) { a.setDuration(duration); } diff --git a/core/java/com/android/internal/protolog/ProtoLogGroup.java b/core/java/com/android/internal/protolog/ProtoLogGroup.java index ce3efd35ee48..5ac493637822 100644 --- a/core/java/com/android/internal/protolog/ProtoLogGroup.java +++ b/core/java/com/android/internal/protolog/ProtoLogGroup.java @@ -80,6 +80,11 @@ public enum ProtoLogGroup implements IProtoLogGroup { Consts.TAG_WM), WM_DEBUG_WINDOW_TRANSITIONS(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, true, Consts.TAG_WM), + WM_DEBUG_WINDOW_INSETS(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false, + Consts.TAG_WM), + WM_DEBUG_LAYER_MIRRORING(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, true, + Consts.TAG_WM), + WM_DEBUG_WALLPAPER(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false, Consts.TAG_WM), TEST_GROUP(true, true, false, "WindowManagerProtoLogTest"); private final boolean mEnabled; diff --git a/core/java/com/android/internal/protolog/ProtoLogImpl.java b/core/java/com/android/internal/protolog/ProtoLogImpl.java index 10224a4b9db6..353c6c083d9d 100644 --- a/core/java/com/android/internal/protolog/ProtoLogImpl.java +++ b/core/java/com/android/internal/protolog/ProtoLogImpl.java @@ -28,7 +28,7 @@ import java.io.File; */ public class ProtoLogImpl extends BaseProtoLogImpl { private static final int BUFFER_CAPACITY = 1024 * 1024; - private static final String LOG_FILENAME = "/data/misc/wmtrace/wm_log.pb"; + private static final String LOG_FILENAME = "/data/misc/wmtrace/wm_log.winscope"; private static final String VIEWER_CONFIG_FILENAME = "/system/etc/protolog.conf.json.gz"; private static ProtoLogImpl sServiceInstance = null; diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl index ed6415d749a3..ad4f280b1e8d 100644 --- a/core/java/com/android/internal/statusbar/IStatusBar.aidl +++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl @@ -25,6 +25,7 @@ import android.hardware.fingerprint.IUdfpsHbmListener; import android.os.Bundle; import android.os.ParcelFileDescriptor; import android.service.notification.StatusBarNotification; +import android.view.InsetsVisibilities; import com.android.internal.statusbar.StatusBarIcon; import com.android.internal.view.AppearanceRegion; @@ -182,7 +183,7 @@ oneway interface IStatusBar /** * Notifies System UI side of system bar attribute change on the specified display. * - * @param displayId the ID of the display to notify + * @param displayId the ID of the display to notify. * @param appearance the appearance of the focused window. The light top bar appearance is not * controlled here, but primaryAppearance and secondaryAppearance. * @param appearanceRegions a set of appearances which will be only applied in their own bounds. @@ -191,11 +192,12 @@ oneway interface IStatusBar * stacks. * @param navbarColorManagedByIme {@code true} if navigation bar color is managed by IME. * @param behavior the behavior of the focused window. - * @param isFullscreen whether any of status or navigation bar is requested invisible. + * @param requestedVisibilities the collection of the requested visibilities of system insets. + * @param packageName the package name of the focused app. */ void onSystemBarAttributesChanged(int displayId, int appearance, in AppearanceRegion[] appearanceRegions, boolean navbarColorManagedByIme, - int behavior, boolean isFullscreen); + int behavior, in InsetsVisibilities requestedVisibilities, String packageName); /** * Notifies System UI to show transient bars. The transient bars are system bars, e.g., status @@ -203,8 +205,10 @@ oneway interface IStatusBar * * @param displayId the ID of the display to notify. * @param types the internal insets types of the bars are about to show transiently. + * @param isGestureOnSystemBar whether the gesture to show the transient bar was a gesture on + * one of the bars itself. */ - void showTransient(int displayId, in int[] types); + void showTransient(int displayId, in int[] types, boolean isGestureOnSystemBar); /** * Notifies System UI to abort the transient state of system bars, which prevents the bars being diff --git a/core/java/com/android/internal/statusbar/RegisterStatusBarResult.java b/core/java/com/android/internal/statusbar/RegisterStatusBarResult.java index 8fb2f9cd8bf9..4dcc82e2e572 100644 --- a/core/java/com/android/internal/statusbar/RegisterStatusBarResult.java +++ b/core/java/com/android/internal/statusbar/RegisterStatusBarResult.java @@ -21,6 +21,7 @@ import android.os.IBinder; import android.os.Parcel; import android.os.Parcelable; import android.util.ArrayMap; +import android.view.InsetsVisibilities; import com.android.internal.view.AppearanceRegion; @@ -39,14 +40,15 @@ public final class RegisterStatusBarResult implements Parcelable { public final IBinder mImeToken; public final boolean mNavbarColorManagedByIme; public final int mBehavior; - public final boolean mAppFullscreen; + public final InsetsVisibilities mRequestedVisibilities; + public final String mPackageName; public final int[] mTransientBarTypes; public RegisterStatusBarResult(ArrayMap icons, int disabledFlags1, int appearance, AppearanceRegion[] appearanceRegions, int imeWindowVis, int imeBackDisposition, boolean showImeSwitcher, int disabledFlags2, IBinder imeToken, - boolean navbarColorManagedByIme, int behavior, boolean appFullscreen, - @NonNull int[] transientBarTypes) { + boolean navbarColorManagedByIme, int behavior, InsetsVisibilities requestedVisibilities, + String packageName, @NonNull int[] transientBarTypes) { mIcons = new ArrayMap<>(icons); mDisabledFlags1 = disabledFlags1; mAppearance = appearance; @@ -58,7 +60,8 @@ public final class RegisterStatusBarResult implements Parcelable { mImeToken = imeToken; mNavbarColorManagedByIme = navbarColorManagedByIme; mBehavior = behavior; - mAppFullscreen = appFullscreen; + mRequestedVisibilities = requestedVisibilities; + mPackageName = packageName; mTransientBarTypes = transientBarTypes; } @@ -80,7 +83,8 @@ public final class RegisterStatusBarResult implements Parcelable { dest.writeStrongBinder(mImeToken); dest.writeBoolean(mNavbarColorManagedByIme); dest.writeInt(mBehavior); - dest.writeBoolean(mAppFullscreen); + dest.writeTypedObject(mRequestedVisibilities, 0); + dest.writeString(mPackageName); dest.writeIntArray(mTransientBarTypes); } @@ -104,12 +108,14 @@ public final class RegisterStatusBarResult implements Parcelable { final IBinder imeToken = source.readStrongBinder(); final boolean navbarColorManagedByIme = source.readBoolean(); final int behavior = source.readInt(); - final boolean appFullscreen = source.readBoolean(); + final InsetsVisibilities requestedVisibilities = + source.readTypedObject(InsetsVisibilities.CREATOR); + final String packageName = source.readString(); final int[] transientBarTypes = source.createIntArray(); return new RegisterStatusBarResult(icons, disabledFlags1, appearance, appearanceRegions, imeWindowVis, imeBackDisposition, showImeSwitcher, disabledFlags2, imeToken, navbarColorManagedByIme, behavior, - appFullscreen, transientBarTypes); + requestedVisibilities, packageName, transientBarTypes); } @Override diff --git a/core/java/com/android/internal/util/LatencyTracker.java b/core/java/com/android/internal/util/LatencyTracker.java index f040462dafdc..4c519f4c779f 100644 --- a/core/java/com/android/internal/util/LatencyTracker.java +++ b/core/java/com/android/internal/util/LatencyTracker.java @@ -14,15 +14,20 @@ package com.android.internal.util; +import static android.os.Trace.TRACE_TAG_APP; + import android.annotation.IntDef; +import android.annotation.NonNull; +import android.annotation.Nullable; import android.content.Context; import android.os.Build; import android.os.SystemClock; import android.os.Trace; import android.provider.DeviceConfig; +import android.text.TextUtils; import android.util.EventLog; import android.util.Log; -import android.util.SparseLongArray; +import android.util.SparseArray; import com.android.internal.annotations.GuardedBy; import com.android.internal.logging.EventLogTags; @@ -31,6 +36,7 @@ import com.android.internal.os.BackgroundThread; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.concurrent.ThreadLocalRandom; +import java.util.concurrent.TimeUnit; /** * Class to track various latencies in SystemUI. It then writes the latency to statsd and also @@ -44,6 +50,7 @@ public class LatencyTracker { private static final String TAG = "LatencyTracker"; private static final String SETTINGS_ENABLED_KEY = "enabled"; private static final String SETTINGS_SAMPLING_INTERVAL_KEY = "sampling_interval"; + private static final boolean DEBUG = false; /** Default to being enabled on debug builds. */ private static final boolean DEFAULT_ENABLED = Build.IS_DEBUGGABLE; /** Default to collecting data for 1/5 of all actions (randomly sampled). */ @@ -110,6 +117,11 @@ public class LatencyTracker { */ public static final int ACTION_LOCKSCREEN_UNLOCK = 11; + /** + * Time it takes to switch users. + */ + public static final int ACTION_USER_SWITCH = 12; + private static final int[] ACTIONS_ALL = { ACTION_EXPAND_PANEL, ACTION_TOGGLE_RECENTS, @@ -122,7 +134,8 @@ public class LatencyTracker { ACTION_START_RECENTS_ANIMATION, ACTION_ROTATE_SCREEN_SENSOR, ACTION_ROTATE_SCREEN_CAMERA_CHECK, - ACTION_LOCKSCREEN_UNLOCK + ACTION_LOCKSCREEN_UNLOCK, + ACTION_USER_SWITCH }; /** @hide */ @@ -138,7 +151,8 @@ public class LatencyTracker { ACTION_START_RECENTS_ANIMATION, ACTION_ROTATE_SCREEN_SENSOR, ACTION_ROTATE_SCREEN_CAMERA_CHECK, - ACTION_LOCKSCREEN_UNLOCK + ACTION_LOCKSCREEN_UNLOCK, + ACTION_USER_SWITCH }) @Retention(RetentionPolicy.SOURCE) public @interface Action { @@ -156,13 +170,15 @@ public class LatencyTracker { FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_START_RECENTS_ANIMATION, FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_ROTATE_SCREEN_SENSOR, FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_ROTATE_SCREEN_CAMERA_CHECK, - FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_LOCKSCREEN_UNLOCK + FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_LOCKSCREEN_UNLOCK, + FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_USER_SWITCH }; private static LatencyTracker sLatencyTracker; private final Object mLock = new Object(); - private final SparseLongArray mStartRtc = new SparseLongArray(); + @GuardedBy("mLock") + private final SparseArray mSessions = new SparseArray<>(); @GuardedBy("mLock") private final int[] mTraceThresholdPerAction = new int[ACTIONS_ALL.length]; @GuardedBy("mLock") @@ -239,13 +255,19 @@ public class LatencyTracker { return "ACTION_ROTATE_SCREEN_SENSOR"; case 12: return "ACTION_LOCKSCREEN_UNLOCK"; + case 13: + return "ACTION_USER_SWITCH"; default: throw new IllegalArgumentException("Invalid action"); } } - private static String getTraceNameOfAction(@Action int action) { - return "L<" + getNameOfAction(STATSD_ACTION[action]) + ">"; + private static String getTraceNameOfAction(@Action int action, String tag) { + if (TextUtils.isEmpty(tag)) { + return "L<" + getNameOfAction(STATSD_ACTION[action]) + ">"; + } else { + return "L<" + getNameOfAction(STATSD_ACTION[action]) + "::" + tag + ">"; + } } private static String getTraceTriggerNameForAction(@Action int action) { @@ -263,35 +285,82 @@ public class LatencyTracker { } /** - * Notifies that an action is starting. This needs to be called from the main thread. + * Notifies that an action is starting. This needs to be called from the main thread. * * @param action The action to start. One of the ACTION_* values. */ public void onActionStart(@Action int action) { - if (!isEnabled()) { - return; + onActionStart(action, null); + } + + /** + * Notifies that an action is starting. This needs to be called from the main thread. + * + * @param action The action to start. One of the ACTION_* values. + * @param tag The brief description of the action. + */ + public void onActionStart(@Action int action, String tag) { + synchronized (mLock) { + if (!isEnabled()) { + return; + } + // skip if the action is already instrumenting. + if (mSessions.get(action) != null) { + return; + } + Session session = new Session(action, tag); + session.begin(() -> onActionCancel(action)); + mSessions.put(action, session); + + if (DEBUG) { + Log.d(TAG, "onActionStart: " + session.name() + ", start=" + session.mStartRtc); + } } - Trace.asyncTraceBegin(Trace.TRACE_TAG_APP, getTraceNameOfAction(action), 0); - mStartRtc.put(action, SystemClock.elapsedRealtime()); } /** - * Notifies that an action has ended. This needs to be called from the main thread. + * Notifies that an action has ended. This needs to be called from the main thread. * * @param action The action to end. One of the ACTION_* values. */ public void onActionEnd(@Action int action) { - if (!isEnabled()) { - return; + synchronized (mLock) { + if (!isEnabled()) { + return; + } + Session session = mSessions.get(action); + if (session == null) { + return; + } + session.end(); + mSessions.delete(action); + logAction(action, session.duration()); + + if (DEBUG) { + Log.d(TAG, "onActionEnd:" + session.name() + ", duration=" + session.duration()); + } } - long endRtc = SystemClock.elapsedRealtime(); - long startRtc = mStartRtc.get(action, -1); - if (startRtc == -1) { - return; + } + + /** + * Notifies that an action has canceled. This needs to be called from the main thread. + * + * @param action The action to cancel. One of the ACTION_* values. + * @hide + */ + public void onActionCancel(@Action int action) { + synchronized (mLock) { + Session session = mSessions.get(action); + if (session == null) { + return; + } + session.cancel(); + mSessions.delete(action); + + if (DEBUG) { + Log.d(TAG, "onActionCancel: " + session.name()); + } } - mStartRtc.delete(action); - Trace.asyncTraceEnd(Trace.TRACE_TAG_APP, getTraceNameOfAction(action), 0); - logAction(action, (int) (endRtc - startRtc)); } /** @@ -332,4 +401,57 @@ public class LatencyTracker { FrameworkStatsLog.UI_ACTION_LATENCY_REPORTED, STATSD_ACTION[action], duration); } } + + static class Session { + @Action + private final int mAction; + private final String mTag; + private final String mName; + private Runnable mTimeoutRunnable; + private long mStartRtc = -1; + private long mEndRtc = -1; + + Session(@Action int action, @Nullable String tag) { + mAction = action; + mTag = tag; + mName = TextUtils.isEmpty(mTag) + ? getNameOfAction(STATSD_ACTION[mAction]) + : getNameOfAction(STATSD_ACTION[mAction]) + "::" + mTag; + } + + String name() { + return mName; + } + + String traceName() { + return getTraceNameOfAction(mAction, mTag); + } + + void begin(@NonNull Runnable timeoutAction) { + mStartRtc = SystemClock.elapsedRealtime(); + Trace.asyncTraceBegin(TRACE_TAG_APP, traceName(), 0); + + // start counting timeout. + mTimeoutRunnable = timeoutAction; + BackgroundThread.getHandler() + .postDelayed(mTimeoutRunnable, TimeUnit.SECONDS.toMillis(15)); + } + + void end() { + mEndRtc = SystemClock.elapsedRealtime(); + Trace.asyncTraceEnd(TRACE_TAG_APP, traceName(), 0); + BackgroundThread.getHandler().removeCallbacks(mTimeoutRunnable); + mTimeoutRunnable = null; + } + + void cancel() { + Trace.asyncTraceEnd(TRACE_TAG_APP, traceName(), 0); + BackgroundThread.getHandler().removeCallbacks(mTimeoutRunnable); + mTimeoutRunnable = null; + } + + int duration() { + return (int) (mEndRtc - mStartRtc); + } + } } diff --git a/core/java/com/android/internal/view/IInputMethod.aidl b/core/java/com/android/internal/view/IInputMethod.aidl index 8d82e33dc29f..5354afbd667b 100644 --- a/core/java/com/android/internal/view/IInputMethod.aidl +++ b/core/java/com/android/internal/view/IInputMethod.aidl @@ -35,7 +35,7 @@ import com.android.internal.view.InlineSuggestionsRequestInfo; * {@hide} */ oneway interface IInputMethod { - void initializeInternal(IBinder token, int displayId, IInputMethodPrivilegedOperations privOps, + void initializeInternal(IBinder token, IInputMethodPrivilegedOperations privOps, int configChanges); void onCreateInlineSuggestionsRequest(in InlineSuggestionsRequestInfo requestInfo, diff --git a/core/java/com/android/internal/view/ScrollCaptureInternal.java b/core/java/com/android/internal/view/ScrollCaptureInternal.java index e3a9fda7b000..72b5488f4bac 100644 --- a/core/java/com/android/internal/view/ScrollCaptureInternal.java +++ b/core/java/com/android/internal/view/ScrollCaptureInternal.java @@ -25,6 +25,7 @@ import android.util.Log; import android.view.ScrollCaptureCallback; import android.view.View; import android.view.ViewGroup; +import android.webkit.WebView; import android.widget.ListView; /** @@ -43,7 +44,7 @@ public class ScrollCaptureInternal { private static final int DOWN = 1; /** - * Not a ViewGroup, or cannot scroll according to View APIs. + * Cannot scroll according to {@link View#canScrollVertically}. */ public static final int TYPE_FIXED = 0; @@ -60,7 +61,7 @@ public class ScrollCaptureInternal { public static final int TYPE_RECYCLING = 2; /** - * The ViewGroup scrolls, but has no child views in + * Unknown scrollable view with no child views (or not a subclass of ViewGroup). */ private static final int TYPE_OPAQUE = 3; @@ -73,16 +74,6 @@ public class ScrollCaptureInternal { * as excluded during scroll capture search. */ private static int detectScrollingType(View view) { - // Must be a ViewGroup - if (!(view instanceof ViewGroup)) { - if (DEBUG_VERBOSE) { - Log.v(TAG, "hint: not a subclass of ViewGroup"); - } - return TYPE_FIXED; - } - if (DEBUG_VERBOSE) { - Log.v(TAG, "hint: is a subclass of ViewGroup"); - } // Confirm that it can scroll. if (!(view.canScrollVertically(DOWN) || view.canScrollVertically(UP))) { // Nothing to scroll here, move along. @@ -94,6 +85,17 @@ public class ScrollCaptureInternal { if (DEBUG_VERBOSE) { Log.v(TAG, "hint: can be scrolled up or down"); } + // Must be a ViewGroup + if (!(view instanceof ViewGroup)) { + if (DEBUG_VERBOSE) { + Log.v(TAG, "hint: not a subclass of ViewGroup"); + } + return TYPE_OPAQUE; + } + if (DEBUG_VERBOSE) { + Log.v(TAG, "hint: is a subclass of ViewGroup"); + } + // ScrollViews accept only a single child. if (((ViewGroup) view).getChildCount() > 1) { if (DEBUG_VERBOSE) { @@ -188,6 +190,18 @@ public class ScrollCaptureInternal { } return new ScrollCaptureViewSupport<>((ViewGroup) view, new RecyclerViewCaptureHelper()); + case TYPE_OPAQUE: + if (DEBUG) { + Log.d(TAG, "scroll capture: FOUND " + view.getClass().getName() + + "[" + resolveId(view.getContext(), view.getId()) + "]" + + " -> TYPE_OPAQUE"); + } + if (view instanceof WebView) { + Log.d(TAG, "scroll capture: Using WebView support"); + return new ScrollCaptureViewSupport<>((WebView) view, + new WebViewCaptureHelper()); + } + break; case TYPE_FIXED: // ignore break; diff --git a/core/java/com/android/internal/view/WebViewCaptureHelper.java b/core/java/com/android/internal/view/WebViewCaptureHelper.java new file mode 100644 index 000000000000..e6a311cfcda5 --- /dev/null +++ b/core/java/com/android/internal/view/WebViewCaptureHelper.java @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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.view; + +import static android.util.MathUtils.constrain; + +import static java.lang.Math.max; +import static java.lang.Math.min; + +import android.annotation.NonNull; +import android.graphics.Rect; +import android.webkit.WebView; + +/** + * ScrollCapture for WebView. + */ +class WebViewCaptureHelper implements ScrollCaptureViewHelper { + private static final String TAG = "WebViewScrollCapture"; + + private final Rect mRequestWebViewLocal = new Rect(); + private final Rect mWebViewBounds = new Rect(); + + private int mOriginScrollY; + private int mOriginScrollX; + + @Override + public boolean onAcceptSession(@NonNull WebView view) { + return view.isVisibleToUser() + && (view.getContentHeight() * view.getScale()) > view.getHeight(); + } + + @Override + public void onPrepareForStart(@NonNull WebView view, @NonNull Rect scrollBounds) { + mOriginScrollX = view.getScrollX(); + mOriginScrollY = view.getScrollY(); + } + + @NonNull + @Override + public ScrollResult onScrollRequested(@NonNull WebView view, @NonNull Rect scrollBounds, + @NonNull Rect requestRect) { + + int scrollDelta = view.getScrollY() - mOriginScrollY; + + ScrollResult result = new ScrollResult(); + result.requestedArea = new Rect(requestRect); + result.availableArea = new Rect(); + result.scrollDelta = scrollDelta; + + mWebViewBounds.set(0, 0, view.getWidth(), view.getHeight()); + + if (!view.isVisibleToUser()) { + return result; + } + + // Map the request into local coordinates + mRequestWebViewLocal.set(requestRect); + mRequestWebViewLocal.offset(0, -scrollDelta); + + // Offset to center the rect vertically, clamp to available content + int upLimit = min(0, -view.getScrollY()); + int contentHeightPx = (int) (view.getContentHeight() * view.getScale()); + int downLimit = max(0, (contentHeightPx - view.getHeight()) - view.getScrollY()); + int scrollToCenter = mRequestWebViewLocal.centerY() - mWebViewBounds.centerY(); + int scrollMovement = constrain(scrollToCenter, upLimit, downLimit); + + // Scroll and update relative based on the new position + view.scrollBy(mOriginScrollX, scrollMovement); + scrollDelta = view.getScrollY() - mOriginScrollY; + mRequestWebViewLocal.offset(0, -scrollMovement); + result.scrollDelta = scrollDelta; + + if (mRequestWebViewLocal.intersect(mWebViewBounds)) { + result.availableArea = new Rect(mRequestWebViewLocal); + result.availableArea.offset(0, result.scrollDelta); + } + return result; + } + + @Override + public void onPrepareForEnd(@NonNull WebView view) { + view.scrollTo(mOriginScrollX, mOriginScrollY); + } + +} + diff --git a/core/java/com/android/internal/widget/PointerLocationView.java b/core/java/com/android/internal/widget/PointerLocationView.java index fd6038fd655d..4fc135c515b0 100644 --- a/core/java/com/android/internal/widget/PointerLocationView.java +++ b/core/java/com/android/internal/widget/PointerLocationView.java @@ -19,6 +19,7 @@ package com.android.internal.widget; import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.graphics.Canvas; +import android.graphics.Insets; import android.graphics.Paint; import android.graphics.Paint.FontMetricsInt; import android.graphics.Path; @@ -136,6 +137,7 @@ public class PointerLocationView extends View implements InputDeviceListener, private final FontMetricsInt mTextMetrics = new FontMetricsInt(); private int mHeaderBottom; private int mHeaderPaddingTop = 0; + private Insets mWaterfallInsets = Insets.NONE; @UnsupportedAppUsage private boolean mCurDown; @UnsupportedAppUsage @@ -229,8 +231,10 @@ public class PointerLocationView extends View implements InputDeviceListener, public WindowInsets onApplyWindowInsets(WindowInsets insets) { if (insets.getDisplayCutout() != null) { mHeaderPaddingTop = insets.getDisplayCutout().getSafeInsetTop(); + mWaterfallInsets = insets.getDisplayCutout().getWaterfallInsets(); } else { mHeaderPaddingTop = 0; + mWaterfallInsets = Insets.NONE; } return super.onApplyWindowInsets(insets); } @@ -266,11 +270,6 @@ public class PointerLocationView extends View implements InputDeviceListener, @Override protected void onDraw(Canvas canvas) { - final int w = getWidth(); - final int itemW = w/7; - final int base = mHeaderPaddingTop-mTextMetrics.ascent+1; - final int bottom = mHeaderBottom; - final int NP = mPointers.size(); if (!mSystemGestureExclusion.isEmpty()) { @@ -286,71 +285,7 @@ public class PointerLocationView extends View implements InputDeviceListener, } // Labels - if (mActivePointerId >= 0) { - final PointerState ps = mPointers.get(mActivePointerId); - - canvas.drawRect(0, mHeaderPaddingTop, itemW-1, bottom,mTextBackgroundPaint); - canvas.drawText(mText.clear() - .append("P: ").append(mCurNumPointers) - .append(" / ").append(mMaxNumPointers) - .toString(), 1, base, mTextPaint); - - final int N = ps.mTraceCount; - if ((mCurDown && ps.mCurDown) || N == 0) { - canvas.drawRect(itemW, mHeaderPaddingTop, (itemW * 2) - 1, bottom, - mTextBackgroundPaint); - canvas.drawText(mText.clear() - .append("X: ").append(ps.mCoords.x, 1) - .toString(), 1 + itemW, base, mTextPaint); - canvas.drawRect(itemW * 2, mHeaderPaddingTop, (itemW * 3) - 1, bottom, - mTextBackgroundPaint); - canvas.drawText(mText.clear() - .append("Y: ").append(ps.mCoords.y, 1) - .toString(), 1 + itemW * 2, base, mTextPaint); - } else { - float dx = ps.mTraceX[N - 1] - ps.mTraceX[0]; - float dy = ps.mTraceY[N - 1] - ps.mTraceY[0]; - canvas.drawRect(itemW, mHeaderPaddingTop, (itemW * 2) - 1, bottom, - Math.abs(dx) < mVC.getScaledTouchSlop() - ? mTextBackgroundPaint : mTextLevelPaint); - canvas.drawText(mText.clear() - .append("dX: ").append(dx, 1) - .toString(), 1 + itemW, base, mTextPaint); - canvas.drawRect(itemW * 2, mHeaderPaddingTop, (itemW * 3) - 1, bottom, - Math.abs(dy) < mVC.getScaledTouchSlop() - ? mTextBackgroundPaint : mTextLevelPaint); - canvas.drawText(mText.clear() - .append("dY: ").append(dy, 1) - .toString(), 1 + itemW * 2, base, mTextPaint); - } - - canvas.drawRect(itemW * 3, mHeaderPaddingTop, (itemW * 4) - 1, bottom, - mTextBackgroundPaint); - canvas.drawText(mText.clear() - .append("Xv: ").append(ps.mXVelocity, 3) - .toString(), 1 + itemW * 3, base, mTextPaint); - - canvas.drawRect(itemW * 4, mHeaderPaddingTop, (itemW * 5) - 1, bottom, - mTextBackgroundPaint); - canvas.drawText(mText.clear() - .append("Yv: ").append(ps.mYVelocity, 3) - .toString(), 1 + itemW * 4, base, mTextPaint); - - canvas.drawRect(itemW * 5, mHeaderPaddingTop, (itemW * 6) - 1, bottom, - mTextBackgroundPaint); - canvas.drawRect(itemW * 5, mHeaderPaddingTop, - (itemW * 5) + (ps.mCoords.pressure * itemW) - 1, bottom, mTextLevelPaint); - canvas.drawText(mText.clear() - .append("Prs: ").append(ps.mCoords.pressure, 2) - .toString(), 1 + itemW * 5, base, mTextPaint); - - canvas.drawRect(itemW * 6, mHeaderPaddingTop, w, bottom, mTextBackgroundPaint); - canvas.drawRect(itemW * 6, mHeaderPaddingTop, - (itemW * 6) + (ps.mCoords.size * itemW) - 1, bottom, mTextLevelPaint); - canvas.drawText(mText.clear() - .append("Size: ").append(ps.mCoords.size, 2) - .toString(), 1 + itemW * 6, base, mTextPaint); - } + drawLabels(canvas); // Pointer trace. for (int p = 0; p < NP; p++) { @@ -463,6 +398,84 @@ public class PointerLocationView extends View implements InputDeviceListener, } } + private void drawLabels(Canvas canvas) { + if (mActivePointerId < 0) { + return; + } + + final int w = getWidth() - mWaterfallInsets.left - mWaterfallInsets.right; + final int itemW = w / 7; + final int base = mHeaderPaddingTop - mTextMetrics.ascent + 1; + final int bottom = mHeaderBottom; + + canvas.save(); + canvas.translate(mWaterfallInsets.left, 0); + final PointerState ps = mPointers.get(mActivePointerId); + + canvas.drawRect(0, mHeaderPaddingTop, itemW - 1, bottom, mTextBackgroundPaint); + canvas.drawText(mText.clear() + .append("P: ").append(mCurNumPointers) + .append(" / ").append(mMaxNumPointers) + .toString(), 1, base, mTextPaint); + + final int count = ps.mTraceCount; + if ((mCurDown && ps.mCurDown) || count == 0) { + canvas.drawRect(itemW, mHeaderPaddingTop, (itemW * 2) - 1, bottom, + mTextBackgroundPaint); + canvas.drawText(mText.clear() + .append("X: ").append(ps.mCoords.x, 1) + .toString(), 1 + itemW, base, mTextPaint); + canvas.drawRect(itemW * 2, mHeaderPaddingTop, (itemW * 3) - 1, bottom, + mTextBackgroundPaint); + canvas.drawText(mText.clear() + .append("Y: ").append(ps.mCoords.y, 1) + .toString(), 1 + itemW * 2, base, mTextPaint); + } else { + float dx = ps.mTraceX[count - 1] - ps.mTraceX[0]; + float dy = ps.mTraceY[count - 1] - ps.mTraceY[0]; + canvas.drawRect(itemW, mHeaderPaddingTop, (itemW * 2) - 1, bottom, + Math.abs(dx) < mVC.getScaledTouchSlop() + ? mTextBackgroundPaint : mTextLevelPaint); + canvas.drawText(mText.clear() + .append("dX: ").append(dx, 1) + .toString(), 1 + itemW, base, mTextPaint); + canvas.drawRect(itemW * 2, mHeaderPaddingTop, (itemW * 3) - 1, bottom, + Math.abs(dy) < mVC.getScaledTouchSlop() + ? mTextBackgroundPaint : mTextLevelPaint); + canvas.drawText(mText.clear() + .append("dY: ").append(dy, 1) + .toString(), 1 + itemW * 2, base, mTextPaint); + } + + canvas.drawRect(itemW * 3, mHeaderPaddingTop, (itemW * 4) - 1, bottom, + mTextBackgroundPaint); + canvas.drawText(mText.clear() + .append("Xv: ").append(ps.mXVelocity, 3) + .toString(), 1 + itemW * 3, base, mTextPaint); + + canvas.drawRect(itemW * 4, mHeaderPaddingTop, (itemW * 5) - 1, bottom, + mTextBackgroundPaint); + canvas.drawText(mText.clear() + .append("Yv: ").append(ps.mYVelocity, 3) + .toString(), 1 + itemW * 4, base, mTextPaint); + + canvas.drawRect(itemW * 5, mHeaderPaddingTop, (itemW * 6) - 1, bottom, + mTextBackgroundPaint); + canvas.drawRect(itemW * 5, mHeaderPaddingTop, + (itemW * 5) + (ps.mCoords.pressure * itemW) - 1, bottom, mTextLevelPaint); + canvas.drawText(mText.clear() + .append("Prs: ").append(ps.mCoords.pressure, 2) + .toString(), 1 + itemW * 5, base, mTextPaint); + + canvas.drawRect(itemW * 6, mHeaderPaddingTop, w, bottom, mTextBackgroundPaint); + canvas.drawRect(itemW * 6, mHeaderPaddingTop, + (itemW * 6) + (ps.mCoords.size * itemW) - 1, bottom, mTextLevelPaint); + canvas.drawText(mText.clear() + .append("Size: ").append(ps.mCoords.size, 2) + .toString(), 1 + itemW * 6, base, mTextPaint); + canvas.restore(); + } + private void logMotionEvent(String type, MotionEvent event) { final int action = event.getAction(); final int N = event.getHistorySize(); diff --git a/core/jni/Android.bp b/core/jni/Android.bp index 7b825298acde..05d8c98f575e 100644 --- a/core/jni/Android.bp +++ b/core/jni/Android.bp @@ -226,6 +226,7 @@ cc_library_shared { "fd_utils.cpp", "android_hardware_input_InputWindowHandle.cpp", "android_hardware_input_InputApplicationHandle.cpp", + "android_window_WindowInfosListener.cpp", ], static_libs: [ @@ -233,15 +234,19 @@ cc_library_shared { "libbinderthreadstateutils", "libdmabufinfo", "libgif", + "libgui_window_info_static", "libseccomp_policy", "libgrallocusage", "libscrypt_static", "libstatssocket_lazy", + "libskia", ], shared_libs: [ "audioclient-types-aidl-cpp", "audioflinger-aidl-cpp", + "audiopolicy-types-aidl-cpp", + "spatializer-aidl-cpp", "av-types-aidl-cpp", "android.hardware.camera.device@3.2", "libandroidicu", @@ -372,6 +377,7 @@ cc_library_shared { "libinput", "libbinderthreadstateutils", "libsqlite", + "libgui_window_info_static", ], shared_libs: [ // libbinder needs to be shared since it has global state diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp index 268e462704b8..9d0715d6e82e 100644 --- a/core/jni/AndroidRuntime.cpp +++ b/core/jni/AndroidRuntime.cpp @@ -208,6 +208,7 @@ extern int register_com_android_internal_os_ZygoteCommandBuffer(JNIEnv *env); extern int register_com_android_internal_os_ZygoteInit(JNIEnv *env); extern int register_com_android_internal_security_VerityUtils(JNIEnv* env); extern int register_com_android_internal_util_VirtualRefBasePtr(JNIEnv *env); +extern int register_android_window_WindowInfosListener(JNIEnv* env); extern int register_com_android_internal_app_ActivityTrigger(JNIEnv *env); // Namespace for Android Runtime flags applied during boot time. @@ -1651,6 +1652,8 @@ static const RegJNIRec gRegJNI[] = { REG_JNI(register_com_android_internal_os_KernelCpuTotalBpfMapReader), REG_JNI(register_com_android_internal_os_KernelCpuUidBpfMapReader), REG_JNI(register_com_android_internal_os_KernelSingleUidTimeReader), + + REG_JNI(register_android_window_WindowInfosListener), REG_JNI(register_com_android_internal_app_ActivityTrigger), REG_JNI(register_com_android_internal_os_KernelSingleProcessCpuThreadReader), }; diff --git a/core/jni/OWNERS b/core/jni/OWNERS index 666ab957b8ce..af77cb7aae8d 100644 --- a/core/jni/OWNERS +++ b/core/jni/OWNERS @@ -22,6 +22,7 @@ per-file android_view_PointerIcon.* = file:/services/core/java/com/android/serve # WindowManager per-file android_graphics_BLASTBufferQueue.cpp = file:/services/core/java/com/android/server/wm/OWNERS per-file android_view_Surface* = file:/services/core/java/com/android/server/wm/OWNERS +per-file android_window_WindowInfosListener.cpp = file:/services/core/java/com/android/server/wm/OWNERS # Resources per-file android_content_res_* = file:/core/java/android/content/res/OWNERS diff --git a/core/jni/android_graphics_BLASTBufferQueue.cpp b/core/jni/android_graphics_BLASTBufferQueue.cpp index 5ffa2fd5e0c9..35b9c2beef3c 100644 --- a/core/jni/android_graphics_BLASTBufferQueue.cpp +++ b/core/jni/android_graphics_BLASTBufferQueue.cpp @@ -67,21 +67,19 @@ private: } }; -static jlong nativeCreate(JNIEnv* env, jclass clazz, jstring jName, jlong surfaceControl, - jlong width, jlong height, jint format) { - String8 str8; - if (jName) { - const jchar* str16 = env->GetStringCritical(jName, nullptr); - if (str16) { - str8 = String8(reinterpret_cast(str16), env->GetStringLength(jName)); - env->ReleaseStringCritical(jName, str16); - str16 = nullptr; - } - } - std::string name = str8.string(); +static jlong nativeCreate(JNIEnv* env, jclass clazz, jstring jName) { + ScopedUtfChars name(env, jName); + sp queue = new BLASTBufferQueue(name.c_str()); + queue->incStrong((void*)nativeCreate); + return reinterpret_cast(queue.get()); +} + +static jlong nativeCreateAndUpdate(JNIEnv* env, jclass clazz, jstring jName, jlong surfaceControl, + jlong width, jlong height, jint format) { + ScopedUtfChars name(env, jName); sp queue = - new BLASTBufferQueue(name, reinterpret_cast(surfaceControl), width, - height, format); + new BLASTBufferQueue(name.c_str(), reinterpret_cast(surfaceControl), + width, height, format); queue->incStrong((void*)nativeCreate); return reinterpret_cast(queue.get()); } @@ -124,11 +122,6 @@ static void nativeUpdate(JNIEnv* env, jclass clazz, jlong ptr, jlong surfaceCont transaction); } -static void nativeFlushShadowQueue(JNIEnv* env, jclass clazz, jlong ptr) { - sp queue = reinterpret_cast(ptr); - queue->flushShadowQueue(); -} - static void nativeMergeWithNextTransaction(JNIEnv*, jclass clazz, jlong ptr, jlong transactionPtr, jlong framenumber) { sp queue = reinterpret_cast(ptr); @@ -151,21 +144,27 @@ static void nativeSetTransactionCompleteCallback(JNIEnv* env, jclass clazz, jlon } } +static jlong nativeGetLastAcquiredFrameNum(JNIEnv* env, jclass clazz, jlong ptr) { + sp queue = reinterpret_cast(ptr); + return queue->getLastAcquiredFrameNum(); +} + static const JNINativeMethod gMethods[] = { /* name, signature, funcPtr */ // clang-format off - {"nativeCreate", "(Ljava/lang/String;JJJI)J", (void*)nativeCreate}, + {"nativeCreate", "(Ljava/lang/String;)J", (void*)nativeCreate}, + {"nativeCreateAndUpdate", "(Ljava/lang/String;JJJI)J", (void*)nativeCreateAndUpdate}, {"nativeGetSurface", "(JZ)Landroid/view/Surface;", (void*)nativeGetSurface}, {"nativeSetUndequeuedBufferCount", "(JI)V", (void*)nativeSetUndequeuedBufferCount}, {"nativeGetUndequeuedBufferCount", "(J)I", (void*)nativeGetUndequeuedBufferCount}, {"nativeDestroy", "(J)V", (void*)nativeDestroy}, {"nativeSetNextTransaction", "(JJ)V", (void*)nativeSetNextTransaction}, {"nativeUpdate", "(JJJJIJ)V", (void*)nativeUpdate}, - {"nativeFlushShadowQueue", "(J)V", (void*)nativeFlushShadowQueue}, {"nativeMergeWithNextTransaction", "(JJJ)V", (void*)nativeMergeWithNextTransaction}, {"nativeSetTransactionCompleteCallback", "(JJLandroid/graphics/BLASTBufferQueue$TransactionCompleteCallback;)V", - (void*)nativeSetTransactionCompleteCallback} + (void*)nativeSetTransactionCompleteCallback}, + {"nativeGetLastAcquiredFrameNum", "(J)J", (void*)nativeGetLastAcquiredFrameNum}, // clang-format on }; diff --git a/core/jni/android_hardware_input_InputApplicationHandle.cpp b/core/jni/android_hardware_input_InputApplicationHandle.cpp index 995bfa97ab2e..24d35316ef20 100644 --- a/core/jni/android_hardware_input_InputApplicationHandle.cpp +++ b/core/jni/android_hardware_input_InputApplicationHandle.cpp @@ -28,6 +28,8 @@ namespace android { static struct { + jclass clazz; + jmethodID ctor; jfieldID ptr; jfieldID name; jfieldID dispatchingTimeoutMillis; @@ -101,6 +103,15 @@ std::shared_ptr android_view_InputApplicationHandle_getH return *handle; } +jobject android_view_InputApplicationHandle_fromInputApplicationInfo( + JNIEnv* env, gui::InputApplicationInfo inputApplicationInfo) { + jobject binderObject = javaObjectForIBinder(env, inputApplicationInfo.token); + ScopedLocalRef name(env, env->NewStringUTF(inputApplicationInfo.name.data())); + return env->NewObject(gInputApplicationHandleClassInfo.clazz, + gInputApplicationHandleClassInfo.ctor, binderObject, name.get(), + inputApplicationInfo.dispatchingTimeoutMillis); +} + // --- JNI --- static void android_view_InputApplicationHandle_nativeDispose(JNIEnv* env, jobject obj) { @@ -131,6 +142,10 @@ static const JNINativeMethod gInputApplicationHandleMethods[] = { var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \ LOG_FATAL_IF(! (var), "Unable to find field " fieldName); +#define GET_METHOD_ID(var, clazz, methodName, methodSignature) \ + var = env->GetMethodID(clazz, methodName, methodSignature); \ + LOG_ALWAYS_FATAL_IF(!(var), "Unable to find method " methodName); + int register_android_view_InputApplicationHandle(JNIEnv* env) { int res = jniRegisterNativeMethods(env, "android/view/InputApplicationHandle", gInputApplicationHandleMethods, NELEM(gInputApplicationHandleMethods)); @@ -139,6 +154,10 @@ int register_android_view_InputApplicationHandle(JNIEnv* env) { jclass clazz; FIND_CLASS(clazz, "android/view/InputApplicationHandle"); + gInputApplicationHandleClassInfo.clazz = MakeGlobalRefOrDie(env, clazz); + + GET_METHOD_ID(gInputApplicationHandleClassInfo.ctor, clazz, "", + "(Landroid/os/IBinder;Ljava/lang/String;J)V"); GET_FIELD_ID(gInputApplicationHandleClassInfo.ptr, clazz, "ptr", "J"); diff --git a/core/jni/android_hardware_input_InputApplicationHandle.h b/core/jni/android_hardware_input_InputApplicationHandle.h index ec99d6da5b8e..5d88d8e25160 100644 --- a/core/jni/android_hardware_input_InputApplicationHandle.h +++ b/core/jni/android_hardware_input_InputApplicationHandle.h @@ -19,7 +19,7 @@ #include -#include +#include #include #include "jni.h" @@ -42,6 +42,9 @@ private: extern std::shared_ptr android_view_InputApplicationHandle_getHandle( JNIEnv* env, jobject inputApplicationHandleObj); +extern jobject android_view_InputApplicationHandle_fromInputApplicationInfo( + JNIEnv* env, gui::InputApplicationInfo inputApplicationInfo); + } // namespace android #endif // _ANDROID_VIEW_INPUT_APPLICATION_HANDLE_H diff --git a/core/jni/android_hardware_input_InputWindowHandle.cpp b/core/jni/android_hardware_input_InputWindowHandle.cpp index 463d909821b1..29887067456a 100644 --- a/core/jni/android_hardware_input_InputWindowHandle.cpp +++ b/core/jni/android_hardware_input_InputWindowHandle.cpp @@ -26,14 +26,20 @@ #include #include +#include +#include +#include "SkRegion.h" #include "android_hardware_input_InputApplicationHandle.h" #include "android_util_Binder.h" #include "core_jni_helpers.h" -#include "input/InputWindow.h" +#include "gui/WindowInfo.h" #include "jni.h" namespace android { +using gui::TouchOcclusionMode; +using gui::WindowInfo; + struct WeakRefHandleField { jfieldID ctrl; jmethodID get; @@ -41,6 +47,8 @@ struct WeakRefHandleField { }; static struct { + jclass clazz; + jmethodID ctor; jfieldID ptr; jfieldID inputApplicationHandle; jfieldID token; @@ -66,11 +74,18 @@ static struct { jfieldID packageName; jfieldID inputFeatures; jfieldID displayId; - jfieldID portalToDisplayId; jfieldID replaceTouchableRegionWithCrop; WeakRefHandleField touchableRegionSurfaceControl; + jfieldID transform; + jfieldID windowToken; } gInputWindowHandleClassInfo; +static struct { + jclass clazz; + jmethodID ctor; + jfieldID nativeRegion; +} gRegionClassInfo; + static Mutex gHandleMutex; @@ -115,9 +130,9 @@ bool NativeInputWindowHandle::updateInfo() { mInfo.name = getStringField(env, obj, gInputWindowHandleClassInfo.name, ""); - mInfo.flags = Flags( + mInfo.flags = Flags( env->GetIntField(obj, gInputWindowHandleClassInfo.layoutParamsFlags)); - mInfo.type = static_cast( + mInfo.type = static_cast( env->GetIntField(obj, gInputWindowHandleClassInfo.layoutParamsType)); mInfo.dispatchingTimeout = std::chrono::milliseconds( env->GetLongField(obj, gInputWindowHandleClassInfo.dispatchingTimeoutMillis)); @@ -159,12 +174,10 @@ bool NativeInputWindowHandle::updateInfo() { mInfo.ownerUid = env->GetIntField(obj, gInputWindowHandleClassInfo.ownerUid); mInfo.packageName = getStringField(env, obj, gInputWindowHandleClassInfo.packageName, ""); - mInfo.inputFeatures = static_cast( + mInfo.inputFeatures = static_cast( env->GetIntField(obj, gInputWindowHandleClassInfo.inputFeatures)); mInfo.displayId = env->GetIntField(obj, gInputWindowHandleClassInfo.displayId); - mInfo.portalToDisplayId = env->GetIntField(obj, - gInputWindowHandleClassInfo.portalToDisplayId); jobject inputApplicationHandleObj = env->GetObjectField(obj, gInputWindowHandleClassInfo.inputApplicationHandle); @@ -204,6 +217,14 @@ bool NativeInputWindowHandle::updateInfo() { mInfo.touchableRegionCropHandle.clear(); } + jobject windowTokenObj = env->GetObjectField(obj, gInputWindowHandleClassInfo.windowToken); + if (windowTokenObj) { + mInfo.windowToken = ibinderForJavaObject(env, windowTokenObj); + env->DeleteLocalRef(windowTokenObj); + } else { + mInfo.windowToken.clear(); + } + env->DeleteLocalRef(obj); return true; } @@ -233,6 +254,81 @@ sp android_view_InputWindowHandle_getHandle( return handle; } +jobject android_view_InputWindowHandle_fromWindowInfo(JNIEnv* env, gui::WindowInfo windowInfo) { + ScopedLocalRef + applicationHandle(env, + android_view_InputApplicationHandle_fromInputApplicationInfo( + env, windowInfo.applicationInfo)); + + jobject inputWindowHandle = + env->NewObject(gInputWindowHandleClassInfo.clazz, gInputWindowHandleClassInfo.ctor, + applicationHandle.get(), windowInfo.displayId); + env->SetObjectField(inputWindowHandle, gInputWindowHandleClassInfo.token, + javaObjectForIBinder(env, windowInfo.token)); + env->SetObjectField(inputWindowHandle, gInputWindowHandleClassInfo.name, + env->NewStringUTF(windowInfo.name.data())); + env->SetIntField(inputWindowHandle, gInputWindowHandleClassInfo.layoutParamsFlags, + static_cast(windowInfo.flags.get())); + env->SetIntField(inputWindowHandle, gInputWindowHandleClassInfo.layoutParamsType, + static_cast(windowInfo.type)); + env->SetLongField(inputWindowHandle, gInputWindowHandleClassInfo.dispatchingTimeoutMillis, + std::chrono::duration_cast( + windowInfo.dispatchingTimeout) + .count()); + env->SetIntField(inputWindowHandle, gInputWindowHandleClassInfo.frameLeft, + windowInfo.frameLeft); + env->SetIntField(inputWindowHandle, gInputWindowHandleClassInfo.frameTop, windowInfo.frameTop); + env->SetIntField(inputWindowHandle, gInputWindowHandleClassInfo.frameRight, + windowInfo.frameRight); + env->SetIntField(inputWindowHandle, gInputWindowHandleClassInfo.frameBottom, + windowInfo.frameBottom); + env->SetIntField(inputWindowHandle, gInputWindowHandleClassInfo.surfaceInset, + windowInfo.surfaceInset); + env->SetFloatField(inputWindowHandle, gInputWindowHandleClassInfo.scaleFactor, + windowInfo.globalScaleFactor); + + SkRegion* region = new SkRegion(); + for (const auto& r : windowInfo.touchableRegion) { + region->op({r.left, r.top, r.right, r.bottom}, SkRegion::kUnion_Op); + } + ScopedLocalRef regionObj(env, + env->NewObject(gRegionClassInfo.clazz, + gRegionClassInfo.ctor)); + env->SetLongField(regionObj.get(), gRegionClassInfo.nativeRegion, + reinterpret_cast(region)); + env->SetObjectField(inputWindowHandle, gInputWindowHandleClassInfo.touchableRegion, + regionObj.get()); + + env->SetBooleanField(inputWindowHandle, gInputWindowHandleClassInfo.visible, + windowInfo.visible); + env->SetBooleanField(inputWindowHandle, gInputWindowHandleClassInfo.focusable, + windowInfo.focusable); + env->SetBooleanField(inputWindowHandle, gInputWindowHandleClassInfo.hasWallpaper, + windowInfo.hasWallpaper); + env->SetBooleanField(inputWindowHandle, gInputWindowHandleClassInfo.paused, windowInfo.paused); + env->SetBooleanField(inputWindowHandle, gInputWindowHandleClassInfo.trustedOverlay, + windowInfo.trustedOverlay); + env->SetIntField(inputWindowHandle, gInputWindowHandleClassInfo.touchOcclusionMode, + static_cast(windowInfo.touchOcclusionMode)); + env->SetIntField(inputWindowHandle, gInputWindowHandleClassInfo.ownerPid, windowInfo.ownerPid); + env->SetIntField(inputWindowHandle, gInputWindowHandleClassInfo.ownerUid, windowInfo.ownerUid); + env->SetObjectField(inputWindowHandle, gInputWindowHandleClassInfo.packageName, + env->NewStringUTF(windowInfo.packageName.data())); + env->SetIntField(inputWindowHandle, gInputWindowHandleClassInfo.inputFeatures, + static_cast(windowInfo.inputFeatures.get())); + + float transformVals[9]; + for (int i = 0; i < 9; i++) { + transformVals[i] = windowInfo.transform[i % 3][i / 3]; + } + ScopedLocalRef matrixObj(env, AMatrix_newInstance(env, transformVals)); + env->SetObjectField(inputWindowHandle, gInputWindowHandleClassInfo.transform, matrixObj.get()); + + env->SetObjectField(inputWindowHandle, gInputWindowHandleClassInfo.windowToken, + javaObjectForIBinder(env, windowInfo.windowToken)); + + return inputWindowHandle; +} // --- JNI --- @@ -275,6 +371,10 @@ int register_android_view_InputWindowHandle(JNIEnv* env) { jclass clazz; FIND_CLASS(clazz, "android/view/InputWindowHandle"); + gInputWindowHandleClassInfo.clazz = MakeGlobalRefOrDie(env, clazz); + + GET_METHOD_ID(gInputWindowHandleClassInfo.ctor, clazz, "", + "(Landroid/view/InputApplicationHandle;I)V"); GET_FIELD_ID(gInputWindowHandleClassInfo.ptr, clazz, "ptr", "J"); @@ -348,12 +448,15 @@ int register_android_view_InputWindowHandle(JNIEnv* env) { GET_FIELD_ID(gInputWindowHandleClassInfo.displayId, clazz, "displayId", "I"); - GET_FIELD_ID(gInputWindowHandleClassInfo.portalToDisplayId, clazz, - "portalToDisplayId", "I"); - GET_FIELD_ID(gInputWindowHandleClassInfo.replaceTouchableRegionWithCrop, clazz, "replaceTouchableRegionWithCrop", "Z"); + GET_FIELD_ID(gInputWindowHandleClassInfo.transform, clazz, "transform", + "Landroid/graphics/Matrix;"); + + GET_FIELD_ID(gInputWindowHandleClassInfo.windowToken, clazz, "windowToken", + "Landroid/os/IBinder;"); + jclass weakRefClazz; FIND_CLASS(weakRefClazz, "java/lang/ref/Reference"); @@ -368,6 +471,11 @@ int register_android_view_InputWindowHandle(JNIEnv* env) { GET_FIELD_ID(gInputWindowHandleClassInfo.touchableRegionSurfaceControl.mNativeObject, surfaceControlClazz, "mNativeObject", "J"); + jclass regionClazz; + FIND_CLASS(regionClazz, "android/graphics/Region"); + gRegionClassInfo.clazz = MakeGlobalRefOrDie(env, regionClazz); + GET_METHOD_ID(gRegionClassInfo.ctor, gRegionClassInfo.clazz, "", "()V"); + GET_FIELD_ID(gRegionClassInfo.nativeRegion, gRegionClassInfo.clazz, "mNativeRegion", "J"); return 0; } diff --git a/core/jni/android_hardware_input_InputWindowHandle.h b/core/jni/android_hardware_input_InputWindowHandle.h index de5bd6ef97f4..408e0f1bfa36 100644 --- a/core/jni/android_hardware_input_InputWindowHandle.h +++ b/core/jni/android_hardware_input_InputWindowHandle.h @@ -17,14 +17,14 @@ #ifndef _ANDROID_VIEW_INPUT_WINDOW_HANDLE_H #define _ANDROID_VIEW_INPUT_WINDOW_HANDLE_H -#include +#include #include #include "jni.h" namespace android { -class NativeInputWindowHandle : public InputWindowHandle { +class NativeInputWindowHandle : public gui::WindowInfoHandle { public: NativeInputWindowHandle(jweak objWeak); virtual ~NativeInputWindowHandle(); @@ -37,10 +37,12 @@ private: jweak mObjWeak; }; - extern sp android_view_InputWindowHandle_getHandle( JNIEnv* env, jobject inputWindowHandleObj); +extern jobject android_view_InputWindowHandle_fromWindowInfo(JNIEnv* env, + gui::WindowInfo windowInfo); + } // namespace android #endif // _ANDROID_VIEW_INPUT_WINDOW_HANDLE_H diff --git a/core/jni/android_media_AudioDeviceAttributes.cpp b/core/jni/android_media_AudioDeviceAttributes.cpp index 2a16dce99125..6879a6008f5a 100644 --- a/core/jni/android_media_AudioDeviceAttributes.cpp +++ b/core/jni/android_media_AudioDeviceAttributes.cpp @@ -24,6 +24,11 @@ using namespace android; static jclass gAudioDeviceAttributesClass; static jmethodID gAudioDeviceAttributesCstor; +static struct { + jfieldID mAddress; + jfieldID mNativeType; + // other fields unused by JNI +} gAudioDeviceAttributesFields; namespace android { @@ -33,12 +38,25 @@ jint createAudioDeviceAttributesFromNative(JNIEnv *env, jobject *jAudioDeviceAtt jint jNativeType = (jint)devTypeAddr->mType; ScopedLocalRef jAddress(env, env->NewStringUTF(devTypeAddr->getAddress())); - *jAudioDeviceAttributes = env->NewObject(gAudioDeviceAttributesClass, gAudioDeviceAttributesCstor, - jNativeType, jAddress.get()); + *jAudioDeviceAttributes = + env->NewObject(gAudioDeviceAttributesClass, gAudioDeviceAttributesCstor, + jNativeType, jAddress.get()); return jStatus; } +jint createAudioDeviceTypeAddrFromJava(JNIEnv *env, AudioDeviceTypeAddr *devTypeAddr, + const jobject jAudioDeviceAttributes) { + devTypeAddr->mType = (audio_devices_t)env->GetIntField(jAudioDeviceAttributes, + gAudioDeviceAttributesFields.mNativeType); + + jstring jAddress = (jstring)env->GetObjectField(jAudioDeviceAttributes, + gAudioDeviceAttributesFields.mAddress); + devTypeAddr->setAddress(ScopedUtfChars(env, jAddress).c_str()); + + return AUDIO_JAVA_SUCCESS; +} + } // namespace android int register_android_media_AudioDeviceAttributes(JNIEnv *env) { @@ -48,5 +66,10 @@ int register_android_media_AudioDeviceAttributes(JNIEnv *env) { gAudioDeviceAttributesCstor = GetMethodIDOrDie(env, audioDeviceTypeAddressClass, "", "(ILjava/lang/String;)V"); + gAudioDeviceAttributesFields.mNativeType = + GetFieldIDOrDie(env, gAudioDeviceAttributesClass, "mNativeType", "I"); + gAudioDeviceAttributesFields.mAddress = + GetFieldIDOrDie(env, gAudioDeviceAttributesClass, "mAddress", "Ljava/lang/String;"); + return 0; } diff --git a/core/jni/android_media_AudioDeviceAttributes.h b/core/jni/android_media_AudioDeviceAttributes.h index b49d9ba515b8..4a1f40d9bb7c 100644 --- a/core/jni/android_media_AudioDeviceAttributes.h +++ b/core/jni/android_media_AudioDeviceAttributes.h @@ -28,6 +28,9 @@ namespace android { extern jint createAudioDeviceAttributesFromNative(JNIEnv *env, jobject *jAudioDeviceAttributes, const AudioDeviceTypeAddr *devTypeAddr); + +extern jint createAudioDeviceTypeAddrFromJava(JNIEnv *env, AudioDeviceTypeAddr *devTypeAddr, + const jobject jAudioDeviceAttributes); } // namespace android #endif \ No newline at end of file diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp index 4b93363b5b90..509b7ad74a29 100644 --- a/core/jni/android_media_AudioSystem.cpp +++ b/core/jni/android_media_AudioSystem.cpp @@ -27,6 +27,8 @@ #include "core_jni_helpers.h" #include +#include +#include #include #include #include @@ -207,6 +209,7 @@ static struct { jmethodID getId; jmethodID getResonantFrequency; jmethodID getQFactor; + jmethodID getMaxAmplitude; } gVibratorMethods; static Mutex gLock; @@ -2022,6 +2025,18 @@ android_media_AudioSystem_registerRoutingCallback(JNIEnv *env, jobject thiz) AudioSystem::setRoutingCallback(android_media_AudioSystem_routing_callback); } +void javaAudioFormatToNativeAudioConfig(JNIEnv *env, audio_config_t *nConfig, + const jobject jFormat, bool isInput) { + *nConfig = AUDIO_CONFIG_INITIALIZER; + nConfig->format = audioFormatToNative(env->GetIntField(jFormat, gAudioFormatFields.mEncoding)); + nConfig->sample_rate = env->GetIntField(jFormat, gAudioFormatFields.mSampleRate); + jint jChannelMask = env->GetIntField(jFormat, gAudioFormatFields.mChannelMask); + if (isInput) { + nConfig->channel_mask = inChannelMaskToNative(jChannelMask); + } else { + nConfig->channel_mask = outChannelMaskToNative(jChannelMask); + } +} static jint convertAudioMixToNative(JNIEnv *env, AudioMix *nAudioMix, @@ -2042,13 +2057,7 @@ static jint convertAudioMixToNative(JNIEnv *env, nAudioMix->mCbFlags = env->GetIntField(jAudioMix, gAudioMixFields.mCallbackFlags); jobject jFormat = env->GetObjectField(jAudioMix, gAudioMixFields.mFormat); - nAudioMix->mFormat = AUDIO_CONFIG_INITIALIZER; - nAudioMix->mFormat.sample_rate = env->GetIntField(jFormat, - gAudioFormatFields.mSampleRate); - nAudioMix->mFormat.channel_mask = outChannelMaskToNative(env->GetIntField(jFormat, - gAudioFormatFields.mChannelMask)); - nAudioMix->mFormat.format = audioFormatToNative(env->GetIntField(jFormat, - gAudioFormatFields.mEncoding)); + javaAudioFormatToNativeAudioConfig(env, &nAudioMix->mFormat, jFormat, false /*isInput*/); env->DeleteLocalRef(jFormat); jobject jRule = env->GetObjectField(jAudioMix, gAudioMixFields.mRule); @@ -2704,11 +2713,65 @@ static jint android_media_AudioSystem_setVibratorInfos(JNIEnv *env, jobject thiz vibratorInfo.resonantFrequency = env->CallFloatMethod(jVibrator.get(), gVibratorMethods.getResonantFrequency); vibratorInfo.qFactor = env->CallFloatMethod(jVibrator.get(), gVibratorMethods.getQFactor); + vibratorInfo.maxAmplitude = + env->CallFloatMethod(jVibrator.get(), gVibratorMethods.getMaxAmplitude); vibratorInfos.push_back(vibratorInfo); } return (jint)check_AudioSystem_Command(AudioSystem::setVibratorInfos(vibratorInfos)); } +static jobject android_media_AudioSystem_getSpatializer(JNIEnv *env, jobject thiz, + jobject jISpatializerCallback) { + sp nISpatializerCallback + = interface_cast( + ibinderForJavaObject(env, jISpatializerCallback)); + sp nSpatializer; + status_t status = AudioSystem::getSpatializer(nISpatializerCallback, + &nSpatializer); + if (status != NO_ERROR) { + return nullptr; + } + return javaObjectForIBinder(env, IInterface::asBinder(nSpatializer)); +} + +static jboolean android_media_AudioSystem_canBeSpatialized(JNIEnv *env, jobject thiz, + jobject jaa, jobject jFormat, + jobjectArray jDeviceArray) { + JNIAudioAttributeHelper::UniqueAaPtr paa = JNIAudioAttributeHelper::makeUnique(); + jint jStatus = JNIAudioAttributeHelper::nativeFromJava(env, jaa, paa.get()); + if (jStatus != (jint)AUDIO_JAVA_SUCCESS) { + return false; + } + + AudioDeviceTypeAddrVector nDevices; + + const size_t numDevices = env->GetArrayLength(jDeviceArray); + for (size_t i = 0; i < numDevices; ++i) { + AudioDeviceTypeAddr device; + jobject jDevice = env->GetObjectArrayElement(jDeviceArray, i); + if (jDevice == nullptr) { + return false; + } + jStatus = createAudioDeviceTypeAddrFromJava(env, &device, jDevice); + if (jStatus != (jint)AUDIO_JAVA_SUCCESS) { + return false; + } + nDevices.push_back(device); + } + + audio_config_t nConfig; + javaAudioFormatToNativeAudioConfig(env, &nConfig, jFormat, false /*isInput*/); + + bool canBeSpatialized; + status_t status = + AudioSystem::canBeSpatialized(paa.get(), &nConfig, nDevices, &canBeSpatialized); + if (status != NO_ERROR) { + ALOGW("%s native returned error %d", __func__, status); + return false; + } + return canBeSpatialized; +} + // ---------------------------------------------------------------------------- static const JNINativeMethod gMethods[] = @@ -2845,7 +2908,15 @@ static const JNINativeMethod gMethods[] = (void *)android_media_AudioSystem_removeUserIdDeviceAffinities}, {"setCurrentImeUid", "(I)I", (void *)android_media_AudioSystem_setCurrentImeUid}, {"setVibratorInfos", "(Ljava/util/List;)I", - (void *)android_media_AudioSystem_setVibratorInfos}}; + (void *)android_media_AudioSystem_setVibratorInfos}, + {"nativeGetSpatializer", + "(Landroid/media/INativeSpatializerCallback;)Landroid/os/IBinder;", + (void *)android_media_AudioSystem_getSpatializer}, + {"canBeSpatialized", + "(Landroid/media/AudioAttributes;Landroid/media/AudioFormat;" + "[Landroid/media/AudioDeviceAttributes;)Z", + (void *)android_media_AudioSystem_canBeSpatialized}}; + static const JNINativeMethod gEventHandlerMethods[] = { {"native_setup", @@ -3070,6 +3141,8 @@ int register_android_media_AudioSystem(JNIEnv *env) gVibratorMethods.getResonantFrequency = GetMethodIDOrDie(env, vibratorClass, "getResonantFrequency", "()F"); gVibratorMethods.getQFactor = GetMethodIDOrDie(env, vibratorClass, "getQFactor", "()F"); + gVibratorMethods.getMaxAmplitude = + GetMethodIDOrDie(env, vibratorClass, "getHapticChannelMaximumAmplitude", "()F"); AudioSystem::addErrorCallback(android_media_AudioSystem_error_callback); diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp index 4c2b114c724a..5e0d9b32380c 100644 --- a/core/jni/android_os_Debug.cpp +++ b/core/jni/android_os_Debug.cpp @@ -34,6 +34,7 @@ #include #include +#include #include #include #include @@ -859,7 +860,22 @@ static jlong android_os_Debug_getDmabufHeapPoolsSizeKb(JNIEnv* env, jobject claz return poolsSizeKb; } +static bool halSupportsGpuPrivateMemory() { + int productApiLevel = + android::base::GetIntProperty("ro.product.first_api_level", + android::base::GetIntProperty("ro.build.version.sdk", + __ANDROID_API_FUTURE__)); + int boardApiLevel = + android::base::GetIntProperty("ro.board.api_level", + android::base::GetIntProperty("ro.board.first_api_level", + __ANDROID_API_FUTURE__)); + + return std::min(productApiLevel, boardApiLevel) >= __ANDROID_API_S__; +} + static jlong android_os_Debug_getGpuPrivateMemoryKb(JNIEnv* env, jobject clazz) { + static bool gpuPrivateMemorySupported = halSupportsGpuPrivateMemory(); + struct memtrack_proc* p = memtrack_proc_new(); if (p == nullptr) { LOG(ERROR) << "getGpuPrivateMemoryKb: Failed to create memtrack_proc"; @@ -876,6 +892,12 @@ static jlong android_os_Debug_getGpuPrivateMemoryKb(JNIEnv* env, jobject clazz) ssize_t gpuPrivateMem = memtrack_proc_gl_pss(p); memtrack_proc_destroy(p); + + // Old HAL implementations may return 0 for GPU private memory if not supported + if (gpuPrivateMem == 0 && !gpuPrivateMemorySupported) { + return -1; + } + return gpuPrivateMem / 1024; } diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp index e93b00d7b148..86d781033e5e 100644 --- a/core/jni/android_util_AssetManager.cpp +++ b/core/jni/android_util_AssetManager.cpp @@ -92,6 +92,7 @@ static struct configuration_offsets_t { jfieldID mSmallestScreenWidthDpOffset; jfieldID mScreenWidthDpOffset; jfieldID mScreenHeightDpOffset; + jfieldID mScreenLayoutOffset; } gConfigurationOffsets; static struct arraymap_offsets_t { @@ -1019,6 +1020,7 @@ static jobject ConstructConfigurationObject(JNIEnv* env, const ResTable_config& config.smallestScreenWidthDp); env->SetIntField(result, gConfigurationOffsets.mScreenWidthDpOffset, config.screenWidthDp); env->SetIntField(result, gConfigurationOffsets.mScreenHeightDpOffset, config.screenHeightDp); + env->SetIntField(result, gConfigurationOffsets.mScreenLayoutOffset, config.screenLayout); return result; } @@ -1553,6 +1555,8 @@ int register_android_content_AssetManager(JNIEnv* env) { GetFieldIDOrDie(env, configurationClass, "screenWidthDp", "I"); gConfigurationOffsets.mScreenHeightDpOffset = GetFieldIDOrDie(env, configurationClass, "screenHeightDp", "I"); + gConfigurationOffsets.mScreenLayoutOffset = + GetFieldIDOrDie(env, configurationClass, "screenLayout", "I"); jclass arrayMapClass = FindClassOrDie(env, "android/util/ArrayMap"); gArrayMapOffsets.classObject = MakeGlobalRefOrDie(env, arrayMapClass); diff --git a/core/jni/android_view_InputEventSender.cpp b/core/jni/android_view_InputEventSender.cpp index 45e3d1b97e83..16366a4e5bec 100644 --- a/core/jni/android_view_InputEventSender.cpp +++ b/core/jni/android_view_InputEventSender.cpp @@ -155,6 +155,7 @@ status_t NativeInputEventSender::sendMotionEvent(uint32_t seq, const MotionEvent event->getYPrecision(), event->getRawXCursorPosition(), event->getRawYCursorPosition(), + event->getDisplayOrientation(), event->getDisplaySize().x, event->getDisplaySize().y, event->getDownTime(), event->getHistoricalEventTime(i), diff --git a/core/jni/android_view_MotionEvent.cpp b/core/jni/android_view_MotionEvent.cpp index 6971301cec32..cabf3abe350a 100644 --- a/core/jni/android_view_MotionEvent.cpp +++ b/core/jni/android_view_MotionEvent.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -56,6 +57,8 @@ static struct { jfieldID toolMajor; jfieldID toolMinor; jfieldID orientation; + jfieldID relativeX; + jfieldID relativeY; } gPointerCoordsClassInfo; static struct { @@ -212,6 +215,12 @@ static void pointerCoordsToNative(JNIEnv* env, jobject pointerCoordsObj, env->GetFloatField(pointerCoordsObj, gPointerCoordsClassInfo.toolMinor)); outRawPointerCoords->setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, env->GetFloatField(pointerCoordsObj, gPointerCoordsClassInfo.orientation)); + outRawPointerCoords->setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, + env->GetFloatField(pointerCoordsObj, + gPointerCoordsClassInfo.relativeX)); + outRawPointerCoords->setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, + env->GetFloatField(pointerCoordsObj, + gPointerCoordsClassInfo.relativeY)); BitSet64 bits = BitSet64(env->GetLongField(pointerCoordsObj, gPointerCoordsClassInfo.mPackedAxisBits)); @@ -261,6 +270,12 @@ static void pointerCoordsFromNative(JNIEnv* env, const PointerCoords* rawPointer float rawY = rawPointerCoords->getAxisValue(AMOTION_EVENT_AXIS_Y); vec2 transformed = transform.transform(rawX, rawY); + float rawRelX = rawPointerCoords->getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X); + float rawRelY = rawPointerCoords->getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y); + // Apply only rotation and scale, not translation. + const vec2 transformedOrigin = transform.transform(0, 0); + const vec2 transformedRel = transform.transform(rawRelX, rawRelY) - transformedOrigin; + env->SetFloatField(outPointerCoordsObj, gPointerCoordsClassInfo.x, transformed.x); env->SetFloatField(outPointerCoordsObj, gPointerCoordsClassInfo.y, transformed.y); env->SetFloatField(outPointerCoordsObj, gPointerCoordsClassInfo.pressure, @@ -277,6 +292,8 @@ static void pointerCoordsFromNative(JNIEnv* env, const PointerCoords* rawPointer rawPointerCoords->getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR)); env->SetFloatField(outPointerCoordsObj, gPointerCoordsClassInfo.orientation, rawPointerCoords->getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION)); + env->SetFloatField(outPointerCoordsObj, gPointerCoordsClassInfo.relativeX, transformedRel.x); + env->SetFloatField(outPointerCoordsObj, gPointerCoordsClassInfo.relativeY, transformedRel.y); uint64_t outBits = 0; BitSet64 bits = BitSet64(rawPointerCoords->bits); @@ -289,6 +306,8 @@ static void pointerCoordsFromNative(JNIEnv* env, const PointerCoords* rawPointer bits.clearBit(AMOTION_EVENT_AXIS_TOOL_MAJOR); bits.clearBit(AMOTION_EVENT_AXIS_TOOL_MINOR); bits.clearBit(AMOTION_EVENT_AXIS_ORIENTATION); + bits.clearBit(AMOTION_EVENT_AXIS_RELATIVE_X); + bits.clearBit(AMOTION_EVENT_AXIS_RELATIVE_Y); if (!bits.isEmpty()) { uint32_t packedAxesCount = bits.count(); jfloatArray outValuesArray = obtainPackedAxisValuesArray(env, packedAxesCount, @@ -378,8 +397,8 @@ static jlong android_view_MotionEvent_nativeInitialize( flags, edgeFlags, metaState, buttonState, static_cast(classification), transform, xPrecision, yPrecision, AMOTION_EVENT_INVALID_CURSOR_POSITION, - AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_DISPLAY_SIZE, - AMOTION_EVENT_INVALID_DISPLAY_SIZE, downTimeNanos, eventTimeNanos, + AMOTION_EVENT_INVALID_CURSOR_POSITION, ui::Transform::ROT_0, + INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE, downTimeNanos, eventTimeNanos, pointerCount, pointerProperties, rawPointerCoords); return reinterpret_cast(event.release()); @@ -872,6 +891,8 @@ int register_android_view_MotionEvent(JNIEnv* env) { gPointerCoordsClassInfo.toolMajor = GetFieldIDOrDie(env, clazz, "toolMajor", "F"); gPointerCoordsClassInfo.toolMinor = GetFieldIDOrDie(env, clazz, "toolMinor", "F"); gPointerCoordsClassInfo.orientation = GetFieldIDOrDie(env, clazz, "orientation", "F"); + gPointerCoordsClassInfo.relativeX = GetFieldIDOrDie(env, clazz, "relativeX", "F"); + gPointerCoordsClassInfo.relativeY = GetFieldIDOrDie(env, clazz, "relativeY", "F"); clazz = FindClassOrDie(env, "android/view/MotionEvent$PointerProperties"); diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp index 8d12df226ffe..1452c67ae3c6 100644 --- a/core/jni/android_view_SurfaceControl.cpp +++ b/core/jni/android_view_SurfaceControl.cpp @@ -62,6 +62,8 @@ namespace android { +using gui::FocusRequest; + static void doThrowNPE(JNIEnv* env) { jniThrowNullPointerException(env, NULL); } @@ -868,6 +870,13 @@ static void nativeSetFixedTransformHint(JNIEnv* env, jclass clazz, jlong transac transaction->setFixedTransformHint(ctrl, transformHint); } +static void nativeSetDropInputMode(JNIEnv* env, jclass clazz, jlong transactionObj, + jlong nativeObject, jint mode) { + auto transaction = reinterpret_cast(transactionObj); + SurfaceControl* const ctrl = reinterpret_cast(nativeObject); + transaction->setDropInputMode(ctrl, static_cast(mode)); +} + static jlongArray nativeGetPhysicalDisplayIds(JNIEnv* env, jclass clazz) { const auto displayIds = SurfaceComposerClient::getPhysicalDisplayIds(); jlongArray array = env->NewLongArray(displayIds.size()); @@ -889,6 +898,12 @@ static jlongArray nativeGetPhysicalDisplayIds(JNIEnv* env, jclass clazz) { return array; } +static jlong nativeGetPrimaryPhysicalDisplayId(JNIEnv* env, jclass clazz) { + PhysicalDisplayId displayId; + SurfaceComposerClient::getPrimaryPhysicalDisplayId(&displayId); + return static_cast(displayId.value); +} + static jobject nativeGetPhysicalDisplayToken(JNIEnv* env, jclass clazz, jlong physicalDisplayId) { sp token = SurfaceComposerClient::getPhysicalDisplayToken(PhysicalDisplayId(physicalDisplayId)); @@ -1014,6 +1029,17 @@ static void nativeSetDisplayLayerStack(JNIEnv* env, jclass clazz, } } +static void nativeSetDisplayFlags(JNIEnv* env, jclass clazz, jlong transactionObj, jobject tokenObj, + jint flags) { + sp token(ibinderForJavaObject(env, tokenObj)); + if (token == NULL) return; + + { + auto transaction = reinterpret_cast(transactionObj); + transaction->setDisplayFlags(token, flags); + } +} + static void nativeSetDisplayProjection(JNIEnv* env, jclass clazz, jlong transactionObj, jobject tokenObj, jint orientation, @@ -1789,16 +1815,18 @@ static void nativeSetTransformHint(JNIEnv* env, jclass clazz, jlong nativeSurfac if (surface == nullptr) { return; } - surface->setTransformHint( - ui::Transform::toRotationFlags(static_cast(transformHint))); + surface->setTransformHint(transformHint); } static jint nativeGetTransformHint(JNIEnv* env, jclass clazz, jlong nativeSurfaceControl) { sp surface(reinterpret_cast(nativeSurfaceControl)); - ui::Transform::RotationFlags transformHintRotationFlags = - static_cast(surface->getTransformHint()); + return surface->getTransformHint(); +} + +static jint nativeGetLayerId(JNIEnv* env, jclass clazz, jlong nativeSurfaceControl) { + sp surface(reinterpret_cast(nativeSurfaceControl)); - return toRotationInt(ui::Transform::toRotation((transformHintRotationFlags))); + return surface->getLayerId(); } // ---------------------------------------------------------------------------- @@ -1879,6 +1907,8 @@ static const JNINativeMethod sSurfaceControlMethods[] = { (void*)nativeReleaseFrameRateFlexibilityToken }, {"nativeGetPhysicalDisplayIds", "()[J", (void*)nativeGetPhysicalDisplayIds }, + {"nativeGetPrimaryPhysicalDisplayId", "()J", + (void*)nativeGetPrimaryPhysicalDisplayId }, {"nativeGetPhysicalDisplayToken", "(J)Landroid/os/IBinder;", (void*)nativeGetPhysicalDisplayToken }, {"nativeCreateDisplay", "(Ljava/lang/String;Z)Landroid/os/IBinder;", @@ -1889,6 +1919,8 @@ static const JNINativeMethod sSurfaceControlMethods[] = { (void*)nativeSetDisplaySurface }, {"nativeSetDisplayLayerStack", "(JLandroid/os/IBinder;I)V", (void*)nativeSetDisplayLayerStack }, + {"nativeSetDisplayFlags", "(JLandroid/os/IBinder;I)V", + (void*)nativeSetDisplayFlags }, {"nativeSetDisplayProjection", "(JLandroid/os/IBinder;IIIIIIIII)V", (void*)nativeSetDisplayProjection }, {"nativeSetDisplaySize", "(JLandroid/os/IBinder;II)V", @@ -1994,6 +2026,10 @@ static const JNINativeMethod sSurfaceControlMethods[] = { (void*)nativeGetTransformHint }, {"nativeSetTrustedOverlay", "(JJZ)V", (void*)nativeSetTrustedOverlay }, + {"nativeSetDropInputMode", "(JJI)V", + (void*)nativeSetDropInputMode }, + {"nativeGetLayerId", "(J)I", + (void*)nativeGetLayerId }, // clang-format on }; diff --git a/core/jni/android_window_WindowInfosListener.cpp b/core/jni/android_window_WindowInfosListener.cpp new file mode 100644 index 000000000000..ab88b537f96b --- /dev/null +++ b/core/jni/android_window_WindowInfosListener.cpp @@ -0,0 +1,134 @@ +/* + * Copyright 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "WindowInfosListener" + +#include +#include +#include +#include +#include + +#include "android_hardware_input_InputWindowHandle.h" +#include "core_jni_helpers.h" + +namespace android { + +using gui::WindowInfo; + +namespace { + +static struct { + jclass clazz; + jmethodID onWindowInfosChanged; +} gListenerClassInfo; + +static jclass gInputWindowHandleClass; + +struct WindowInfosListener : public gui::WindowInfosListener { + WindowInfosListener(JNIEnv* env, jobject listener) + : mListener(env->NewWeakGlobalRef(listener)) {} + + void onWindowInfosChanged(const std::vector& windowInfos) override { + JNIEnv* env = AndroidRuntime::getJNIEnv(); + LOG_ALWAYS_FATAL_IF(env == nullptr, "Unable to retrieve JNIEnv in onWindowInfoChanged."); + + jobject listener = env->NewGlobalRef(mListener); + if (listener == nullptr) { + // Weak reference went out of scope + return; + } + + jobjectArray jWindowHandlesArray = + env->NewObjectArray(windowInfos.size(), gInputWindowHandleClass, nullptr); + for (int i = 0; i < windowInfos.size(); i++) { + ScopedLocalRef + jWindowHandle(env, + android_view_InputWindowHandle_fromWindowInfo(env, + windowInfos[i])); + env->SetObjectArrayElement(jWindowHandlesArray, i, jWindowHandle.get()); + } + + env->CallVoidMethod(listener, gListenerClassInfo.onWindowInfosChanged, jWindowHandlesArray); + env->DeleteGlobalRef(listener); + + if (env->ExceptionCheck()) { + ALOGE("WindowInfosListener.onWindowInfosChanged() failed."); + LOGE_EX(env); + env->ExceptionClear(); + } + } + + ~WindowInfosListener() override { + JNIEnv* env = AndroidRuntime::getJNIEnv(); + env->DeleteWeakGlobalRef(mListener); + } + +private: + jweak mListener; +}; + +jlong nativeCreate(JNIEnv* env, jclass clazz, jobject obj) { + WindowInfosListener* listener = new WindowInfosListener(env, obj); + listener->incStrong((void*)nativeCreate); + return reinterpret_cast(listener); +} + +void destroyNativeService(void* ptr) { + WindowInfosListener* listener = reinterpret_cast(ptr); + listener->decStrong((void*)nativeCreate); +} + +void nativeRegister(JNIEnv* env, jclass clazz, jlong ptr) { + sp listener = reinterpret_cast(ptr); + SurfaceComposerClient::getDefault()->addWindowInfosListener(listener); +} + +void nativeUnregister(JNIEnv* env, jclass clazz, jlong ptr) { + sp listener = reinterpret_cast(ptr); + SurfaceComposerClient::getDefault()->removeWindowInfosListener(listener); +} + +static jlong nativeGetFinalizer(JNIEnv* /* env */, jclass /* clazz */) { + return static_cast(reinterpret_cast(&destroyNativeService)); +} + +const JNINativeMethod gMethods[] = { + /* name, signature, funcPtr */ + {"nativeCreate", "(Landroid/window/WindowInfosListener;)J", (void*)nativeCreate}, + {"nativeRegister", "(J)V", (void*)nativeRegister}, + {"nativeUnregister", "(J)V", (void*)nativeUnregister}, + {"nativeGetFinalizer", "()J", (void*)nativeGetFinalizer}}; + +} // namespace + +int register_android_window_WindowInfosListener(JNIEnv* env) { + int res = jniRegisterNativeMethods(env, "android/window/WindowInfosListener", gMethods, + NELEM(gMethods)); + LOG_ALWAYS_FATAL_IF(res < 0, "Unable to register native methods."); + + jclass clazz = env->FindClass("android/window/WindowInfosListener"); + gListenerClassInfo.clazz = MakeGlobalRefOrDie(env, clazz); + gListenerClassInfo.onWindowInfosChanged = + env->GetMethodID(gListenerClassInfo.clazz, "onWindowInfosChanged", + "([Landroid/view/InputWindowHandle;)V"); + + clazz = env->FindClass("android/view/InputWindowHandle"); + gInputWindowHandleClass = MakeGlobalRefOrDie(env, clazz); + return 0; +} + +} // namespace android diff --git a/core/proto/android/providers/settings/secure.proto b/core/proto/android/providers/settings/secure.proto index 1bba12ff7fa6..ba4a5b0ce222 100644 --- a/core/proto/android/providers/settings/secure.proto +++ b/core/proto/android/providers/settings/secure.proto @@ -79,7 +79,7 @@ message SecureSettingsProto { optional SettingProto accessibility_magnification_mode = 34 [ (android.privacy).dest = DEST_AUTOMATIC ]; optional SettingProto button_targets = 35 [ (android.privacy).dest = DEST_AUTOMATIC ]; optional SettingProto accessibility_magnification_capability = 36 [ (android.privacy).dest = DEST_AUTOMATIC ]; - // Settings for accessibility button mode (navigation bar or floating action menu). + // Settings for accessibility button related config optional SettingProto accessibility_button_mode = 37 [ (android.privacy).dest = DEST_AUTOMATIC ]; optional SettingProto accessibility_floating_menu_size = 38 [ (android.privacy).dest = DEST_AUTOMATIC ]; optional SettingProto accessibility_floating_menu_icon_type = 39 [ (android.privacy).dest = DEST_AUTOMATIC ]; diff --git a/core/proto/android/server/accessibilitytrace.proto b/core/proto/android/server/accessibilitytrace.proto index 1fc4a01936b1..41fecfd6cdb7 100644 --- a/core/proto/android/server/accessibilitytrace.proto +++ b/core/proto/android/server/accessibilitytrace.proto @@ -46,17 +46,17 @@ message AccessibilityTraceProto { /* required: elapsed realtime in nanos since boot of when this entry was logged */ optional fixed64 elapsed_realtime_nanos = 1; optional string calendar_time = 2; - - optional string process_name = 3; - optional string thread_id_name = 4; + repeated string logging_type = 3; + optional string process_name = 4; + optional string thread_id_name = 5; /* where the trace originated */ - optional string where = 5; + optional string where = 6; - optional string calling_pkg = 6; - optional string calling_params = 7; - optional string calling_stacks = 8; + optional string calling_pkg = 7; + optional string calling_params = 8; + optional string calling_stacks = 9; - optional AccessibilityDumpProto accessibility_service = 9; - optional com.android.server.wm.WindowManagerServiceDumpProto window_manager_service = 10; + optional AccessibilityDumpProto accessibility_service = 10; + optional com.android.server.wm.WindowManagerServiceDumpProto window_manager_service = 11; } diff --git a/core/proto/android/server/windowmanagerservice.proto b/core/proto/android/server/windowmanagerservice.proto index fa1e9d4afcdf..6faa04690473 100644 --- a/core/proto/android/server/windowmanagerservice.proto +++ b/core/proto/android/server/windowmanagerservice.proto @@ -69,6 +69,7 @@ message RootWindowContainerProto { // know what activity types to check for when invoking splitscreen multi-window. optional bool is_home_recents_component = 6; repeated IdentifierProto pending_activities = 7 [deprecated=true]; + optional int32 default_min_size_resizable_task = 8; } message BarControllerProto { @@ -201,7 +202,6 @@ message DisplayContentProto { optional .com.android.server.wm.IdentifierProto resumed_activity = 24; repeated TaskProto tasks = 25 [deprecated=true]; optional bool display_ready = 26; - optional WindowStateProto input_method_target = 27; optional WindowStateProto input_method_input_target = 28; optional WindowStateProto input_method_control_target = 29; @@ -211,6 +211,8 @@ message DisplayContentProto { optional DisplayRotationProto display_rotation = 33; optional int32 ime_policy = 34; + optional bool is_sleeping = 36; + repeated string sleep_tokens = 37; } /* represents DisplayArea object */ @@ -278,7 +280,7 @@ message PinnedTaskControllerProto { message TaskProto { option (.android.msg_privacy).dest = DEST_AUTOMATIC; - optional WindowContainerProto window_container = 1; + optional WindowContainerProto window_container = 1 [deprecated=true]; optional int32 id = 2; reserved 3; // activity optional bool fills_parent = 4; @@ -295,12 +297,12 @@ message TaskProto { optional string real_activity = 13; optional string orig_activity = 14; - optional int32 display_id = 15; + optional int32 display_id = 15 [deprecated=true]; optional int32 root_task_id = 16; - optional int32 activity_type = 17 [(.android.typedef) = "android.app.WindowConfiguration.ActivityType"]; + optional int32 activity_type = 17 [(.android.typedef) = "android.app.WindowConfiguration.ActivityType", deprecated=true] ; optional int32 resize_mode = 18 [(.android.typedef) = "android.appwidget.AppWidgetProviderInfo.ResizeModeFlags"]; - optional int32 min_width = 19; - optional int32 min_height = 20; + optional int32 min_width = 19 [deprecated=true]; + optional int32 min_height = 20 [deprecated=true]; optional .android.graphics.RectProto adjusted_bounds = 21; optional .android.graphics.RectProto last_non_fullscreen_bounds = 22; @@ -312,6 +314,18 @@ message TaskProto { optional bool created_by_organizer = 28; optional string affinity = 29; optional bool has_child_pip_activity = 30; + optional TaskFragmentProto task_fragment = 31; +} + +/* represents TaskFragment */ +message TaskFragmentProto { + option (.android.msg_privacy).dest = DEST_AUTOMATIC; + + optional WindowContainerProto window_container = 1; + optional int32 display_id = 2; + optional int32 activity_type = 3 [(.android.typedef) = "android.app.WindowConfiguration.ActivityType"]; + optional int32 min_width = 4; + optional int32 min_height = 5; } /* represents ActivityRecordProto */ @@ -351,6 +365,8 @@ message ActivityRecordProto { optional bool translucent = 30; optional bool pip_auto_enter_enabled = 31; optional bool in_size_compat_mode = 32; + optional float min_aspect_ratio = 33; + optional bool provides_max_bounds = 34; } /* represents WindowToken */ @@ -468,6 +484,7 @@ message WindowContainerProto { optional SurfaceAnimatorProto surface_animator = 4; repeated WindowContainerChildProto children = 5; optional IdentifierProto identifier = 6; + optional .android.view.SurfaceControlProto surface_control = 7; } /* represents a generic child of a WindowContainer */ @@ -493,6 +510,8 @@ message WindowContainerChildProto { optional WindowTokenProto window_token = 7; /* represents a WindowState child */ optional WindowStateProto window = 8; + /* represents a WindowState child */ + optional TaskFragmentProto task_fragment = 9; } /* represents ConfigurationContainer */ diff --git a/core/proto/android/view/surfacecontrol.proto b/core/proto/android/view/surfacecontrol.proto index cbb243ba7872..5a5f035412b2 100644 --- a/core/proto/android/view/surfacecontrol.proto +++ b/core/proto/android/view/surfacecontrol.proto @@ -29,4 +29,5 @@ message SurfaceControlProto { optional int32 hash_code = 1; optional string name = 2 [ (android.privacy).dest = DEST_EXPLICIT ]; + optional int32 layerId = 3; } diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 2ef64107ab3c..03fa20ecde2b 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -3510,6 +3510,13 @@ + + + @@ -4897,6 +4904,18 @@ + + + + + + @@ -5701,6 +5720,10 @@ + + diff --git a/core/res/OWNERS b/core/res/OWNERS index 7a8da36d8a7d..bd192088e80d 100644 --- a/core/res/OWNERS +++ b/core/res/OWNERS @@ -25,3 +25,9 @@ svetoslavganov@google.com toddke@google.com tsuji@google.com yamasani@google.com + +# Multiuser +per-file res/xml/config_user_types.xml = file:/MULTIUSER_OWNERS + +# Car +per-file res/values/dimens_car.xml = file:/platform/packages/services/Car:/OWNERS diff --git a/core/res/res/anim/task_fragment_close_enter.xml b/core/res/res/anim/task_fragment_close_enter.xml new file mode 100644 index 000000000000..c940552d53ad --- /dev/null +++ b/core/res/res/anim/task_fragment_close_enter.xml @@ -0,0 +1,32 @@ + + + + + + \ No newline at end of file diff --git a/core/res/res/anim/task_fragment_close_exit.xml b/core/res/res/anim/task_fragment_close_exit.xml new file mode 100644 index 000000000000..8998f764ff9b --- /dev/null +++ b/core/res/res/anim/task_fragment_close_exit.xml @@ -0,0 +1,42 @@ + + + + + + + diff --git a/core/res/res/anim/task_fragment_open_enter.xml b/core/res/res/anim/task_fragment_open_enter.xml new file mode 100644 index 000000000000..6bc47deb2de4 --- /dev/null +++ b/core/res/res/anim/task_fragment_open_enter.xml @@ -0,0 +1,41 @@ + + + + + + + diff --git a/core/res/res/anim/task_fragment_open_exit.xml b/core/res/res/anim/task_fragment_open_exit.xml new file mode 100644 index 000000000000..160eb84223da --- /dev/null +++ b/core/res/res/anim/task_fragment_open_exit.xml @@ -0,0 +1,32 @@ + + + + + + \ No newline at end of file diff --git a/core/res/res/drawable-nodpi/default_wallpaper.png b/core/res/res/drawable-nodpi/default_wallpaper.png index ce546f0a11e7..5152972d2a80 100644 Binary files a/core/res/res/drawable-nodpi/default_wallpaper.png and b/core/res/res/drawable-nodpi/default_wallpaper.png differ diff --git a/core/res/res/drawable-sw600dp-nodpi/default_wallpaper.png b/core/res/res/drawable-sw600dp-nodpi/default_wallpaper.png index af8e2512385a..26376fb87cbe 100644 Binary files a/core/res/res/drawable-sw600dp-nodpi/default_wallpaper.png and b/core/res/res/drawable-sw600dp-nodpi/default_wallpaper.png differ diff --git a/core/res/res/drawable-sw720dp-nodpi/default_wallpaper.png b/core/res/res/drawable-sw720dp-nodpi/default_wallpaper.png index cb00d82a826f..490ebeeb75c1 100644 Binary files a/core/res/res/drawable-sw720dp-nodpi/default_wallpaper.png and b/core/res/res/drawable-sw720dp-nodpi/default_wallpaper.png differ diff --git a/core/res/res/drawable/ic_corp_badge.xml b/core/res/res/drawable/ic_corp_badge.xml index 16df45290302..6c40f10a03c3 100644 --- a/core/res/res/drawable/ic_corp_badge.xml +++ b/core/res/res/drawable/ic_corp_badge.xml @@ -22,8 +22,5 @@ Copyright (C) 2018 The Android Open Source Project android:viewportHeight="24"> - + android:pathData="@string/config_work_badge_path_24"/> \ No newline at end of file diff --git a/core/res/res/drawable/ic_corp_badge_case.xml b/core/res/res/drawable/ic_corp_badge_case.xml index 1cd995eea171..838426ecd9a0 100644 --- a/core/res/res/drawable/ic_corp_badge_case.xml +++ b/core/res/res/drawable/ic_corp_badge_case.xml @@ -1,9 +1,9 @@ + android:viewportWidth="24.0" + android:viewportHeight="24.0"> diff --git a/core/res/res/drawable/ic_corp_badge_no_background.xml b/core/res/res/drawable/ic_corp_badge_no_background.xml index 8f7fb70d5b83..e81e69f1b5d5 100644 --- a/core/res/res/drawable/ic_corp_badge_no_background.xml +++ b/core/res/res/drawable/ic_corp_badge_no_background.xml @@ -4,6 +4,6 @@ android:viewportWidth="24.0" android:viewportHeight="24.0"> diff --git a/core/res/res/drawable/ic_corp_icon.xml b/core/res/res/drawable/ic_corp_icon.xml index 48531dd8c539..86bb98e0996b 100644 --- a/core/res/res/drawable/ic_corp_icon.xml +++ b/core/res/res/drawable/ic_corp_icon.xml @@ -4,6 +4,6 @@ android:viewportWidth="24.0" android:viewportHeight="24.0"> \ No newline at end of file diff --git a/core/res/res/drawable/ic_corp_icon_badge_case.xml b/core/res/res/drawable/ic_corp_icon_badge_case.xml index 50551d401120..09cf9cb89abe 100644 --- a/core/res/res/drawable/ic_corp_icon_badge_case.xml +++ b/core/res/res/drawable/ic_corp_icon_badge_case.xml @@ -22,9 +22,15 @@ Copyright (C) 2016 The Android Open Source Project - + + + \ No newline at end of file diff --git a/core/res/res/drawable/ic_corp_statusbar_icon.xml b/core/res/res/drawable/ic_corp_statusbar_icon.xml index 8f7fb70d5b83..e81e69f1b5d5 100644 --- a/core/res/res/drawable/ic_corp_statusbar_icon.xml +++ b/core/res/res/drawable/ic_corp_statusbar_icon.xml @@ -4,6 +4,6 @@ android:viewportWidth="24.0" android:viewportHeight="24.0"> diff --git a/core/res/res/drawable/ic_corp_user_badge.xml b/core/res/res/drawable/ic_corp_user_badge.xml index a08f2d4845e1..76ba4506426d 100644 --- a/core/res/res/drawable/ic_corp_user_badge.xml +++ b/core/res/res/drawable/ic_corp_user_badge.xml @@ -7,9 +7,6 @@ - diff --git a/core/res/res/layout-car/car_alert_dialog.xml b/core/res/res/layout-car/car_alert_dialog.xml index 569e5948e2e0..2e7b62ceb723 100644 --- a/core/res/res/layout-car/car_alert_dialog.xml +++ b/core/res/res/layout-car/car_alert_dialog.xml @@ -54,7 +54,7 @@ android:layout_height="wrap_content" android:layout_marginStart="@dimen/text_view_start_margin" android:layout_marginEnd="@dimen/text_view_end_margin" - style="@style/CarBody2"/> + style="@style/CarBody4"/> diff --git a/core/res/res/layout/accessibility_shortcut_chooser_item.xml b/core/res/res/layout/accessibility_shortcut_chooser_item.xml index 7cca1292af68..4d7946b2138b 100644 --- a/core/res/res/layout/accessibility_shortcut_chooser_item.xml +++ b/core/res/res/layout/accessibility_shortcut_chooser_item.xml @@ -39,15 +39,20 @@ android:layout_height="48dp" android:scaleType="fitCenter"/> - + android:layout_weight="1"> + + +