summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apct-tests/perftests/core/src/android/libcore/regression/ExpensiveObjectsPerfTest.java8
-rw-r--r--apct-tests/perftests/multiuser/src/android/multiuser/BroadcastWaiter.java34
-rw-r--r--apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java153
-rw-r--r--apct-tests/perftests/multiuser/src/android/multiuser/UserSwitchWaiter.java82
-rw-r--r--apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java40
-rw-r--r--core/java/android/accessibilityservice/AccessibilityService.java4
-rw-r--r--core/java/android/accounts/AbstractAccountAuthenticator.java2
-rw-r--r--core/java/android/accounts/AccountAuthenticatorActivity.java2
-rw-r--r--core/java/android/accounts/AccountManager.java2
-rw-r--r--core/java/android/accounts/ChooseAccountActivity.java2
-rw-r--r--core/java/android/accounts/ChooseTypeAndAccountActivity.java4
-rw-r--r--core/java/android/accounts/GrantCredentialsPermissionActivity.java4
-rw-r--r--core/java/android/app/Activity.java2
-rw-r--r--core/java/android/app/ActivityOptions.java20
-rw-r--r--core/java/android/app/ActivityThread.java26
-rw-r--r--core/java/android/app/AppOpsManager.java4
-rw-r--r--core/java/android/app/BroadcastOptions.java33
-rw-r--r--core/java/android/app/ExitTransitionCoordinator.java2
-rw-r--r--core/java/android/app/Notification.java8
-rw-r--r--core/java/android/app/RecoverableSecurityException.java2
-rw-r--r--core/java/android/app/RemoteInput.java2
-rw-r--r--core/java/android/app/SearchDialog.java2
-rw-r--r--core/java/android/app/SharedElementCallback.java4
-rw-r--r--core/java/android/app/admin/DelegatedAdminReceiver.java2
-rw-r--r--core/java/android/app/admin/DeviceAdminReceiver.java24
-rw-r--r--core/java/android/app/ambientcontext/AmbientContextManager.java2
-rw-r--r--core/java/android/app/slice/SliceManager.java8
-rw-r--r--core/java/android/app/slice/SliceProvider.java16
-rw-r--r--core/java/android/content/ClipboardManager.java55
-rw-r--r--core/java/android/content/ContentResolver.java4
-rw-r--r--core/java/android/content/IClipboard.aidl20
-rw-r--r--core/java/android/content/Intent.java16
-rw-r--r--core/java/android/content/SyncActivityTooManyDeletes.java2
-rw-r--r--core/java/android/content/pm/ApplicationInfo.java2
-rw-r--r--core/java/android/content/pm/LauncherApps.java2
-rw-r--r--core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java34
-rw-r--r--core/java/android/hardware/location/ContextHubIntentEvent.java4
-rw-r--r--core/java/android/hardware/radio/RadioMetadata.java4
-rw-r--r--core/java/android/inputmethodservice/InputMethodService.java4
-rw-r--r--core/java/android/net/ScoredNetwork.java2
-rw-r--r--core/java/android/nfc/tech/Ndef.java2
-rw-r--r--core/java/android/os/Parcel.java51
-rw-r--r--core/java/android/os/image/DynamicSystemClient.java2
-rw-r--r--core/java/android/preference/PreferenceActivity.java2
-rw-r--r--core/java/android/preference/RingtonePreference.java2
-rw-r--r--core/java/android/print/PrintManager.java4
-rw-r--r--core/java/android/provider/ContactsContract.java4
-rw-r--r--core/java/android/provider/DocumentsContract.java12
-rw-r--r--core/java/android/provider/DocumentsProvider.java14
-rw-r--r--core/java/android/provider/Settings.java6
-rw-r--r--core/java/android/service/autofill/FillRequest.java2
-rw-r--r--core/java/android/service/contentsuggestions/ContentSuggestionsService.java2
-rw-r--r--core/java/android/service/controls/templates/ThumbnailTemplate.java2
-rw-r--r--core/java/android/service/controls/templates/ToggleRangeTemplate.java2
-rw-r--r--core/java/android/service/controls/templates/ToggleTemplate.java2
-rw-r--r--core/java/android/service/dreams/DreamService.java2
-rw-r--r--core/java/android/service/games/GameSessionTrampolineActivity.java6
-rw-r--r--core/java/android/service/notification/NotificationListenerService.java2
-rw-r--r--core/java/android/service/notification/StatusBarNotification.java2
-rw-r--r--core/java/android/service/restrictions/RestrictionsReceiver.java2
-rw-r--r--core/java/android/service/trust/TrustAgentService.java2
-rw-r--r--core/java/android/service/voice/VoiceInteractionSession.java2
-rw-r--r--core/java/android/speech/AlternativeSpans.java2
-rw-r--r--core/java/android/speech/tts/TextToSpeechService.java2
-rw-r--r--core/java/android/view/InsetsState.java5
-rw-r--r--core/java/android/view/RemoteAccessibilityController.java23
-rw-r--r--core/java/android/view/ScrollCaptureConnection.java2
-rw-r--r--core/java/android/view/ThreadedRenderer.java33
-rw-r--r--core/java/android/view/View.java2
-rw-r--r--core/java/android/view/ViewRootImpl.java1
-rw-r--r--core/java/android/view/ViewTreeObserver.java84
-rw-r--r--core/java/android/view/WindowInfo.java2
-rw-r--r--core/java/android/view/WindowLayout.java29
-rw-r--r--core/java/android/view/WindowManagerImpl.java2
-rw-r--r--core/java/android/view/autofill/AutofillManager.java2
-rw-r--r--core/java/android/view/inputmethod/InputMethodManager.java1
-rw-r--r--core/java/android/view/selectiontoolbar/ShowInfo.java2
-rw-r--r--core/java/android/view/textclassifier/ExtrasUtils.java4
-rw-r--r--core/java/android/view/translation/TranslationManager.java4
-rw-r--r--core/java/android/window/TaskFragmentOrganizer.java2
-rw-r--r--core/java/com/android/internal/app/BlockedAppStreamingActivity.java2
-rw-r--r--core/java/com/android/internal/app/ChooserActivity.java156
-rw-r--r--core/java/com/android/internal/app/ConfirmUserCreationActivity.java2
-rw-r--r--core/java/com/android/internal/app/HarmfulAppWarningActivity.java4
-rw-r--r--core/java/com/android/internal/app/HeavyWeightSwitcherActivity.java2
-rw-r--r--core/java/com/android/internal/app/IntentForwarderActivity.java2
-rw-r--r--core/java/com/android/internal/app/LaunchAfterAuthenticationActivity.java2
-rw-r--r--core/java/com/android/internal/app/ResolverActivity.java19
-rw-r--r--core/java/com/android/internal/app/ResolverListAdapter.java8
-rw-r--r--core/java/com/android/internal/app/ResolverListController.java6
-rw-r--r--core/java/com/android/internal/app/SuspendedAppActivity.java4
-rw-r--r--core/java/com/android/internal/app/UnlaunchableAppActivity.java2
-rw-r--r--core/java/com/android/internal/net/VpnProfile.java2
-rw-r--r--core/java/com/android/internal/policy/DecorView.java5
-rw-r--r--core/java/com/android/internal/util/ScreenshotHelper.java4
-rw-r--r--core/java/com/android/internal/widget/CallLayout.java2
-rw-r--r--core/java/com/android/internal/widget/ConversationLayout.java4
-rw-r--r--core/java/com/android/internal/widget/MessagingLayout.java4
-rw-r--r--core/java/com/android/internal/widget/ResolverDrawerLayout.java38
-rw-r--r--core/jni/android_os_Parcel.cpp9
-rw-r--r--core/res/res/drawable-nodpi/default_wallpaper.pngbin738385 -> 861738 bytes
-rw-r--r--core/res/res/drawable-sw600dp-nodpi/default_wallpaper.pngbin2774036 -> 3063458 bytes
-rw-r--r--core/res/res/drawable-sw720dp-nodpi/default_wallpaper.pngbin4958722 -> 4449640 bytes
-rw-r--r--core/res/res/values/dimens.xml2
-rw-r--r--core/tests/coretests/src/android/view/WindowInfoTest.java50
-rw-r--r--core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java47
-rw-r--r--core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java12
-rw-r--r--core/tests/coretests/src/com/android/internal/app/ResolverListControllerTest.java124
-rw-r--r--core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java20
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java4
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java4
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitDecorManager.java31
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java48
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java44
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java3
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuView.java4
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java76
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java46
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java15
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java5
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java91
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/PipAppHelper.kt5
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/AutoEnterPipOnGoToHomeTest.kt116
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTest.kt2
-rw-r--r--libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/res/layout/activity_pip.xml7
-rw-r--r--libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/src/com/android/wm/shell/flicker/testapp/PipActivity.java4
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/MockSurfaceControlHelper.java56
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/TestRunningTaskInfoBuilder.java33
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java58
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipAnimationControllerTest.java10
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipDummySurfaceControlTx.java66
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java4
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitScreenControllerTests.java152
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java178
-rw-r--r--libs/hwui/Readback.cpp35
-rw-r--r--location/java/android/location/SettingInjectorService.java2
-rw-r--r--media/java/android/media/AudioAttributes.java2
-rw-r--r--media/java/android/media/MediaMetadata.java4
-rw-r--r--media/java/android/media/MediaRouter.java2
-rw-r--r--media/java/android/media/RemoteController.java2
-rw-r--r--media/java/android/media/audiofx/HapticGenerator.java3
-rw-r--r--media/java/android/media/session/MediaSession.java2
-rw-r--r--packages/SettingsLib/res/values-fa/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-mn/strings.xml12
-rw-r--r--packages/SettingsLib/res/values-my/strings.xml6
-rw-r--r--packages/SettingsProvider/res/values-nb/strings.xml2
-rw-r--r--packages/SystemUI/AndroidManifest.xml11
-rw-r--r--packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt7
-rw-r--r--packages/SystemUI/docs/camera.md45
-rw-r--r--packages/SystemUI/proguard.flags4
-rw-r--r--packages/SystemUI/res-keyguard/layout/keyguard_bouncer_user_switcher.xml1
-rw-r--r--packages/SystemUI/res/values-television/config.xml2
-rw-r--r--packages/SystemUI/res/values/config.xml2
-rw-r--r--packages/SystemUI/res/values/ids.xml3
-rw-r--r--packages/SystemUI/res/values/styles.xml4
-rw-r--r--packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/ScreenshotTestRule.kt21
-rw-r--r--packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/ViewScreenshotTestRule.kt16
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java8
-rw-r--r--packages/SystemUI/src/com/android/keyguard/LockIconViewController.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/ScreenDecorations.java205
-rw-r--r--packages/SystemUI/src/com/android/systemui/SystemUIAppComponentFactory.java158
-rw-r--r--packages/SystemUI/src/com/android/systemui/SystemUIAppComponentFactoryBase.kt183
-rw-r--r--packages/SystemUI/src/com/android/systemui/SystemUIApplication.java23
-rw-r--r--packages/SystemUI/src/com/android/systemui/SystemUIInitializer.java (renamed from packages/SystemUI/src/com/android/systemui/SystemUIFactory.java)101
-rw-r--r--packages/SystemUI/src/com/android/systemui/SystemUIInitializerFactory.kt72
-rw-r--r--packages/SystemUI/src/com/android/systemui/SystemUIInitializerImpl.kt30
-rw-r--r--packages/SystemUI/src/com/android/systemui/camera/CameraGestureHelper.kt7
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/decor/CutoutDecorProviderFactory.kt60
-rw-r--r--packages/SystemUI/src/com/android/systemui/decor/CutoutDecorProviderImpl.kt65
-rw-r--r--packages/SystemUI/src/com/android/systemui/decor/DecorProvider.kt69
-rw-r--r--packages/SystemUI/src/com/android/systemui/decor/OverlayWindow.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt15
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaProjectionAppSelectorActivity.kt119
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java40
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/dagger/MediaProjectionModule.kt35
-rw-r--r--packages/SystemUI/src/com/android/systemui/people/PeopleProvider.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/user/UserSwitchDialogController.kt7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotifications.kt9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java59
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java83
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java269
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/tv/TvSystemUIInitializer.java (renamed from packages/SystemUI/src/com/android/systemui/tv/TvSystemUIFactory.java)12
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/AsyncActivityLauncher.kt89
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/service/ObservableServiceConnection.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/service/PersistentConnectionManager.java5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/DependencyTest.java10
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java282
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/SysuiBaseFragmentTest.java12
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java7
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/animation/DialogLaunchAnimatorTest.kt26
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/decor/CutoutDecorProviderFactoryTest.kt200
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java3
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java7
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java8
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerLegacyTest.java299
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java3
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaTest.kt1
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java3
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/UserSwitcherControllerTest.kt8
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/service/ObservableServiceConnectionTest.java24
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/service/PersistentConnectionManagerTest.java19
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java4
-rw-r--r--services/accessibility/java/com/android/server/accessibility/PolicyWarningUIController.java2
-rw-r--r--services/autofill/java/com/android/server/autofill/AutofillManagerServiceShellCommand.java2
-rw-r--r--services/autofill/java/com/android/server/autofill/Session.java8
-rw-r--r--services/companion/java/com/android/server/companion/AssociationRequestsProcessor.java6
-rw-r--r--services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java4
-rw-r--r--services/core/java/com/android/server/ExplicitHealthCheckController.java2
-rw-r--r--services/core/java/com/android/server/StorageManagerService.java26
-rw-r--r--services/core/java/com/android/server/Watchdog.java27
-rw-r--r--services/core/java/com/android/server/accounts/AccountManagerService.java6
-rw-r--r--services/core/java/com/android/server/adb/AdbDebuggingManager.java2
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java14
-rw-r--r--services/core/java/com/android/server/am/BroadcastRecord.java3
-rw-r--r--services/core/java/com/android/server/am/OomAdjuster.java4
-rw-r--r--services/core/java/com/android/server/am/PendingIntentRecord.java18
-rw-r--r--services/core/java/com/android/server/audio/BtHelper.java2
-rw-r--r--services/core/java/com/android/server/camera/CameraServiceProxy.java2
-rw-r--r--services/core/java/com/android/server/clipboard/ClipboardService.java159
-rw-r--r--services/core/java/com/android/server/display/WifiDisplayController.java4
-rw-r--r--services/core/java/com/android/server/inputmethod/InputMethodManagerService.java3
-rw-r--r--services/core/java/com/android/server/location/contexthub/ContextHubClientBroker.java11
-rw-r--r--services/core/java/com/android/server/location/contexthub/ContextHubService.java7
-rw-r--r--services/core/java/com/android/server/locksettings/LockSettingsStorage.java48
-rw-r--r--services/core/java/com/android/server/locksettings/ResumeOnRebootServiceProvider.java4
-rw-r--r--services/core/java/com/android/server/media/BluetoothRouteProvider.java2
-rw-r--r--services/core/java/com/android/server/media/MediaRouterService.java2
-rw-r--r--services/core/java/com/android/server/net/NetworkPolicyManagerService.java2
-rw-r--r--services/core/java/com/android/server/notification/CountdownConditionProvider.java2
-rwxr-xr-xservices/core/java/com/android/server/notification/NotificationManagerService.java19
-rw-r--r--services/core/java/com/android/server/notification/NotificationRecord.java4
-rw-r--r--services/core/java/com/android/server/notification/NotificationRecordLogger.java2
-rw-r--r--services/core/java/com/android/server/notification/SnoozeHelper.java11
-rw-r--r--services/core/java/com/android/server/om/OverlayManagerService.java2
-rw-r--r--services/core/java/com/android/server/pm/InstallPackageHelper.java18
-rw-r--r--services/core/java/com/android/server/pm/InstantAppResolverConnection.java4
-rw-r--r--services/core/java/com/android/server/pm/UserManagerService.java2
-rw-r--r--services/core/java/com/android/server/pm/pkg/component/ParsedPermissionUtils.java3
-rw-r--r--services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageImpl.java2
-rw-r--r--services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java2
-rw-r--r--services/core/java/com/android/server/policy/GlobalKeyIntent.java2
-rw-r--r--services/core/java/com/android/server/sensorprivacy/SensorPrivacyService.java2
-rw-r--r--services/core/java/com/android/server/storage/CacheQuotaStrategy.java2
-rw-r--r--services/core/java/com/android/server/storage/StorageUserConnection.java2
-rw-r--r--services/core/java/com/android/server/trust/TrustAgentWrapper.java2
-rw-r--r--services/core/java/com/android/server/vr/Vr2dDisplay.java2
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java18
-rw-r--r--services/core/java/com/android/server/wm/BackNavigationController.java12
-rw-r--r--services/core/java/com/android/server/wm/DisplayPolicy.java31
-rw-r--r--services/core/java/com/android/server/wm/EventLogTags.logtags2
-rw-r--r--services/core/java/com/android/server/wm/InsetsPolicy.java25
-rw-r--r--services/core/java/com/android/server/wm/Task.java3
-rw-r--r--services/core/java/com/android/server/wm/TaskFragment.java29
-rw-r--r--services/core/java/com/android/server/wm/WindowContainer.java13
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java10
-rw-r--r--services/core/java/com/android/server/wm/WindowOrganizerController.java19
-rw-r--r--services/core/java/com/android/server/wm/WindowSurfaceController.java8
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java116
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/NetworkLoggingHandler.java2
-rw-r--r--services/midi/java/com/android/server/midi/MidiService.java10
-rw-r--r--services/net/java/android/net/ConnectivityModuleConnector.java32
-rw-r--r--services/net/java/android/net/NetworkStackClient.java45
-rw-r--r--services/people/java/com/android/server/people/prediction/ShareTargetPredictor.java2
-rw-r--r--services/tests/apexsystemservices/Android.bp2
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java22
-rw-r--r--services/tests/servicestests/AndroidTest.xml1
-rw-r--r--services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTests.java70
-rw-r--r--services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java1
-rwxr-xr-xservices/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java85
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java17
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java17
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java73
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskTests.java3
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java12
-rw-r--r--services/usb/java/com/android/server/usb/MtpNotificationManager.java2
-rw-r--r--services/usb/java/com/android/server/usb/UsbDeviceManager.java4
-rw-r--r--services/usb/java/com/android/server/usb/UsbPortManager.java2
-rw-r--r--services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java4
-rwxr-xr-xtelecomm/java/android/telecom/ConnectionService.java2
-rw-r--r--telephony/java/android/telephony/ServiceState.java2
-rw-r--r--telephony/java/android/telephony/SignalStrength.java12
-rw-r--r--telephony/java/android/telephony/TelephonyManager.java6
-rw-r--r--telephony/java/android/telephony/VisualVoicemailService.java4
-rw-r--r--telephony/java/android/telephony/euicc/EuiccManager.java4
-rw-r--r--telephony/java/android/telephony/mbms/MbmsDownloadReceiver.java16
-rw-r--r--tests/FlickerTests/Android.bp17
-rw-r--r--tests/FlickerTests/AndroidManifest.xml1
-rw-r--r--tests/FlickerTests/libs/window-extensions-release.aarbin0 -> 19218 bytes
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt5
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/ActivityEmbeddingTestBase.kt33
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/OpenActivityEmbeddingPlaceholderSplit.kt114
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppTransition.kt6
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ActivityEmbeddingAppHelper.kt97
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLauncherTransition.kt10
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationCold.kt6
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWarm.kt6
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWithLockOverlayApp.kt6
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationCold.kt6
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationWarm.kt6
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt5
-rw-r--r--tests/FlickerTests/test-apps/flickerapp/Android.bp5
-rw-r--r--tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml32
-rw-r--r--tests/FlickerTests/test-apps/flickerapp/res/layout/activity_embedding_base_layout.xml24
-rw-r--r--tests/FlickerTests/test-apps/flickerapp/res/layout/activity_embedding_main_layout.xml32
-rw-r--r--tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityEmbeddingBaseActivity.java34
-rw-r--r--tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityEmbeddingMainActivity.java85
-rw-r--r--tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityEmbeddingPlaceholderPrimaryActivity.java30
-rw-r--r--tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityEmbeddingPlaceholderSecondaryActivity.java30
-rw-r--r--tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java13
-rw-r--r--tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java23
-rw-r--r--tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java36
-rw-r--r--tests/UsbManagerTests/lib/src/com/android/server/usblib/UsbManagerTestLib.java2
-rw-r--r--tests/UsbTests/src/com/android/server/usb/UsbHandlerTest.java8
322 files changed, 4698 insertions, 2629 deletions
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/ExpensiveObjectsPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/ExpensiveObjectsPerfTest.java
index 03c9d43d3258..adcd5710ef19 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/ExpensiveObjectsPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/ExpensiveObjectsPerfTest.java
@@ -158,14 +158,6 @@ public class ExpensiveObjectsPerfTest {
}
@Test
- public void timeNewSimpleDateFormat() {
- BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
- while (state.keepRunning()) {
- new SimpleDateFormat();
- }
- }
-
- @Test
public void timeClonedSimpleDateFormat() {
SimpleDateFormat sdf = new SimpleDateFormat();
BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
diff --git a/apct-tests/perftests/multiuser/src/android/multiuser/BroadcastWaiter.java b/apct-tests/perftests/multiuser/src/android/multiuser/BroadcastWaiter.java
index 7ed97fbb440e..dcabca476925 100644
--- a/apct-tests/perftests/multiuser/src/android/multiuser/BroadcastWaiter.java
+++ b/apct-tests/perftests/multiuser/src/android/multiuser/BroadcastWaiter.java
@@ -23,9 +23,12 @@ import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.os.SystemClock;
import android.text.TextUtils;
import android.util.Log;
+import com.android.internal.util.FunctionalUtils;
+
import java.io.Closeable;
import java.util.ArrayList;
import java.util.Arrays;
@@ -72,7 +75,8 @@ public class BroadcastWaiter implements Closeable {
@Override
public void onReceive(Context context, Intent intent) {
if (action.equals(intent.getAction())) {
- final int userId = getSendingUserId();
+ final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
+ getSendingUserId());
final String data = intent.getDataString();
Log.d(mTag, "Received " + action + " for user " + userId
+ (!TextUtils.isEmpty(data) ? " with " + data : ""));
@@ -95,7 +99,7 @@ public class BroadcastWaiter implements Closeable {
return mActionReceivedForUser.contains(action + userId);
}
- public boolean waitActionForUser(String action, int userId) {
+ private boolean waitActionForUser(String action, int userId) {
Log.d(mTag, "#waitActionForUser(action: " + action + ", userId: " + userId + ")");
if (!mActions.contains(action)) {
@@ -103,18 +107,40 @@ public class BroadcastWaiter implements Closeable {
return false;
}
+ final long startTime = SystemClock.elapsedRealtime();
try {
- if (!getSemaphore(action, userId).tryAcquire(1, mTimeoutInSecond, SECONDS)) {
- Log.e(mTag, action + " broadcast wasn't received for user " + userId);
+ final boolean doneBeforeTimeout = getSemaphore(action, userId)
+ .tryAcquire(1, mTimeoutInSecond, SECONDS);
+ if (!doneBeforeTimeout) {
+ Log.e(mTag, action + " broadcast wasn't received for user " + userId
+ + " in " + mTimeoutInSecond + " seconds");
return false;
}
} catch (InterruptedException e) {
Log.e(mTag, "Interrupted while waiting " + action + " for user " + userId);
return false;
}
+ final long elapsedTime = SystemClock.elapsedRealtime() - startTime;
+ Log.d(mTag, action + " broadcast received for user " + userId
+ + " in " + elapsedTime + " ms");
return true;
}
+ public String runThenWaitForBroadcasts(int userId, FunctionalUtils.ThrowingRunnable runnable,
+ String... actions) {
+ for (String action : actions) {
+ mActionReceivedForUser.remove(action + userId);
+ getSemaphore(action, userId).drainPermits();
+ }
+ runnable.run();
+ for (String action : actions) {
+ if (!waitActionForUser(action, userId)) {
+ return action;
+ }
+ }
+ return null;
+ }
+
public boolean waitActionForUserIfNotReceivedYet(String action, int userId) {
return hasActionBeenReceivedForUser(action, userId)
|| waitActionForUser(action, userId);
diff --git a/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java b/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java
index a44d93972ae1..734545376279 100644
--- a/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java
+++ b/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java
@@ -23,14 +23,12 @@ import android.app.ActivityTaskManager;
import android.app.AppGlobals;
import android.app.IActivityManager;
import android.app.IStopUserCallback;
-import android.app.UserSwitchObserver;
import android.app.WaitResult;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.IIntentReceiver;
import android.content.IIntentSender;
import android.content.Intent;
-import android.content.IntentFilter;
import android.content.IntentSender;
import android.content.pm.IPackageInstaller;
import android.content.pm.PackageManager;
@@ -51,6 +49,8 @@ import androidx.test.InstrumentationRegistry;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
+import com.android.internal.util.FunctionalUtils;
+
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
@@ -115,6 +115,7 @@ public class UserLifecycleTests {
private ArrayList<Integer> mUsersToRemove;
private boolean mHasManagedUserFeature;
private BroadcastWaiter mBroadcastWaiter;
+ private UserSwitchWaiter mUserSwitchWaiter;
private final BenchmarkRunner mRunner = new BenchmarkRunner();
@Rule
@@ -132,7 +133,9 @@ public class UserLifecycleTests {
mBroadcastWaiter = new BroadcastWaiter(context, TAG, TIMEOUT_IN_SECOND,
Intent.ACTION_USER_STARTED,
Intent.ACTION_MEDIA_MOUNTED,
- Intent.ACTION_USER_UNLOCKED);
+ Intent.ACTION_USER_UNLOCKED,
+ Intent.ACTION_USER_STOPPED);
+ mUserSwitchWaiter = new UserSwitchWaiter(TAG, TIMEOUT_IN_SECOND);
removeAnyPreviousTestUsers();
if (mAm.getCurrentUser() != UserHandle.USER_SYSTEM) {
Log.w(TAG, "WARNING: Tests are being run from user " + mAm.getCurrentUser()
@@ -175,8 +178,9 @@ public class UserLifecycleTests {
// Don't use this.startUserInBackgroundAndWaitForUnlock() since only waiting until
// ACTION_USER_STARTED.
- mIam.startUserInBackground(userId);
- waitForBroadcast(Intent.ACTION_USER_STARTED, userId);
+ runThenWaitForBroadcasts(userId, () -> {
+ mIam.startUserInBackground(userId);
+ }, Intent.ACTION_USER_STARTED);
mRunner.pauseTiming();
Log.i(TAG, "Stopping timer");
@@ -197,8 +201,9 @@ public class UserLifecycleTests {
mRunner.resumeTiming();
Log.i(TAG, "Starting timer");
- mIam.startUserInBackground(userId);
- waitForBroadcast(Intent.ACTION_USER_STARTED, userId);
+ runThenWaitForBroadcasts(userId, () -> {
+ mIam.startUserInBackground(userId);
+ }, Intent.ACTION_USER_STARTED);
mRunner.pauseTiming();
Log.i(TAG, "Stopping timer");
@@ -259,8 +264,9 @@ public class UserLifecycleTests {
mRunner.resumeTiming();
Log.i(TAG, "Starting timer");
- mAm.switchUser(testUser);
- waitForBroadcast(Intent.ACTION_USER_UNLOCKED, testUser);
+ runThenWaitForBroadcasts(testUser, () -> {
+ mAm.switchUser(testUser);
+ }, Intent.ACTION_USER_UNLOCKED);
mRunner.pauseTiming();
Log.i(TAG, "Stopping timer");
@@ -296,10 +302,10 @@ public class UserLifecycleTests {
while (mRunner.keepRunning()) {
mRunner.pauseTiming();
final int userId = createUserNoFlags();
- mIam.startUserInBackground(userId);
- waitForBroadcast(Intent.ACTION_USER_STARTED, userId);
- waitForBroadcast(Intent.ACTION_MEDIA_MOUNTED, userId);
+ runThenWaitForBroadcasts(userId, ()-> {
+ mIam.startUserInBackground(userId);
+ }, Intent.ACTION_USER_STARTED, Intent.ACTION_MEDIA_MOUNTED);
mRunner.resumeTiming();
Log.i(TAG, "Starting timer");
@@ -320,13 +326,12 @@ public class UserLifecycleTests {
mRunner.pauseTiming();
final int startUser = mAm.getCurrentUser();
final int userId = createUserNoFlags();
- final CountDownLatch latch = new CountDownLatch(1);
- registerUserSwitchObserver(null, latch, userId);
- mRunner.resumeTiming();
- Log.i(TAG, "Starting timer");
- mAm.switchUser(userId);
- waitForLatch("Failed to achieve onLockedBootComplete for user " + userId, latch);
+ mUserSwitchWaiter.runThenWaitUntilBootCompleted(userId, () -> {
+ mRunner.resumeTiming();
+ Log.i(TAG, "Starting timer");
+ mAm.switchUser(userId);
+ }, () -> fail("Failed to achieve onLockedBootComplete for user " + userId));
mRunner.pauseTiming();
Log.i(TAG, "Stopping timer");
@@ -343,34 +348,22 @@ public class UserLifecycleTests {
mRunner.pauseTiming();
final int startUser = mAm.getCurrentUser();
final int userId = createUserWithFlags(UserInfo.FLAG_EPHEMERAL | UserInfo.FLAG_DEMO);
- switchUser(userId);
- waitForBroadcast(Intent.ACTION_MEDIA_MOUNTED, userId);
-
- final CountDownLatch latch = new CountDownLatch(1);
- InstrumentationRegistry.getContext().registerReceiver(new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- if (Intent.ACTION_USER_STOPPED.equals(intent.getAction()) && intent.getIntExtra(
- Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL) == userId) {
- latch.countDown();
- }
- }
- }, new IntentFilter(Intent.ACTION_USER_STOPPED));
- final CountDownLatch switchLatch = new CountDownLatch(1);
- registerUserSwitchObserver(switchLatch, null, startUser);
- mRunner.resumeTiming();
- Log.i(TAG, "Starting timer");
+ runThenWaitForBroadcasts(userId, () -> {
+ switchUser(userId);
+ }, Intent.ACTION_MEDIA_MOUNTED);
- mAm.switchUser(startUser);
- waitForLatch("Failed to achieve ACTION_USER_STOPPED for user " + userId, latch);
+ mUserSwitchWaiter.runThenWaitUntilSwitchCompleted(startUser, () -> {
+ mRunner.resumeTiming();
+ Log.i(TAG, "Starting timer");
+
+ runThenWaitForBroadcasts(userId, () -> {
+ mAm.switchUser(startUser);
+ }, Intent.ACTION_USER_STOPPED);
+
+ mRunner.pauseTiming();
+ Log.i(TAG, "Stopping timer");
+ }, null);
- mRunner.pauseTiming();
- Log.i(TAG, "Stopping timer");
- try {
- switchLatch.await(TIMEOUT_IN_SECOND, TimeUnit.SECONDS);
- } catch (InterruptedException e) {
- Log.e(TAG, "Thread interrupted unexpectedly while waiting for switch.", e);
- }
removeUser(userId);
mRunner.resumeTimingForNextIteration();
}
@@ -547,8 +540,9 @@ public class UserLifecycleTests {
while (mRunner.keepRunning()) {
mRunner.pauseTiming();
final int userId = createManagedProfile();
- startUserInBackgroundAndWaitForUnlock(userId);
- waitForBroadcast(Intent.ACTION_MEDIA_MOUNTED, userId);
+ runThenWaitForBroadcasts(userId, () -> {
+ startUserInBackgroundAndWaitForUnlock(userId);
+ }, Intent.ACTION_MEDIA_MOUNTED);
mRunner.resumeTiming();
Log.i(TAG, "Starting timer");
@@ -667,15 +661,11 @@ public class UserLifecycleTests {
* If lack of success should fail the test, use {@link #switchUser(int)} instead.
*/
private boolean switchUserNoCheck(int userId) throws RemoteException {
- final CountDownLatch latch = new CountDownLatch(1);
- registerUserSwitchObserver(latch, null, userId);
- mAm.switchUser(userId);
- try {
- return latch.await(TIMEOUT_IN_SECOND, TimeUnit.SECONDS);
- } catch (InterruptedException e) {
- Log.e(TAG, "Thread interrupted unexpectedly.", e);
- return false;
- }
+ final boolean[] success = {true};
+ mUserSwitchWaiter.runThenWaitUntilSwitchCompleted(userId, () -> {
+ mAm.switchUser(userId);
+ }, () -> success[0] = false);
+ return success[0];
}
private void stopUser(int userId, boolean force) throws RemoteException {
@@ -704,9 +694,9 @@ public class UserLifecycleTests {
final int origUser = mAm.getCurrentUser();
// First, create and switch to testUser, waiting for its ACTION_USER_UNLOCKED
final int testUser = createUserNoFlags();
- mAm.switchUser(testUser);
- waitForBroadcast(Intent.ACTION_USER_UNLOCKED, testUser);
- waitForBroadcast(Intent.ACTION_MEDIA_MOUNTED, testUser);
+ runThenWaitForBroadcasts(testUser, () -> {
+ mAm.switchUser(testUser);
+ }, Intent.ACTION_USER_UNLOCKED, Intent.ACTION_MEDIA_MOUNTED);
// Second, switch back to origUser, waiting merely for switchUser() to finish
switchUser(origUser);
@@ -756,26 +746,6 @@ public class UserLifecycleTests {
result.result == ActivityManager.START_SUCCESS);
}
- private void registerUserSwitchObserver(final CountDownLatch switchLatch,
- final CountDownLatch bootCompleteLatch, final int userId) throws RemoteException {
- ActivityManager.getService().registerUserSwitchObserver(
- new UserSwitchObserver() {
- @Override
- public void onUserSwitchComplete(int newUserId) throws RemoteException {
- if (switchLatch != null && userId == newUserId) {
- switchLatch.countDown();
- }
- }
-
- @Override
- public void onLockedBootComplete(int newUserId) {
- if (bootCompleteLatch != null && userId == newUserId) {
- bootCompleteLatch.countDown();
- }
- }
- }, TAG);
- }
-
private class ProgressWaiter extends IProgressListener.Stub {
private final CountDownLatch mFinishedLatch = new CountDownLatch(1);
@@ -803,12 +773,21 @@ public class UserLifecycleTests {
/**
* Waits TIMEOUT_IN_SECOND for the broadcast to be received, otherwise declares the given error.
* It only works for the broadcasts provided in {@link #mBroadcastWaiter}'s instantiation above.
- * @param action action of the broadcast, i.e. {@link Intent#ACTION_USER_STARTED}
- * @param userId sendingUserId of the broadcast. See {@link BroadcastReceiver#getSendingUserId}
+ * @param userId userId associated with the broadcast. It is {@link Intent#EXTRA_USER_HANDLE}
+ * or in case that is null, then it is {@link BroadcastReceiver#getSendingUserId}.
+ * @param runnable function to be run after clearing any possible previously received broadcasts
+ * and before waiting for the new broadcasts. This function should typically do
+ * something to trigger broadcasts to be sent. Like starting or stopping a user.
+ * @param actions actions of the broadcasts, i.e. {@link Intent#ACTION_USER_STARTED}.
+ * If multiple actions are provided, they will be waited in given order.
*/
- private void waitForBroadcast(String action, int userId) {
- attestTrue("Failed to achieve " + action + " for user " + userId,
- mBroadcastWaiter.waitActionForUser(action, userId));
+ private void runThenWaitForBroadcasts(int userId, FunctionalUtils.ThrowingRunnable runnable,
+ String... actions) {
+ final String unreceivedAction =
+ mBroadcastWaiter.runThenWaitForBroadcasts(userId, runnable, actions);
+
+ attestTrue("Failed to achieve " + unreceivedAction + " for user " + userId,
+ unreceivedAction == null);
}
/** Waits TIMEOUT_IN_SECOND for the latch to complete, otherwise declares the given error. */
@@ -874,10 +853,14 @@ public class UserLifecycleTests {
}
}
+ private void fail(@NonNull String message) {
+ Log.e(TAG, "Test failed on iteration #" + mRunner.getIteration() + ": " + message);
+ mRunner.markAsFailed(new AssertionError(message));
+ }
+
private void attestTrue(@NonNull String message, boolean assertion) {
if (!assertion) {
- Log.e(TAG, "Test failed on iteration #" + mRunner.getIteration() + ": " + message);
- mRunner.markAsFailed(new AssertionError(message));
+ fail(message);
}
}
diff --git a/apct-tests/perftests/multiuser/src/android/multiuser/UserSwitchWaiter.java b/apct-tests/perftests/multiuser/src/android/multiuser/UserSwitchWaiter.java
new file mode 100644
index 000000000000..228d14c3a05b
--- /dev/null
+++ b/apct-tests/perftests/multiuser/src/android/multiuser/UserSwitchWaiter.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.multiuser;
+
+import android.app.ActivityManager;
+import android.app.UserSwitchObserver;
+import android.os.RemoteException;
+import android.util.Log;
+
+import com.android.internal.util.FunctionalUtils;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+public class UserSwitchWaiter {
+
+ private final String mTag;
+ private final int mTimeoutInSecond;
+
+ public UserSwitchWaiter(String tag, int timeoutInSecond) {
+ mTag = tag;
+ mTimeoutInSecond = timeoutInSecond;
+ }
+
+ public void runThenWaitUntilSwitchCompleted(int userId,
+ FunctionalUtils.ThrowingRunnable runnable, Runnable onFail) throws RemoteException {
+ final CountDownLatch latch = new CountDownLatch(1);
+ ActivityManager.getService().registerUserSwitchObserver(
+ new UserSwitchObserver() {
+ @Override
+ public void onUserSwitchComplete(int newUserId) throws RemoteException {
+ if (userId == newUserId) {
+ latch.countDown();
+ }
+ }
+ }, mTag);
+ runnable.run();
+ waitForLatch(latch, onFail);
+ }
+
+ public void runThenWaitUntilBootCompleted(int userId,
+ FunctionalUtils.ThrowingRunnable runnable, Runnable onFail) throws RemoteException {
+ final CountDownLatch latch = new CountDownLatch(1);
+ ActivityManager.getService().registerUserSwitchObserver(
+ new UserSwitchObserver() {
+ @Override
+ public void onLockedBootComplete(int newUserId) {
+ if (userId == newUserId) {
+ latch.countDown();
+ }
+ }
+ }, mTag);
+ runnable.run();
+ waitForLatch(latch, onFail);
+ }
+
+ private void waitForLatch(CountDownLatch latch, Runnable onFail) {
+ boolean success = false;
+ try {
+ success = latch.await(mTimeoutInSecond, TimeUnit.SECONDS);
+ } catch (InterruptedException e) {
+ Log.e(mTag, "Thread interrupted unexpectedly.", e);
+ }
+ if (!success && onFail != null) {
+ onFail.run();
+ }
+ }
+}
diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
index 367c8f5eb7f6..c053b2ed5adb 100644
--- a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
@@ -332,12 +332,18 @@ public class AlarmManagerService extends SystemService {
"REORDER_ALARMS_FOR_TARE",
});
- BroadcastOptions mOptsWithFgs = BroadcastOptions.makeBasic();
- BroadcastOptions mOptsWithFgsForAlarmClock = BroadcastOptions.makeBasic();
- BroadcastOptions mOptsWithoutFgs = BroadcastOptions.makeBasic();
- BroadcastOptions mOptsTimeBroadcast = BroadcastOptions.makeBasic();
+ BroadcastOptions mOptsWithFgs = makeBasicAlarmBroadcastOptions();
+ BroadcastOptions mOptsWithFgsForAlarmClock = makeBasicAlarmBroadcastOptions();
+ BroadcastOptions mOptsWithoutFgs = makeBasicAlarmBroadcastOptions();
+ BroadcastOptions mOptsTimeBroadcast = makeBasicAlarmBroadcastOptions();
ActivityOptions mActivityOptsRestrictBal = ActivityOptions.makeBasic();
- BroadcastOptions mBroadcastOptsRestrictBal = BroadcastOptions.makeBasic();
+ BroadcastOptions mBroadcastOptsRestrictBal = makeBasicAlarmBroadcastOptions();
+
+ private static BroadcastOptions makeBasicAlarmBroadcastOptions() {
+ final BroadcastOptions b = BroadcastOptions.makeBasic();
+ b.setAlarmBroadcast(true);
+ return b;
+ }
// TODO(b/172085676): Move inside alarm store.
private final SparseArray<AlarmManager.AlarmClockInfo> mNextAlarmClockForUser =
@@ -685,8 +691,6 @@ public class AlarmManagerService extends SystemService {
static final String KEY_ALLOW_WHILE_IDLE_COMPAT_WINDOW = "allow_while_idle_compat_window";
@VisibleForTesting
- static final String KEY_CRASH_NON_CLOCK_APPS = "crash_non_clock_apps";
- @VisibleForTesting
static final String KEY_PRIORITY_ALARM_DELAY = "priority_alarm_delay";
@VisibleForTesting
static final String KEY_EXACT_ALARM_DENY_LIST = "exact_alarm_deny_list";
@@ -734,8 +738,6 @@ public class AlarmManagerService extends SystemService {
private static final long DEFAULT_ALLOW_WHILE_IDLE_WINDOW = 60 * 60 * 1000; // 1 hour.
private static final long DEFAULT_ALLOW_WHILE_IDLE_COMPAT_WINDOW = 9 * 60 * 1000; // 9 mins.
- private static final boolean DEFAULT_CRASH_NON_CLOCK_APPS = true;
-
private static final long DEFAULT_PRIORITY_ALARM_DELAY = 9 * 60_000;
private static final long DEFAULT_MIN_DEVICE_IDLE_FUZZ = 2 * 60_000;
@@ -794,13 +796,6 @@ public class AlarmManagerService extends SystemService {
public long ALLOW_WHILE_IDLE_WINDOW = DEFAULT_ALLOW_WHILE_IDLE_WINDOW;
/**
- * Whether or not to crash callers that use setExactAndAllowWhileIdle or setAlarmClock
- * but don't hold the required permission. This is useful to catch broken
- * apps and reverting to a softer failure in case of broken apps.
- */
- public boolean CRASH_NON_CLOCK_APPS = DEFAULT_CRASH_NON_CLOCK_APPS;
-
- /**
* Minimum delay between two slots that an app can get for their prioritized alarms, while
* the device is in doze.
*/
@@ -994,10 +989,6 @@ public class AlarmManagerService extends SystemService {
KEY_TIME_TICK_ALLOWED_WHILE_IDLE,
DEFAULT_TIME_TICK_ALLOWED_WHILE_IDLE);
break;
- case KEY_CRASH_NON_CLOCK_APPS:
- CRASH_NON_CLOCK_APPS = properties.getBoolean(KEY_CRASH_NON_CLOCK_APPS,
- DEFAULT_CRASH_NON_CLOCK_APPS);
- break;
case KEY_PRIORITY_ALARM_DELAY:
PRIORITY_ALARM_DELAY = properties.getLong(KEY_PRIORITY_ALARM_DELAY,
DEFAULT_PRIORITY_ALARM_DELAY);
@@ -1255,9 +1246,6 @@ public class AlarmManagerService extends SystemService {
pw.print(KEY_TIME_TICK_ALLOWED_WHILE_IDLE, TIME_TICK_ALLOWED_WHILE_IDLE);
pw.println();
- pw.print(KEY_CRASH_NON_CLOCK_APPS, CRASH_NON_CLOCK_APPS);
- pw.println();
-
pw.print(KEY_PRIORITY_ALARM_DELAY);
pw.print("=");
TimeUtils.formatDuration(PRIORITY_ALARM_DELAY, pw);
@@ -2905,11 +2893,7 @@ public class AlarmManagerService extends SystemService {
+ Manifest.permission.SCHEDULE_EXACT_ALARM + " or "
+ Manifest.permission.USE_EXACT_ALARM + " to set "
+ "exact alarms.";
- if (mConstants.CRASH_NON_CLOCK_APPS) {
- throw new SecurityException(errorMessage);
- } else {
- Slog.wtf(TAG, errorMessage);
- }
+ throw new SecurityException(errorMessage);
}
// If the app is on the full system power allow-list (not except-idle),
// or the user-elected allow-list, or we're in a soft failure mode, we still
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index c17fbf19516b..90b78288d0c6 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -2590,9 +2590,9 @@ public abstract class AccessibilityService extends Service {
return;
}
final HardwareBuffer hardwareBuffer =
- result.getParcelable(KEY_ACCESSIBILITY_SCREENSHOT_HARDWAREBUFFER);
+ result.getParcelable(KEY_ACCESSIBILITY_SCREENSHOT_HARDWAREBUFFER, android.hardware.HardwareBuffer.class);
final ParcelableColorSpace colorSpace =
- result.getParcelable(KEY_ACCESSIBILITY_SCREENSHOT_COLORSPACE);
+ result.getParcelable(KEY_ACCESSIBILITY_SCREENSHOT_COLORSPACE, android.graphics.ParcelableColorSpace.class);
final ScreenshotResult screenshot = new ScreenshotResult(hardwareBuffer,
colorSpace.getColorSpace(),
result.getLong(KEY_ACCESSIBILITY_SCREENSHOT_TIMESTAMP));
diff --git a/core/java/android/accounts/AbstractAccountAuthenticator.java b/core/java/android/accounts/AbstractAccountAuthenticator.java
index 3807b503ce70..a3a361501b1c 100644
--- a/core/java/android/accounts/AbstractAccountAuthenticator.java
+++ b/core/java/android/accounts/AbstractAccountAuthenticator.java
@@ -938,7 +938,7 @@ public abstract class AbstractAccountAuthenticator {
String authTokenType = sessionBundle.getString(KEY_AUTH_TOKEN_TYPE);
Bundle options = sessionBundle.getBundle(KEY_OPTIONS);
String[] requiredFeatures = sessionBundle.getStringArray(KEY_REQUIRED_FEATURES);
- Account account = sessionBundle.getParcelable(KEY_ACCOUNT);
+ Account account = sessionBundle.getParcelable(KEY_ACCOUNT, android.accounts.Account.class);
boolean containsKeyAccount = sessionBundle.containsKey(KEY_ACCOUNT);
// Actual options passed to add account or update credentials flow.
diff --git a/core/java/android/accounts/AccountAuthenticatorActivity.java b/core/java/android/accounts/AccountAuthenticatorActivity.java
index 65ba35ff9e8d..5f620f356e7a 100644
--- a/core/java/android/accounts/AccountAuthenticatorActivity.java
+++ b/core/java/android/accounts/AccountAuthenticatorActivity.java
@@ -60,7 +60,7 @@ public class AccountAuthenticatorActivity extends Activity {
super.onCreate(icicle);
mAccountAuthenticatorResponse =
- getIntent().getParcelableExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE);
+ getIntent().getParcelableExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, android.accounts.AccountAuthenticatorResponse.class);
if (mAccountAuthenticatorResponse != null) {
mAccountAuthenticatorResponse.onRequestContinued();
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java
index fa9de6e27282..a573776e8670 100644
--- a/core/java/android/accounts/AccountManager.java
+++ b/core/java/android/accounts/AccountManager.java
@@ -2450,7 +2450,7 @@ public class AccountManager {
onError(ERROR_CODE_INVALID_RESPONSE, "null bundle returned");
return;
}
- Intent intent = bundle.getParcelable(KEY_INTENT);
+ Intent intent = bundle.getParcelable(KEY_INTENT, android.content.Intent.class);
if (intent != null && mActivity != null) {
// since the user provided an Activity we will silently start intents
// that we see
diff --git a/core/java/android/accounts/ChooseAccountActivity.java b/core/java/android/accounts/ChooseAccountActivity.java
index 6c8744f28864..20142a6d90e1 100644
--- a/core/java/android/accounts/ChooseAccountActivity.java
+++ b/core/java/android/accounts/ChooseAccountActivity.java
@@ -62,7 +62,7 @@ public class ChooseAccountActivity extends Activity {
.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
mAccounts = getIntent().getParcelableArrayExtra(AccountManager.KEY_ACCOUNTS);
mAccountManagerResponse =
- getIntent().getParcelableExtra(AccountManager.KEY_ACCOUNT_MANAGER_RESPONSE);
+ getIntent().getParcelableExtra(AccountManager.KEY_ACCOUNT_MANAGER_RESPONSE, android.accounts.AccountManagerResponse.class);
// KEY_ACCOUNTS is a required parameter
if (mAccounts == null) {
diff --git a/core/java/android/accounts/ChooseTypeAndAccountActivity.java b/core/java/android/accounts/ChooseTypeAndAccountActivity.java
index f623295dee3e..4d4a4d78ac81 100644
--- a/core/java/android/accounts/ChooseTypeAndAccountActivity.java
+++ b/core/java/android/accounts/ChooseTypeAndAccountActivity.java
@@ -186,7 +186,7 @@ public class ChooseTypeAndAccountActivity extends Activity
mExistingAccounts = null;
// If the selected account as specified in the intent matches one in the list we will
// show is as pre-selected.
- Account selectedAccount = (Account) intent.getParcelableExtra(EXTRA_SELECTED_ACCOUNT);
+ Account selectedAccount = (Account) intent.getParcelableExtra(EXTRA_SELECTED_ACCOUNT, android.accounts.Account.class);
if (selectedAccount != null) {
mSelectedAccountName = selectedAccount.name;
}
@@ -396,7 +396,7 @@ public class ChooseTypeAndAccountActivity extends Activity
try {
final Bundle accountManagerResult = accountManagerFuture.getResult();
final Intent intent = (Intent)accountManagerResult.getParcelable(
- AccountManager.KEY_INTENT);
+ AccountManager.KEY_INTENT, android.content.Intent.class);
if (intent != null) {
mPendingRequest = REQUEST_ADD_ACCOUNT;
mExistingAccounts = AccountManager.get(this).getAccountsForPackage(mCallingPackage,
diff --git a/core/java/android/accounts/GrantCredentialsPermissionActivity.java b/core/java/android/accounts/GrantCredentialsPermissionActivity.java
index 74dae0ecceb7..a89fae72d4ab 100644
--- a/core/java/android/accounts/GrantCredentialsPermissionActivity.java
+++ b/core/java/android/accounts/GrantCredentialsPermissionActivity.java
@@ -68,7 +68,7 @@ public class GrantCredentialsPermissionActivity extends Activity implements View
}
// Grant 'account'/'type' to mUID
- mAccount = extras.getParcelable(EXTRAS_ACCOUNT);
+ mAccount = extras.getParcelable(EXTRAS_ACCOUNT, android.accounts.Account.class);
mAuthTokenType = extras.getString(EXTRAS_AUTH_TOKEN_TYPE);
mUid = extras.getInt(EXTRAS_REQUESTING_UID);
final PackageManager pm = getPackageManager();
@@ -199,7 +199,7 @@ public class GrantCredentialsPermissionActivity extends Activity implements View
*/
public void finish() {
Intent intent = getIntent();
- AccountAuthenticatorResponse response = intent.getParcelableExtra(EXTRAS_RESPONSE);
+ AccountAuthenticatorResponse response = intent.getParcelableExtra(EXTRAS_RESPONSE, android.accounts.AccountAuthenticatorResponse.class);
if (response != null) {
// send the result bundle back if set, otherwise send an error.
if (mResultBundle != null) {
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 90c37d1999e1..493cb87e92d7 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -6496,7 +6496,7 @@ public class Activity extends ContextThemeWrapper
Intent intent = getIntent();
if (intent != null) {
try {
- Uri referrer = intent.getParcelableExtra(Intent.EXTRA_REFERRER);
+ Uri referrer = intent.getParcelableExtra(Intent.EXTRA_REFERRER, android.net.Uri.class);
if (referrer != null) {
return referrer;
}
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index 00ab559697f4..d9e09604bb05 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -1182,7 +1182,7 @@ public class ActivityOptions extends ComponentOptions {
} catch (RuntimeException e) {
Slog.w(TAG, e);
}
- mLaunchBounds = opts.getParcelable(KEY_LAUNCH_BOUNDS);
+ mLaunchBounds = opts.getParcelable(KEY_LAUNCH_BOUNDS, android.graphics.Rect.class);
mAnimationType = opts.getInt(KEY_ANIM_TYPE, ANIM_UNDEFINED);
switch (mAnimationType) {
case ANIM_CUSTOM:
@@ -1210,7 +1210,7 @@ public class ActivityOptions extends ComponentOptions {
case ANIM_THUMBNAIL_ASPECT_SCALE_UP:
case ANIM_THUMBNAIL_ASPECT_SCALE_DOWN:
// Unpackage the HardwareBuffer from the parceled thumbnail
- final HardwareBuffer buffer = opts.getParcelable(KEY_ANIM_THUMBNAIL);
+ final HardwareBuffer buffer = opts.getParcelable(KEY_ANIM_THUMBNAIL, android.hardware.HardwareBuffer.class);
if (buffer != null) {
mThumbnail = Bitmap.wrapHardwareBuffer(buffer, null);
}
@@ -1223,10 +1223,10 @@ public class ActivityOptions extends ComponentOptions {
break;
case ANIM_SCENE_TRANSITION:
- mTransitionReceiver = opts.getParcelable(KEY_TRANSITION_COMPLETE_LISTENER);
+ mTransitionReceiver = opts.getParcelable(KEY_TRANSITION_COMPLETE_LISTENER, android.os.ResultReceiver.class);
mIsReturning = opts.getBoolean(KEY_TRANSITION_IS_RETURNING, false);
mSharedElementNames = opts.getStringArrayList(KEY_TRANSITION_SHARED_ELEMENTS);
- mResultData = opts.getParcelable(KEY_RESULT_DATA);
+ mResultData = opts.getParcelable(KEY_RESULT_DATA, android.content.Intent.class);
mResultCode = opts.getInt(KEY_RESULT_CODE);
mExitCoordinatorIndex = opts.getInt(KEY_EXIT_COORDINATOR_INDEX);
break;
@@ -1234,10 +1234,10 @@ public class ActivityOptions extends ComponentOptions {
mLockTaskMode = opts.getBoolean(KEY_LOCK_TASK_MODE, false);
mLaunchDisplayId = opts.getInt(KEY_LAUNCH_DISPLAY_ID, INVALID_DISPLAY);
mCallerDisplayId = opts.getInt(KEY_CALLER_DISPLAY_ID, INVALID_DISPLAY);
- mLaunchTaskDisplayArea = opts.getParcelable(KEY_LAUNCH_TASK_DISPLAY_AREA_TOKEN);
+ mLaunchTaskDisplayArea = opts.getParcelable(KEY_LAUNCH_TASK_DISPLAY_AREA_TOKEN, android.window.WindowContainerToken.class);
mLaunchTaskDisplayAreaFeatureId = opts.getInt(KEY_LAUNCH_TASK_DISPLAY_AREA_FEATURE_ID,
FEATURE_UNDEFINED);
- mLaunchRootTask = opts.getParcelable(KEY_LAUNCH_ROOT_TASK_TOKEN);
+ mLaunchRootTask = opts.getParcelable(KEY_LAUNCH_ROOT_TASK_TOKEN, android.window.WindowContainerToken.class);
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);
@@ -1263,23 +1263,23 @@ public class ActivityOptions extends ComponentOptions {
mAnimationFinishedListener = IRemoteCallback.Stub.asInterface(
opts.getBinder(KEY_ANIMATION_FINISHED_LISTENER));
}
- mSourceInfo = opts.getParcelable(KEY_SOURCE_INFO);
+ mSourceInfo = opts.getParcelable(KEY_SOURCE_INFO, android.app.ActivityOptions.SourceInfo.class);
mRotationAnimationHint = opts.getInt(KEY_ROTATION_ANIMATION_HINT, -1);
mAppVerificationBundle = opts.getBundle(KEY_INSTANT_APP_VERIFICATION_BUNDLE);
if (opts.containsKey(KEY_SPECS_FUTURE)) {
mSpecsFuture = IAppTransitionAnimationSpecsFuture.Stub.asInterface(opts.getBinder(
KEY_SPECS_FUTURE));
}
- mRemoteAnimationAdapter = opts.getParcelable(KEY_REMOTE_ANIMATION_ADAPTER);
+ mRemoteAnimationAdapter = opts.getParcelable(KEY_REMOTE_ANIMATION_ADAPTER, android.view.RemoteAnimationAdapter.class);
mLaunchCookie = opts.getBinder(KEY_LAUNCH_COOKIE);
- mRemoteTransition = opts.getParcelable(KEY_REMOTE_TRANSITION);
+ mRemoteTransition = opts.getParcelable(KEY_REMOTE_TRANSITION, android.window.RemoteTransition.class);
mOverrideTaskTransition = opts.getBoolean(KEY_OVERRIDE_TASK_TRANSITION);
mSplashScreenThemeResName = opts.getString(KEY_SPLASH_SCREEN_THEME);
mRemoveWithTaskOrganizer = opts.getBoolean(KEY_REMOVE_WITH_TASK_ORGANIZER);
mLaunchedFromBubble = opts.getBoolean(KEY_LAUNCHED_FROM_BUBBLE);
mTransientLaunch = opts.getBoolean(KEY_TRANSIENT_LAUNCH);
mSplashScreenStyle = opts.getInt(KEY_SPLASH_SCREEN_STYLE);
- mLaunchIntoPipParams = opts.getParcelable(KEY_LAUNCH_INTO_PIP_PARAMS);
+ mLaunchIntoPipParams = opts.getParcelable(KEY_LAUNCH_INTO_PIP_PARAMS, android.app.PictureInPictureParams.class);
mIsEligibleForLegacyPermissionPrompt =
opts.getBoolean(KEY_LEGACY_PERMISSION_PROMPT_ELIGIBLE);
mDismissKeyguard = opts.getBoolean(KEY_DISMISS_KEYGUARD);
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 8a9ec0984ec7..2a83cbddd3dc 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -5885,20 +5885,20 @@ public final class ActivityThread extends ClientTransactionHandler
final boolean movedToDifferentDisplay = isDifferentDisplay(activity.getDisplayId(),
displayId);
- final Configuration currentConfig = activity.mCurrentConfig;
- final int diff = currentConfig.diffPublicOnly(newConfig);
- final boolean hasPublicConfigChange = diff != 0;
+ final Configuration currentResConfig = activity.getResources().getConfiguration();
+ final int diff = currentResConfig.diffPublicOnly(newConfig);
+ final boolean hasPublicResConfigChange = diff != 0;
final ActivityClientRecord r = getActivityClient(activityToken);
// TODO(b/173090263): Use diff instead after the improvement of AssetManager and
// ResourcesImpl constructions.
- final boolean shouldUpdateResources = hasPublicConfigChange
- || shouldUpdateResources(activityToken, currentConfig, newConfig, amOverrideConfig,
- movedToDifferentDisplay, hasPublicConfigChange);
- final boolean shouldReportChange = shouldReportChange(diff, currentConfig, newConfig,
+ final boolean shouldUpdateResources = hasPublicResConfigChange
+ || shouldUpdateResources(activityToken, currentResConfig, newConfig,
+ amOverrideConfig, movedToDifferentDisplay, hasPublicResConfigChange);
+ final boolean shouldReportChange = shouldReportChange(activity.mCurrentConfig, newConfig,
r != null ? r.mSizeConfigurations : null,
activity.mActivityInfo.getRealConfigChanged());
// Nothing significant, don't proceed with updating and reporting.
- if (!shouldUpdateResources) {
+ if (!shouldUpdateResources && !shouldReportChange) {
return null;
}
@@ -5918,9 +5918,6 @@ public final class ActivityThread extends ClientTransactionHandler
amOverrideConfig, contextThemeWrapperOverrideConfig);
mResourcesManager.updateResourcesForActivity(activityToken, finalOverrideConfig, displayId);
- activity.mConfigChangeFlags = 0;
- activity.mCurrentConfig = new Configuration(newConfig);
-
// Apply the ContextThemeWrapper override if necessary.
// NOTE: Make sure the configurations are not modified, as they are treated as immutable
// in many places.
@@ -5931,8 +5928,10 @@ public final class ActivityThread extends ClientTransactionHandler
activity.dispatchMovedToDisplay(displayId, configToReport);
}
+ activity.mConfigChangeFlags = 0;
if (shouldReportChange) {
activity.mCalled = false;
+ activity.mCurrentConfig = new Configuration(newConfig);
activity.onConfigurationChanged(configToReport);
if (!activity.mCalled) {
throw new SuperNotCalledException("Activity " + activity.getLocalClassName() +
@@ -5947,8 +5946,6 @@ public final class ActivityThread extends ClientTransactionHandler
* Returns {@code true} if {@link Activity#onConfigurationChanged(Configuration)} should be
* dispatched.
*
- * @param publicDiff Usually computed by {@link Configuration#diffPublicOnly(Configuration)}.
- * This parameter is to prevent we compute it again.
* @param currentConfig The current configuration cached in {@link Activity#mCurrentConfig}.
* It is {@code null} before the first config update from the server side.
* @param newConfig The updated {@link Configuration}
@@ -5957,9 +5954,10 @@ public final class ActivityThread extends ClientTransactionHandler
* @return {@code true} if the config change should be reported to the Activity
*/
@VisibleForTesting
- public static boolean shouldReportChange(int publicDiff, @Nullable Configuration currentConfig,
+ public static boolean shouldReportChange(@Nullable Configuration currentConfig,
@NonNull Configuration newConfig, @Nullable SizeConfigurationBuckets sizeBuckets,
int handledConfigChanges) {
+ final int publicDiff = currentConfig.diffPublicOnly(newConfig);
// Don't report the change if there's no public diff between current and new config.
if (publicDiff == 0) {
return false;
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 125f5e4e1a21..6092b307d50e 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -7693,7 +7693,7 @@ public class AppOpsManager {
request.mOpNames, request.mHistoryFlags, request.mFilter,
request.mBeginTimeMillis, request.mEndTimeMillis, request.mFlags,
new RemoteCallback((result) -> {
- final HistoricalOps ops = result.getParcelable(KEY_HISTORICAL_OPS);
+ final HistoricalOps ops = result.getParcelable(KEY_HISTORICAL_OPS, android.app.AppOpsManager.HistoricalOps.class);
final long identity = Binder.clearCallingIdentity();
try {
executor.execute(() -> callback.accept(ops));
@@ -7733,7 +7733,7 @@ public class AppOpsManager {
request.mAttributionTag, request.mOpNames, request.mHistoryFlags,
request.mFilter, request.mBeginTimeMillis, request.mEndTimeMillis,
request.mFlags, new RemoteCallback((result) -> {
- final HistoricalOps ops = result.getParcelable(KEY_HISTORICAL_OPS);
+ final HistoricalOps ops = result.getParcelable(KEY_HISTORICAL_OPS, android.app.AppOpsManager.HistoricalOps.class);
final long identity = Binder.clearCallingIdentity();
try {
executor.execute(() -> callback.accept(ops));
diff --git a/core/java/android/app/BroadcastOptions.java b/core/java/android/app/BroadcastOptions.java
index 56f8760f6059..f0e14483d98a 100644
--- a/core/java/android/app/BroadcastOptions.java
+++ b/core/java/android/app/BroadcastOptions.java
@@ -53,6 +53,7 @@ public class BroadcastOptions extends ComponentOptions {
private String[] mRequireNoneOfPermissions;
private long mRequireCompatChangeId = CHANGE_INVALID;
private boolean mRequireCompatChangeEnabled = true;
+ private boolean mIsAlarmBroadcast = false;
private long mIdForResponseEvent;
/**
@@ -149,6 +150,13 @@ public class BroadcastOptions extends ComponentOptions {
"android:broadcast.requireCompatChangeEnabled";
/**
+ * Corresponds to {@link #setAlarmBroadcast(boolean)}
+ * @hide
+ */
+ public static final String KEY_ALARM_BROADCAST =
+ "android:broadcast.is_alarm";
+
+ /**
* @hide
* @deprecated Use {@link android.os.PowerExemptionManager#
* TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_ALLOWED} instead.
@@ -207,6 +215,7 @@ public class BroadcastOptions extends ComponentOptions {
mRequireCompatChangeId = opts.getLong(KEY_REQUIRE_COMPAT_CHANGE_ID, CHANGE_INVALID);
mRequireCompatChangeEnabled = opts.getBoolean(KEY_REQUIRE_COMPAT_CHANGE_ENABLED, true);
mIdForResponseEvent = opts.getLong(KEY_ID_FOR_RESPONSE_EVENT);
+ mIsAlarmBroadcast = opts.getBoolean(KEY_ALARM_BROADCAST, false);
}
/**
@@ -498,6 +507,27 @@ public class BroadcastOptions extends ComponentOptions {
mRequireCompatChangeEnabled = true;
}
+ /**
+ * When set, this broadcast will be understood as having originated from an
+ * alarm going off. Only the OS itself can use this option; uses by other
+ * senders will be ignored.
+ * @hide
+ *
+ * @param senderIsAlarm Whether the broadcast is alarm-triggered.
+ */
+ public void setAlarmBroadcast(boolean senderIsAlarm) {
+ mIsAlarmBroadcast = senderIsAlarm;
+ }
+
+ /**
+ * Did this broadcast originate from an alarm triggering?
+ * @return true if this broadcast is an alarm message, false otherwise
+ * @hide
+ */
+ public boolean isAlarmBroadcast() {
+ return mIsAlarmBroadcast;
+ }
+
/** {@hide} */
public long getRequireCompatChangeId() {
return mRequireCompatChangeId;
@@ -560,6 +590,9 @@ public class BroadcastOptions extends ComponentOptions {
b.putInt(KEY_TEMPORARY_APP_ALLOWLIST_REASON_CODE, mTemporaryAppAllowlistReasonCode);
b.putString(KEY_TEMPORARY_APP_ALLOWLIST_REASON, mTemporaryAppAllowlistReason);
}
+ if (mIsAlarmBroadcast) {
+ b.putBoolean(KEY_ALARM_BROADCAST, true);
+ }
if (mMinManifestReceiverApiLevel != 0) {
b.putInt(KEY_MIN_MANIFEST_RECEIVER_API_LEVEL, mMinManifestReceiverApiLevel);
}
diff --git a/core/java/android/app/ExitTransitionCoordinator.java b/core/java/android/app/ExitTransitionCoordinator.java
index cd84e5671753..930750e138f8 100644
--- a/core/java/android/app/ExitTransitionCoordinator.java
+++ b/core/java/android/app/ExitTransitionCoordinator.java
@@ -81,7 +81,7 @@ public class ExitTransitionCoordinator extends ActivityTransitionCoordinator {
switch (resultCode) {
case MSG_SET_REMOTE_RECEIVER:
stopCancel();
- mResultReceiver = resultData.getParcelable(KEY_REMOTE_RECEIVER);
+ mResultReceiver = resultData.getParcelable(KEY_REMOTE_RECEIVER, android.os.ResultReceiver.class);
if (mIsCanceled) {
mResultReceiver.send(MSG_CANCEL, null);
mResultReceiver = null;
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index e82073380394..343adb82c8eb 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -2842,7 +2842,7 @@ public class Notification implements Parcelable
visitor.accept(Uri.parse(extras.getString(EXTRA_BACKGROUND_IMAGE_URI)));
}
- ArrayList<Person> people = extras.getParcelableArrayList(EXTRA_PEOPLE_LIST);
+ ArrayList<Person> people = extras.getParcelableArrayList(EXTRA_PEOPLE_LIST, android.app.Person.class);
if (people != null && !people.isEmpty()) {
for (Person p : people) {
visitor.accept(p.getIconUri());
@@ -3882,7 +3882,7 @@ public class Notification implements Parcelable
}
if (mN.extras.containsKey(EXTRA_PEOPLE_LIST)) {
- ArrayList<Person> people = mN.extras.getParcelableArrayList(EXTRA_PEOPLE_LIST);
+ ArrayList<Person> people = mN.extras.getParcelableArrayList(EXTRA_PEOPLE_LIST, android.app.Person.class);
mPersonList.addAll(people);
}
@@ -9777,7 +9777,7 @@ public class Notification implements Parcelable
mCallType = extras.getInt(EXTRA_CALL_TYPE);
mIsVideo = extras.getBoolean(EXTRA_CALL_IS_VIDEO);
mPerson = extras.getParcelable(EXTRA_CALL_PERSON, Person.class);
- mVerificationIcon = extras.getParcelable(EXTRA_VERIFICATION_ICON);
+ mVerificationIcon = extras.getParcelable(EXTRA_VERIFICATION_ICON, android.graphics.drawable.Icon.class);
mVerificationText = extras.getCharSequence(EXTRA_VERIFICATION_TEXT);
mAnswerIntent = extras.getParcelable(EXTRA_ANSWER_INTENT, PendingIntent.class);
mDeclineIntent = extras.getParcelable(EXTRA_DECLINE_INTENT, PendingIntent.class);
@@ -10895,7 +10895,7 @@ public class Notification implements Parcelable
public WearableExtender(Notification notif) {
Bundle wearableBundle = notif.extras.getBundle(EXTRA_WEARABLE_EXTENSIONS);
if (wearableBundle != null) {
- List<Action> actions = wearableBundle.getParcelableArrayList(KEY_ACTIONS);
+ List<Action> actions = wearableBundle.getParcelableArrayList(KEY_ACTIONS, android.app.Notification.Action.class);
if (actions != null) {
mActions.addAll(actions);
}
diff --git a/core/java/android/app/RecoverableSecurityException.java b/core/java/android/app/RecoverableSecurityException.java
index 21fb2a6927aa..176f14133641 100644
--- a/core/java/android/app/RecoverableSecurityException.java
+++ b/core/java/android/app/RecoverableSecurityException.java
@@ -164,7 +164,7 @@ public final class RecoverableSecurityException extends SecurityException implem
public static class LocalDialog extends DialogFragment {
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
- final RecoverableSecurityException e = getArguments().getParcelable(TAG);
+ final RecoverableSecurityException e = getArguments().getParcelable(TAG, android.app.RecoverableSecurityException.class);
return new AlertDialog.Builder(getActivity())
.setMessage(e.mUserMessage)
.setPositiveButton(e.mUserAction.getTitle(), (dialog, which) -> {
diff --git a/core/java/android/app/RemoteInput.java b/core/java/android/app/RemoteInput.java
index 36c524b57fe4..88161091b6ea 100644
--- a/core/java/android/app/RemoteInput.java
+++ b/core/java/android/app/RemoteInput.java
@@ -429,7 +429,7 @@ public final class RemoteInput implements Parcelable {
if (clipDataIntent == null) {
return null;
}
- return clipDataIntent.getExtras().getParcelable(EXTRA_RESULTS_DATA);
+ return clipDataIntent.getExtras().getParcelable(EXTRA_RESULTS_DATA, android.os.Bundle.class);
}
/**
diff --git a/core/java/android/app/SearchDialog.java b/core/java/android/app/SearchDialog.java
index 9fe894b75455..57576041408b 100644
--- a/core/java/android/app/SearchDialog.java
+++ b/core/java/android/app/SearchDialog.java
@@ -352,7 +352,7 @@ public class SearchDialog extends Dialog {
public void onRestoreInstanceState(Bundle savedInstanceState) {
if (savedInstanceState == null) return;
- ComponentName launchComponent = savedInstanceState.getParcelable(INSTANCE_KEY_COMPONENT);
+ ComponentName launchComponent = savedInstanceState.getParcelable(INSTANCE_KEY_COMPONENT, android.content.ComponentName.class);
Bundle appSearchData = savedInstanceState.getBundle(INSTANCE_KEY_APPDATA);
String userQuery = savedInstanceState.getString(INSTANCE_KEY_USER_QUERY);
diff --git a/core/java/android/app/SharedElementCallback.java b/core/java/android/app/SharedElementCallback.java
index 8eb7e7246976..594d297a1979 100644
--- a/core/java/android/app/SharedElementCallback.java
+++ b/core/java/android/app/SharedElementCallback.java
@@ -234,8 +234,8 @@ public abstract class SharedElementCallback {
View view = null;
if (snapshot instanceof Bundle) {
Bundle bundle = (Bundle) snapshot;
- HardwareBuffer buffer = bundle.getParcelable(BUNDLE_SNAPSHOT_HARDWARE_BUFFER);
- Bitmap bitmap = bundle.getParcelable(BUNDLE_SNAPSHOT_BITMAP);
+ HardwareBuffer buffer = bundle.getParcelable(BUNDLE_SNAPSHOT_HARDWARE_BUFFER, android.hardware.HardwareBuffer.class);
+ Bitmap bitmap = bundle.getParcelable(BUNDLE_SNAPSHOT_BITMAP, android.graphics.Bitmap.class);
if (buffer == null && bitmap == null) {
return null;
}
diff --git a/core/java/android/app/admin/DelegatedAdminReceiver.java b/core/java/android/app/admin/DelegatedAdminReceiver.java
index c74ddb285644..30509d649736 100644
--- a/core/java/android/app/admin/DelegatedAdminReceiver.java
+++ b/core/java/android/app/admin/DelegatedAdminReceiver.java
@@ -156,7 +156,7 @@ public class DelegatedAdminReceiver extends BroadcastReceiver {
if (ACTION_CHOOSE_PRIVATE_KEY_ALIAS.equals(action)) {
int uid = intent.getIntExtra(EXTRA_CHOOSE_PRIVATE_KEY_SENDER_UID, -1);
- Uri uri = intent.getParcelableExtra(EXTRA_CHOOSE_PRIVATE_KEY_URI);
+ Uri uri = intent.getParcelableExtra(EXTRA_CHOOSE_PRIVATE_KEY_URI, android.net.Uri.class);
String alias = intent.getStringExtra(EXTRA_CHOOSE_PRIVATE_KEY_ALIAS);
String chosenAlias = onChoosePrivateKeyAlias(context, intent, uid, uri, alias);
setResultData(chosenAlias);
diff --git a/core/java/android/app/admin/DeviceAdminReceiver.java b/core/java/android/app/admin/DeviceAdminReceiver.java
index 27e8c46ca548..f21e11ab35cc 100644
--- a/core/java/android/app/admin/DeviceAdminReceiver.java
+++ b/core/java/android/app/admin/DeviceAdminReceiver.java
@@ -1179,11 +1179,11 @@ public class DeviceAdminReceiver extends BroadcastReceiver {
}
if (ACTION_PASSWORD_CHANGED.equals(action)) {
- onPasswordChanged(context, intent, intent.getParcelableExtra(Intent.EXTRA_USER));
+ onPasswordChanged(context, intent, intent.getParcelableExtra(Intent.EXTRA_USER, android.os.UserHandle.class));
} else if (ACTION_PASSWORD_FAILED.equals(action)) {
- onPasswordFailed(context, intent, intent.getParcelableExtra(Intent.EXTRA_USER));
+ onPasswordFailed(context, intent, intent.getParcelableExtra(Intent.EXTRA_USER, android.os.UserHandle.class));
} else if (ACTION_PASSWORD_SUCCEEDED.equals(action)) {
- onPasswordSucceeded(context, intent, intent.getParcelableExtra(Intent.EXTRA_USER));
+ onPasswordSucceeded(context, intent, intent.getParcelableExtra(Intent.EXTRA_USER, android.os.UserHandle.class));
} else if (ACTION_DEVICE_ADMIN_ENABLED.equals(action)) {
onEnabled(context, intent);
} else if (ACTION_DEVICE_ADMIN_DISABLE_REQUESTED.equals(action)) {
@@ -1195,12 +1195,12 @@ public class DeviceAdminReceiver extends BroadcastReceiver {
} else if (ACTION_DEVICE_ADMIN_DISABLED.equals(action)) {
onDisabled(context, intent);
} else if (ACTION_PASSWORD_EXPIRING.equals(action)) {
- onPasswordExpiring(context, intent, intent.getParcelableExtra(Intent.EXTRA_USER));
+ onPasswordExpiring(context, intent, intent.getParcelableExtra(Intent.EXTRA_USER, android.os.UserHandle.class));
} else if (ACTION_PROFILE_PROVISIONING_COMPLETE.equals(action)) {
onProfileProvisioningComplete(context, intent);
} else if (ACTION_CHOOSE_PRIVATE_KEY_ALIAS.equals(action)) {
int uid = intent.getIntExtra(EXTRA_CHOOSE_PRIVATE_KEY_SENDER_UID, -1);
- Uri uri = intent.getParcelableExtra(EXTRA_CHOOSE_PRIVATE_KEY_URI);
+ Uri uri = intent.getParcelableExtra(EXTRA_CHOOSE_PRIVATE_KEY_URI, android.net.Uri.class);
String alias = intent.getStringExtra(EXTRA_CHOOSE_PRIVATE_KEY_ALIAS);
String chosenAlias = onChoosePrivateKeyAlias(context, intent, uid, uri, alias);
setResultData(chosenAlias);
@@ -1228,22 +1228,22 @@ public class DeviceAdminReceiver extends BroadcastReceiver {
int networkLogsCount = intent.getIntExtra(EXTRA_NETWORK_LOGS_COUNT, 0);
onNetworkLogsAvailable(context, intent, batchToken, networkLogsCount);
} else if (ACTION_USER_ADDED.equals(action)) {
- onUserAdded(context, intent, intent.getParcelableExtra(Intent.EXTRA_USER));
+ onUserAdded(context, intent, intent.getParcelableExtra(Intent.EXTRA_USER, android.os.UserHandle.class));
} else if (ACTION_USER_REMOVED.equals(action)) {
- onUserRemoved(context, intent, intent.getParcelableExtra(Intent.EXTRA_USER));
+ onUserRemoved(context, intent, intent.getParcelableExtra(Intent.EXTRA_USER, android.os.UserHandle.class));
} else if (ACTION_USER_STARTED.equals(action)) {
- onUserStarted(context, intent, intent.getParcelableExtra(Intent.EXTRA_USER));
+ onUserStarted(context, intent, intent.getParcelableExtra(Intent.EXTRA_USER, android.os.UserHandle.class));
} else if (ACTION_USER_STOPPED.equals(action)) {
- onUserStopped(context, intent, intent.getParcelableExtra(Intent.EXTRA_USER));
+ onUserStopped(context, intent, intent.getParcelableExtra(Intent.EXTRA_USER, android.os.UserHandle.class));
} else if (ACTION_USER_SWITCHED.equals(action)) {
- onUserSwitched(context, intent, intent.getParcelableExtra(Intent.EXTRA_USER));
+ onUserSwitched(context, intent, intent.getParcelableExtra(Intent.EXTRA_USER, android.os.UserHandle.class));
} else if (ACTION_TRANSFER_OWNERSHIP_COMPLETE.equals(action)) {
PersistableBundle bundle =
- intent.getParcelableExtra(EXTRA_TRANSFER_OWNERSHIP_ADMIN_EXTRAS_BUNDLE);
+ intent.getParcelableExtra(EXTRA_TRANSFER_OWNERSHIP_ADMIN_EXTRAS_BUNDLE, android.os.PersistableBundle.class);
onTransferOwnershipComplete(context, bundle);
} else if (ACTION_AFFILIATED_PROFILE_TRANSFER_OWNERSHIP_COMPLETE.equals(action)) {
onTransferAffiliatedProfileOwnershipComplete(context,
- intent.getParcelableExtra(Intent.EXTRA_USER));
+ intent.getParcelableExtra(Intent.EXTRA_USER, android.os.UserHandle.class));
} else if (ACTION_OPERATION_SAFETY_STATE_CHANGED.equals(action)) {
onOperationSafetyStateChanged(context, intent);
} else if (ACTION_COMPLIANCE_ACKNOWLEDGEMENT_REQUIRED.equals(action)) {
diff --git a/core/java/android/app/ambientcontext/AmbientContextManager.java b/core/java/android/app/ambientcontext/AmbientContextManager.java
index dd1dd0c75f76..308c5edfd0f4 100644
--- a/core/java/android/app/ambientcontext/AmbientContextManager.java
+++ b/core/java/android/app/ambientcontext/AmbientContextManager.java
@@ -117,7 +117,7 @@ public final class AmbientContextManager {
*/
@NonNull public static List<AmbientContextEvent> getEventsFromIntent(@NonNull Intent intent) {
if (intent.hasExtra(AmbientContextManager.EXTRA_AMBIENT_CONTEXT_EVENTS)) {
- return intent.getParcelableArrayListExtra(EXTRA_AMBIENT_CONTEXT_EVENTS);
+ return intent.getParcelableArrayListExtra(EXTRA_AMBIENT_CONTEXT_EVENTS, android.app.ambientcontext.AmbientContextEvent.class);
} else {
return new ArrayList<>();
}
diff --git a/core/java/android/app/slice/SliceManager.java b/core/java/android/app/slice/SliceManager.java
index ed4ea749c181..1e4934ebb6f5 100644
--- a/core/java/android/app/slice/SliceManager.java
+++ b/core/java/android/app/slice/SliceManager.java
@@ -231,7 +231,7 @@ public class SliceManager {
extras.putParcelable(SliceProvider.EXTRA_BIND_URI, uri);
final Bundle res = provider.call(
SliceProvider.METHOD_GET_DESCENDANTS, null, extras);
- return res.getParcelableArrayList(SliceProvider.EXTRA_SLICE_DESCENDANTS);
+ return res.getParcelableArrayList(SliceProvider.EXTRA_SLICE_DESCENDANTS, android.net.Uri.class);
}
} catch (RemoteException e) {
Log.e(TAG, "Unable to get slice descendants", e);
@@ -264,7 +264,7 @@ public class SliceManager {
if (res == null) {
return null;
}
- return res.getParcelable(SliceProvider.EXTRA_SLICE);
+ return res.getParcelable(SliceProvider.EXTRA_SLICE, android.app.slice.Slice.class);
} catch (RemoteException e) {
// Arbitrary and not worth documenting, as Activity
// Manager will kill this process shortly anyway.
@@ -323,7 +323,7 @@ public class SliceManager {
if (res == null) {
return null;
}
- return res.getParcelable(SliceProvider.EXTRA_SLICE);
+ return res.getParcelable(SliceProvider.EXTRA_SLICE, android.net.Uri.class);
} catch (RemoteException e) {
// Arbitrary and not worth documenting, as Activity
// Manager will kill this process shortly anyway.
@@ -403,7 +403,7 @@ public class SliceManager {
if (res == null) {
return null;
}
- return res.getParcelable(SliceProvider.EXTRA_SLICE);
+ return res.getParcelable(SliceProvider.EXTRA_SLICE, android.app.slice.Slice.class);
} catch (RemoteException e) {
// Arbitrary and not worth documenting, as Activity
// Manager will kill this process shortly anyway.
diff --git a/core/java/android/app/slice/SliceProvider.java b/core/java/android/app/slice/SliceProvider.java
index e6c88a31a1b2..63835cb5446b 100644
--- a/core/java/android/app/slice/SliceProvider.java
+++ b/core/java/android/app/slice/SliceProvider.java
@@ -352,8 +352,8 @@ public abstract class SliceProvider extends ContentProvider {
public Bundle call(String method, String arg, Bundle extras) {
if (method.equals(METHOD_SLICE)) {
Uri uri = getUriWithoutUserId(validateIncomingUriOrNull(
- extras.getParcelable(EXTRA_BIND_URI)));
- List<SliceSpec> supportedSpecs = extras.getParcelableArrayList(EXTRA_SUPPORTED_SPECS);
+ extras.getParcelable(EXTRA_BIND_URI, android.net.Uri.class)));
+ List<SliceSpec> supportedSpecs = extras.getParcelableArrayList(EXTRA_SUPPORTED_SPECS, android.app.slice.SliceSpec.class);
String callingPackage = getCallingPackage();
int callingUid = Binder.getCallingUid();
@@ -364,10 +364,10 @@ public abstract class SliceProvider extends ContentProvider {
b.putParcelable(EXTRA_SLICE, s);
return b;
} else if (method.equals(METHOD_MAP_INTENT)) {
- Intent intent = extras.getParcelable(EXTRA_INTENT);
+ Intent intent = extras.getParcelable(EXTRA_INTENT, android.content.Intent.class);
if (intent == null) return null;
Uri uri = validateIncomingUriOrNull(onMapIntentToUri(intent));
- List<SliceSpec> supportedSpecs = extras.getParcelableArrayList(EXTRA_SUPPORTED_SPECS);
+ List<SliceSpec> supportedSpecs = extras.getParcelableArrayList(EXTRA_SUPPORTED_SPECS, android.app.slice.SliceSpec.class);
Bundle b = new Bundle();
if (uri != null) {
Slice s = handleBindSlice(uri, supportedSpecs, getCallingPackage(),
@@ -378,7 +378,7 @@ public abstract class SliceProvider extends ContentProvider {
}
return b;
} else if (method.equals(METHOD_MAP_ONLY_INTENT)) {
- Intent intent = extras.getParcelable(EXTRA_INTENT);
+ Intent intent = extras.getParcelable(EXTRA_INTENT, android.content.Intent.class);
if (intent == null) return null;
Uri uri = validateIncomingUriOrNull(onMapIntentToUri(intent));
Bundle b = new Bundle();
@@ -386,21 +386,21 @@ public abstract class SliceProvider extends ContentProvider {
return b;
} else if (method.equals(METHOD_PIN)) {
Uri uri = getUriWithoutUserId(validateIncomingUriOrNull(
- extras.getParcelable(EXTRA_BIND_URI)));
+ extras.getParcelable(EXTRA_BIND_URI, android.net.Uri.class)));
if (Binder.getCallingUid() != Process.SYSTEM_UID) {
throw new SecurityException("Only the system can pin/unpin slices");
}
handlePinSlice(uri);
} else if (method.equals(METHOD_UNPIN)) {
Uri uri = getUriWithoutUserId(validateIncomingUriOrNull(
- extras.getParcelable(EXTRA_BIND_URI)));
+ extras.getParcelable(EXTRA_BIND_URI, android.net.Uri.class)));
if (Binder.getCallingUid() != Process.SYSTEM_UID) {
throw new SecurityException("Only the system can pin/unpin slices");
}
handleUnpinSlice(uri);
} else if (method.equals(METHOD_GET_DESCENDANTS)) {
Uri uri = getUriWithoutUserId(
- validateIncomingUriOrNull(extras.getParcelable(EXTRA_BIND_URI)));
+ validateIncomingUriOrNull(extras.getParcelable(EXTRA_BIND_URI, android.net.Uri.class)));
Bundle b = new Bundle();
b.putParcelableArrayList(EXTRA_SLICE_DESCENDANTS,
new ArrayList<>(handleGetDescendants(uri)));
diff --git a/core/java/android/content/ClipboardManager.java b/core/java/android/content/ClipboardManager.java
index d41cda102103..85af87722ed2 100644
--- a/core/java/android/content/ClipboardManager.java
+++ b/core/java/android/content/ClipboardManager.java
@@ -129,7 +129,11 @@ public class ClipboardManager extends android.text.ClipboardManager {
try {
Objects.requireNonNull(clip);
clip.prepareToLeaveProcess(true);
- mService.setPrimaryClip(clip, mContext.getOpPackageName(), mContext.getUserId());
+ mService.setPrimaryClip(
+ clip,
+ mContext.getOpPackageName(),
+ mContext.getAttributionTag(),
+ mContext.getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -154,7 +158,11 @@ public class ClipboardManager extends android.text.ClipboardManager {
Objects.requireNonNull(sourcePackage);
clip.prepareToLeaveProcess(true);
mService.setPrimaryClipAsPackage(
- clip, mContext.getOpPackageName(), mContext.getUserId(), sourcePackage);
+ clip,
+ mContext.getOpPackageName(),
+ mContext.getAttributionTag(),
+ mContext.getUserId(),
+ sourcePackage);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -167,7 +175,10 @@ public class ClipboardManager extends android.text.ClipboardManager {
*/
public void clearPrimaryClip() {
try {
- mService.clearPrimaryClip(mContext.getOpPackageName(), mContext.getUserId());
+ mService.clearPrimaryClip(
+ mContext.getOpPackageName(),
+ mContext.getAttributionTag(),
+ mContext.getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -183,24 +194,29 @@ public class ClipboardManager extends android.text.ClipboardManager {
*/
public @Nullable ClipData getPrimaryClip() {
try {
- return mService.getPrimaryClip(mContext.getOpPackageName(), mContext.getUserId());
+ return mService.getPrimaryClip(
+ mContext.getOpPackageName(),
+ mContext.getAttributionTag(),
+ mContext.getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/**
- * Returns a description of the current primary clip on the clipboard
- * but not a copy of its data.
+ * Returns a description of the current primary clip on the clipboard but not a copy of its
+ * data.
*
- * <em>If the application is not the default IME or does not have input focus this return
+ * <p><em>If the application is not the default IME or does not have input focus this return
* {@code null}.</em>
*
* @see #setPrimaryClip(ClipData)
*/
public @Nullable ClipDescription getPrimaryClipDescription() {
try {
- return mService.getPrimaryClipDescription(mContext.getOpPackageName(),
+ return mService.getPrimaryClipDescription(
+ mContext.getOpPackageName(),
+ mContext.getAttributionTag(),
mContext.getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -215,7 +231,10 @@ public class ClipboardManager extends android.text.ClipboardManager {
*/
public boolean hasPrimaryClip() {
try {
- return mService.hasPrimaryClip(mContext.getOpPackageName(), mContext.getUserId());
+ return mService.hasPrimaryClip(
+ mContext.getOpPackageName(),
+ mContext.getAttributionTag(),
+ mContext.getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -226,7 +245,9 @@ public class ClipboardManager extends android.text.ClipboardManager {
if (mPrimaryClipChangedListeners.isEmpty()) {
try {
mService.addPrimaryClipChangedListener(
- mPrimaryClipChangedServiceListener, mContext.getOpPackageName(),
+ mPrimaryClipChangedServiceListener,
+ mContext.getOpPackageName(),
+ mContext.getAttributionTag(),
mContext.getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -242,7 +263,9 @@ public class ClipboardManager extends android.text.ClipboardManager {
if (mPrimaryClipChangedListeners.isEmpty()) {
try {
mService.removePrimaryClipChangedListener(
- mPrimaryClipChangedServiceListener, mContext.getOpPackageName(),
+ mPrimaryClipChangedServiceListener,
+ mContext.getOpPackageName(),
+ mContext.getAttributionTag(),
mContext.getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -280,7 +303,10 @@ public class ClipboardManager extends android.text.ClipboardManager {
@Deprecated
public boolean hasText() {
try {
- return mService.hasClipboardText(mContext.getOpPackageName(), mContext.getUserId());
+ return mService.hasClipboardText(
+ mContext.getOpPackageName(),
+ mContext.getAttributionTag(),
+ mContext.getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -297,7 +323,10 @@ public class ClipboardManager extends android.text.ClipboardManager {
@RequiresPermission(Manifest.permission.SET_CLIP_SOURCE)
public String getPrimaryClipSource() {
try {
- return mService.getPrimaryClipSource(mContext.getOpPackageName(), mContext.getUserId());
+ return mService.getPrimaryClipSource(
+ mContext.getOpPackageName(),
+ mContext.getAttributionTag(),
+ mContext.getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index 7b9d37e7136d..37794531dfa3 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -980,7 +980,7 @@ public abstract class ContentResolver implements ContentInterface {
@Override
public void onResult(Bundle result) {
synchronized (this) {
- ParcelableException e = result.getParcelable(REMOTE_CALLBACK_ERROR);
+ ParcelableException e = result.getParcelable(REMOTE_CALLBACK_ERROR, android.os.ParcelableException.class);
if (e != null) {
Throwable t = e.getCause();
if (t instanceof RuntimeException) {
@@ -1021,7 +1021,7 @@ public abstract class ContentResolver implements ContentInterface {
private static class UriResultListener extends ResultListener<Uri> {
@Override
protected Uri getResultFromBundle(Bundle result) {
- return result.getParcelable(REMOTE_CALLBACK_RESULT);
+ return result.getParcelable(REMOTE_CALLBACK_RESULT, android.net.Uri.class);
}
}
diff --git a/core/java/android/content/IClipboard.aidl b/core/java/android/content/IClipboard.aidl
index 102b8e798a5c..46ece2bc3f5e 100644
--- a/core/java/android/content/IClipboard.aidl
+++ b/core/java/android/content/IClipboard.aidl
@@ -26,22 +26,22 @@ import android.content.IOnPrimaryClipChangedListener;
* {@hide}
*/
interface IClipboard {
- void setPrimaryClip(in ClipData clip, String callingPackage, int userId);
- void setPrimaryClipAsPackage(in ClipData clip, String callingPackage, int userId,
+ void setPrimaryClip(in ClipData clip, String callingPackage, String attributionTag, int userId);
+ void setPrimaryClipAsPackage(in ClipData clip, String callingPackage, String attributionTag, int userId,
String sourcePackage);
- void clearPrimaryClip(String callingPackage, int userId);
- ClipData getPrimaryClip(String pkg, int userId);
- ClipDescription getPrimaryClipDescription(String callingPackage, int userId);
- boolean hasPrimaryClip(String callingPackage, int userId);
+ void clearPrimaryClip(String callingPackage, String attributionTag, int userId);
+ ClipData getPrimaryClip(String pkg, String attributionTag, int userId);
+ ClipDescription getPrimaryClipDescription(String callingPackage, String attributionTag, int userId);
+ boolean hasPrimaryClip(String callingPackage, String attributionTag, int userId);
void addPrimaryClipChangedListener(in IOnPrimaryClipChangedListener listener,
- String callingPackage, int userId);
+ String callingPackage, String attributionTag, int userId);
void removePrimaryClipChangedListener(in IOnPrimaryClipChangedListener listener,
- String callingPackage, int userId);
+ String callingPackage, String attributionTag, int userId);
/**
* Returns true if the clipboard contains text; false otherwise.
*/
- boolean hasClipboardText(String callingPackage, int userId);
+ boolean hasClipboardText(String callingPackage, String attributionTag, int userId);
- String getPrimaryClipSource(String callingPackage, int userId);
+ String getPrimaryClipSource(String callingPackage, String attributionTag, int userId);
}
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 7a88a057fb77..26b2f071e3f5 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -11940,7 +11940,7 @@ public class Intent implements Parcelable, Cloneable {
// passed via Bluetooth intents
if (mAction != null && mAction.startsWith("android.bluetooth.")
&& hasExtra(BluetoothDevice.EXTRA_DEVICE)) {
- final BluetoothDevice device = getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
+ final BluetoothDevice device = getParcelableExtra(BluetoothDevice.EXTRA_DEVICE, BluetoothDevice.class);
if (device != null) {
device.prepareToEnterProcess(source);
}
@@ -11989,12 +11989,12 @@ public class Intent implements Parcelable, Cloneable {
}
String action = getAction();
if (ACTION_SEND.equals(action)) {
- final Uri stream = getParcelableExtra(EXTRA_STREAM);
+ final Uri stream = getParcelableExtra(EXTRA_STREAM, Uri.class);
if (stream != null) {
putExtra(EXTRA_STREAM, maybeAddUserId(stream, contentUserHint));
}
} else if (ACTION_SEND_MULTIPLE.equals(action)) {
- final ArrayList<Uri> streams = getParcelableArrayListExtra(EXTRA_STREAM);
+ final ArrayList<Uri> streams = getParcelableArrayListExtra(EXTRA_STREAM, Uri.class);
if (streams != null) {
ArrayList<Uri> newStreams = new ArrayList<Uri>();
for (int i = 0; i < streams.size(); i++) {
@@ -12003,7 +12003,7 @@ public class Intent implements Parcelable, Cloneable {
putParcelableArrayListExtra(EXTRA_STREAM, newStreams);
}
} else if (isImageCaptureIntent()) {
- final Uri output = getParcelableExtra(MediaStore.EXTRA_OUTPUT);
+ final Uri output = getParcelableExtra(MediaStore.EXTRA_OUTPUT, Uri.class);
if (output != null) {
putExtra(MediaStore.EXTRA_OUTPUT, maybeAddUserId(output, contentUserHint));
}
@@ -12047,7 +12047,7 @@ public class Intent implements Parcelable, Cloneable {
boolean migrated = false;
try {
- final Intent intent = getParcelableExtra(EXTRA_INTENT);
+ final Intent intent = getParcelableExtra(EXTRA_INTENT, Intent.class);
if (intent != null) {
migrated |= intent.migrateExtraStreamToClipData(context);
}
@@ -12069,7 +12069,7 @@ public class Intent implements Parcelable, Cloneable {
} else if (ACTION_SEND.equals(action)) {
try {
- final Uri stream = getParcelableExtra(EXTRA_STREAM);
+ final Uri stream = getParcelableExtra(EXTRA_STREAM, Uri.class);
final CharSequence text = getCharSequenceExtra(EXTRA_TEXT);
final String htmlText = getStringExtra(EXTRA_HTML_TEXT);
if (stream != null || text != null || htmlText != null) {
@@ -12085,7 +12085,7 @@ public class Intent implements Parcelable, Cloneable {
} else if (ACTION_SEND_MULTIPLE.equals(action)) {
try {
- final ArrayList<Uri> streams = getParcelableArrayListExtra(EXTRA_STREAM);
+ final ArrayList<Uri> streams = getParcelableArrayListExtra(EXTRA_STREAM, Uri.class);
final ArrayList<CharSequence> texts = getCharSequenceArrayListExtra(EXTRA_TEXT);
final ArrayList<String> htmlTexts = getStringArrayListExtra(EXTRA_HTML_TEXT);
int num = -1;
@@ -12124,7 +12124,7 @@ public class Intent implements Parcelable, Cloneable {
} else if (isImageCaptureIntent()) {
Uri output;
try {
- output = getParcelableExtra(MediaStore.EXTRA_OUTPUT);
+ output = getParcelableExtra(MediaStore.EXTRA_OUTPUT, Uri.class);
} catch (ClassCastException e) {
return false;
}
diff --git a/core/java/android/content/SyncActivityTooManyDeletes.java b/core/java/android/content/SyncActivityTooManyDeletes.java
index 093fb0821a96..1a4eedd572b0 100644
--- a/core/java/android/content/SyncActivityTooManyDeletes.java
+++ b/core/java/android/content/SyncActivityTooManyDeletes.java
@@ -54,7 +54,7 @@ public class SyncActivityTooManyDeletes extends Activity
}
mNumDeletes = extras.getLong("numDeletes");
- mAccount = (Account) extras.getParcelable("account");
+ mAccount = (Account) extras.getParcelable("account", android.accounts.Account.class);
mAuthority = extras.getString("authority");
mProvider = extras.getString("provider");
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index f08fa51b4d9b..756c468e982a 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -178,7 +178,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
* signature checks} or
* <a href="https://developer.android.com/training/articles/security-tips#Permissions">permissions</a>.
*
- * <p><b>Warning:</b> Note that does flag not behave the same as
+ * <p><b>Warning:</b> Note that this flag does not behave the same as
* {@link android.R.attr#protectionLevel android:protectionLevel} {@code system} or
* {@code signatureOrSystem}.
*/
diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java
index 301d1bbc8e9d..f780f815fa89 100644
--- a/core/java/android/content/pm/LauncherApps.java
+++ b/core/java/android/content/pm/LauncherApps.java
@@ -2062,7 +2062,7 @@ public class LauncherApps {
* the {@link #EXTRA_PIN_ITEM_REQUEST} extra.
*/
public PinItemRequest getPinItemRequest(Intent intent) {
- return intent.getParcelableExtra(EXTRA_PIN_ITEM_REQUEST);
+ return intent.getParcelableExtra(EXTRA_PIN_ITEM_REQUEST, android.content.pm.LauncherApps.PinItemRequest.class);
}
/**
diff --git a/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java
index 4d0ba63d7759..336ef7ac78db 100644
--- a/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java
@@ -1739,6 +1739,20 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession {
// abruptly.
Log.w(TAG, "Output surface likely abandoned, dropping buffer!");
img.close();
+ } catch (RuntimeException e) {
+ // NOTE: This is intended to catch RuntimeException from ImageReader.detachImage
+ // ImageReader.detachImage is not supposed to throw RuntimeExceptions but the
+ // bug went unchecked for a few years and now its behavior cannot be changed
+ // without breaking backwards compatibility.
+
+ if (!e.getClass().equals(RuntimeException.class)) {
+ // re-throw any exceptions that aren't base RuntimeException since they are
+ // coming from elsewhere, and we shouldn't silently drop those.
+ throw e;
+ }
+
+ Log.w(TAG, "Output surface likely abandoned, dropping buffer!");
+ img.close();
}
}
}
@@ -1773,9 +1787,23 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession {
}
try {
reader.detachImage(img);
- } catch (Exception e) {
- Log.e(TAG,
- "Failed to detach image!");
+ } catch (IllegalStateException e) {
+ Log.e(TAG, "Failed to detach image!");
+ img.close();
+ return;
+ } catch (RuntimeException e) {
+ // NOTE: This is intended to catch RuntimeException from ImageReader.detachImage
+ // ImageReader.detachImage is not supposed to throw RuntimeExceptions but the
+ // bug went unchecked for a few years and now its behavior cannot be changed
+ // without breaking backwards compatibility.
+
+ if (!e.getClass().equals(RuntimeException.class)) {
+ // re-throw any exceptions that aren't base RuntimeException since they are
+ // coming from elsewhere, and we shouldn't silently drop those.
+ throw e;
+ }
+
+ Log.e(TAG, "Failed to detach image!");
img.close();
return;
}
diff --git a/core/java/android/hardware/location/ContextHubIntentEvent.java b/core/java/android/hardware/location/ContextHubIntentEvent.java
index 3e8f4219a485..06c533401e27 100644
--- a/core/java/android/hardware/location/ContextHubIntentEvent.java
+++ b/core/java/android/hardware/location/ContextHubIntentEvent.java
@@ -98,7 +98,7 @@ public class ContextHubIntentEvent {
Objects.requireNonNull(intent, "Intent cannot be null");
hasExtraOrThrow(intent, ContextHubManager.EXTRA_CONTEXT_HUB_INFO);
- ContextHubInfo info = intent.getParcelableExtra(ContextHubManager.EXTRA_CONTEXT_HUB_INFO);
+ ContextHubInfo info = intent.getParcelableExtra(ContextHubManager.EXTRA_CONTEXT_HUB_INFO, android.hardware.location.ContextHubInfo.class);
if (info == null) {
throw new IllegalArgumentException("ContextHubInfo extra was null");
}
@@ -117,7 +117,7 @@ public class ContextHubIntentEvent {
if (eventType == ContextHubManager.EVENT_NANOAPP_MESSAGE) {
hasExtraOrThrow(intent, ContextHubManager.EXTRA_MESSAGE);
NanoAppMessage message =
- intent.getParcelableExtra(ContextHubManager.EXTRA_MESSAGE);
+ intent.getParcelableExtra(ContextHubManager.EXTRA_MESSAGE, android.hardware.location.NanoAppMessage.class);
if (message == null) {
throw new IllegalArgumentException("NanoAppMessage extra was null");
}
diff --git a/core/java/android/hardware/radio/RadioMetadata.java b/core/java/android/hardware/radio/RadioMetadata.java
index a882c2fe877c..b7bf783754f7 100644
--- a/core/java/android/hardware/radio/RadioMetadata.java
+++ b/core/java/android/hardware/radio/RadioMetadata.java
@@ -384,7 +384,7 @@ public final class RadioMetadata implements Parcelable {
public Bitmap getBitmap(String key) {
Bitmap bmp = null;
try {
- bmp = mBundle.getParcelable(key);
+ bmp = mBundle.getParcelable(key, android.graphics.Bitmap.class);
} catch (Exception e) {
// ignore, value was not a bitmap
Log.w(TAG, "Failed to retrieve a key as Bitmap.", e);
@@ -419,7 +419,7 @@ public final class RadioMetadata implements Parcelable {
public Clock getClock(String key) {
Clock clock = null;
try {
- clock = mBundle.getParcelable(key);
+ clock = mBundle.getParcelable(key, android.hardware.radio.RadioMetadata.Clock.class);
} catch (Exception e) {
// ignore, value was not a clock.
Log.w(TAG, "Failed to retrieve a key as Clock.", e);
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index c02f870edbc2..c6fc9ec0ee6b 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -2163,13 +2163,13 @@ public class InputMethodService extends AbstractInputMethodService {
mCandidatesVisibility = vis;
}
}
-
+
/**
* Returns the visibility mode (either {@link View#INVISIBLE View.INVISIBLE}
* or {@link View#GONE View.GONE}) of the candidates view when it is not
* shown. The default implementation returns GONE when
* {@link #isExtractViewShown} returns true,
- * otherwise VISIBLE. Be careful if you change this to return GONE in
+ * otherwise INVISIBLE. Be careful if you change this to return GONE in
* other situations -- if showing or hiding the candidates view causes
* your window to resize, this can cause temporary drawing artifacts as
* the resize takes place.
diff --git a/core/java/android/net/ScoredNetwork.java b/core/java/android/net/ScoredNetwork.java
index a46bdd9ac37e..758367d30eb4 100644
--- a/core/java/android/net/ScoredNetwork.java
+++ b/core/java/android/net/ScoredNetwork.java
@@ -299,7 +299,7 @@ public class ScoredNetwork implements Parcelable {
public int calculateBadge(int rssi) {
if (attributes != null && attributes.containsKey(ATTRIBUTES_KEY_BADGING_CURVE)) {
RssiCurve badgingCurve =
- attributes.getParcelable(ATTRIBUTES_KEY_BADGING_CURVE);
+ attributes.getParcelable(ATTRIBUTES_KEY_BADGING_CURVE, android.net.RssiCurve.class);
return badgingCurve.lookupScore(rssi);
}
diff --git a/core/java/android/nfc/tech/Ndef.java b/core/java/android/nfc/tech/Ndef.java
index 225636565480..39c355ad918a 100644
--- a/core/java/android/nfc/tech/Ndef.java
+++ b/core/java/android/nfc/tech/Ndef.java
@@ -161,7 +161,7 @@ public final class Ndef extends BasicTagTechnology {
if (extras != null) {
mMaxNdefSize = extras.getInt(EXTRA_NDEF_MAXLENGTH);
mCardState = extras.getInt(EXTRA_NDEF_CARDSTATE);
- mNdefMsg = extras.getParcelable(EXTRA_NDEF_MSG);
+ mNdefMsg = extras.getParcelable(EXTRA_NDEF_MSG, android.nfc.NdefMessage.class);
mNdefType = extras.getInt(EXTRA_NDEF_TYPE);
} else {
throw new NullPointerException("NDEF tech extras are null.");
diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java
index 1dedc2666582..aa6155869f64 100644
--- a/core/java/android/os/Parcel.java
+++ b/core/java/android/os/Parcel.java
@@ -33,6 +33,7 @@ import android.util.ArraySet;
import android.util.ExceptionUtils;
import android.util.Log;
import android.util.MathUtils;
+import android.util.Pair;
import android.util.Size;
import android.util.SizeF;
import android.util.Slog;
@@ -3034,7 +3035,7 @@ public final class Parcel {
switch (code) {
case EX_PARCELABLE:
if (readInt() > 0) {
- return (Exception) readParcelable(Parcelable.class.getClassLoader());
+ return (Exception) readParcelable(Parcelable.class.getClassLoader(), java.lang.Exception.class);
} else {
return new RuntimeException(msg + " [missing Parcelable]");
}
@@ -4865,28 +4866,36 @@ public final class Parcel {
if (name == null) {
return null;
}
- Parcelable.Creator<?> creator;
- HashMap<String, Parcelable.Creator<?>> map;
- synchronized (mCreators) {
- map = mCreators.get(loader);
+
+ Pair<Parcelable.Creator<?>, Class<?>> creatorAndParcelableClass;
+ synchronized (sPairedCreators) {
+ HashMap<String, Pair<Parcelable.Creator<?>, Class<?>>> map =
+ sPairedCreators.get(loader);
if (map == null) {
- map = new HashMap<>();
- mCreators.put(loader, map);
+ sPairedCreators.put(loader, new HashMap<>());
+ mCreators.put(loader, new HashMap<>());
+ creatorAndParcelableClass = null;
+ } else {
+ creatorAndParcelableClass = map.get(name);
}
- creator = map.get(name);
}
- if (creator != null) {
+
+ if (creatorAndParcelableClass != null) {
+ Parcelable.Creator<?> creator = creatorAndParcelableClass.first;
+ Class<?> parcelableClass = creatorAndParcelableClass.second;
if (clazz != null) {
- Class<?> parcelableClass = creator.getClass().getEnclosingClass();
if (!clazz.isAssignableFrom(parcelableClass)) {
throw new BadTypeParcelableException("Parcelable creator " + name + " is not "
+ "a subclass of required class " + clazz.getName()
+ " provided in the parameter");
}
}
+
return (Parcelable.Creator<T>) creator;
}
+ Parcelable.Creator<?> creator;
+ Class<?> parcelableClass;
try {
// If loader == null, explicitly emulate Class.forName(String) "caller
// classloader" behavior.
@@ -4894,7 +4903,7 @@ public final class Parcel {
(loader == null ? getClass().getClassLoader() : loader);
// Avoid initializing the Parcelable class until we know it implements
// Parcelable and has the necessary CREATOR field. http://b/1171613.
- Class<?> parcelableClass = Class.forName(name, false /* initialize */,
+ parcelableClass = Class.forName(name, false /* initialize */,
parcelableClassLoader);
if (!Parcelable.class.isAssignableFrom(parcelableClass)) {
throw new BadParcelableException("Parcelable protocol requires subclassing "
@@ -4941,8 +4950,9 @@ public final class Parcel {
+ "CREATOR on class " + name);
}
- synchronized (mCreators) {
- map.put(name, creator);
+ synchronized (sPairedCreators) {
+ sPairedCreators.get(loader).put(name, Pair.create(creator, parcelableClass));
+ mCreators.get(loader).put(name, creator);
}
return (Parcelable.Creator<T>) creator;
@@ -5093,12 +5103,17 @@ public final class Parcel {
}
}
- // Cache of previously looked up CREATOR.createFromParcel() methods for
- // particular classes. Keys are the names of the classes, values are
- // Method objects.
+
+ // Left due to the UnsupportedAppUsage. Do not use anymore - use sPairedCreators instead
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
- private static final HashMap<ClassLoader,HashMap<String,Parcelable.Creator<?>>>
- mCreators = new HashMap<>();
+ private static final HashMap<ClassLoader, HashMap<String, Parcelable.Creator<?>>>
+ mCreators = new HashMap<>();
+
+ // Cache of previously looked up CREATOR.createFromParcel() methods for particular classes.
+ // Keys are the names of the classes, values are a pair consisting of a parcelable creator,
+ // and the class of the parcelable type for the object.
+ private static final HashMap<ClassLoader, HashMap<String,
+ Pair<Parcelable.Creator<?>, Class<?>>>> sPairedCreators = new HashMap<>();
/** @hide for internal use only. */
static protected final Parcel obtain(int obj) {
diff --git a/core/java/android/os/image/DynamicSystemClient.java b/core/java/android/os/image/DynamicSystemClient.java
index 5aa4e27fc2f3..63259edeae7d 100644
--- a/core/java/android/os/image/DynamicSystemClient.java
+++ b/core/java/android/os/image/DynamicSystemClient.java
@@ -420,7 +420,7 @@ public class DynamicSystemClient {
Bundle bundle = (Bundle) msg.obj;
long progress = bundle.getLong(KEY_INSTALLED_SIZE);
ParcelableException t = (ParcelableException) bundle.getSerializable(
- KEY_EXCEPTION_DETAIL);
+ KEY_EXCEPTION_DETAIL, android.os.ParcelableException.class);
Throwable detail = t == null ? null : t.getCause();
diff --git a/core/java/android/preference/PreferenceActivity.java b/core/java/android/preference/PreferenceActivity.java
index 53b1dab9f760..f6bdc18c29ec 100644
--- a/core/java/android/preference/PreferenceActivity.java
+++ b/core/java/android/preference/PreferenceActivity.java
@@ -578,7 +578,7 @@ public abstract class PreferenceActivity extends ListActivity implements
if (savedInstanceState != null) {
// We are restarting from a previous saved state; used that to
// initialize, instead of starting fresh.
- ArrayList<Header> headers = savedInstanceState.getParcelableArrayList(HEADERS_TAG);
+ ArrayList<Header> headers = savedInstanceState.getParcelableArrayList(HEADERS_TAG, android.preference.PreferenceActivity.Header.class);
if (headers != null) {
mHeaders.addAll(headers);
int curHeader = savedInstanceState.getInt(CUR_HEADER_TAG,
diff --git a/core/java/android/preference/RingtonePreference.java b/core/java/android/preference/RingtonePreference.java
index c6d8c08c9141..e15244ac0df0 100644
--- a/core/java/android/preference/RingtonePreference.java
+++ b/core/java/android/preference/RingtonePreference.java
@@ -248,7 +248,7 @@ public class RingtonePreference extends Preference implements
if (requestCode == mRequestCode) {
if (data != null) {
- Uri uri = data.getParcelableExtra(RingtoneManager.EXTRA_RINGTONE_PICKED_URI);
+ Uri uri = data.getParcelableExtra(RingtoneManager.EXTRA_RINGTONE_PICKED_URI, android.net.Uri.class);
if (callChangeListener(uri != null ? uri.toString() : "")) {
onSaveRingtone(uri);
diff --git a/core/java/android/print/PrintManager.java b/core/java/android/print/PrintManager.java
index a5e2f33d4418..931adb55a686 100644
--- a/core/java/android/print/PrintManager.java
+++ b/core/java/android/print/PrintManager.java
@@ -529,8 +529,8 @@ public final class PrintManager {
Bundle result = mService.print(printJobName, delegate,
attributes, mContext.getPackageName(), mAppId, mUserId);
if (result != null) {
- PrintJobInfo printJob = result.getParcelable(EXTRA_PRINT_JOB);
- IntentSender intent = result.getParcelable(EXTRA_PRINT_DIALOG_INTENT);
+ PrintJobInfo printJob = result.getParcelable(EXTRA_PRINT_JOB, android.print.PrintJobInfo.class);
+ IntentSender intent = result.getParcelable(EXTRA_PRINT_DIALOG_INTENT, android.content.IntentSender.class);
if (printJob == null || intent == null) {
return null;
}
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index 3c1b4ba8f8b5..d50ba8de8fa6 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -8448,7 +8448,7 @@ public final class ContactsContract {
Bundle response = contentResolver.call(ContactsContract.AUTHORITY_URI,
ContactsContract.SimContacts.QUERY_SIM_ACCOUNTS_METHOD,
null, null);
- List<SimAccount> result = response.getParcelableArrayList(KEY_SIM_ACCOUNTS);
+ List<SimAccount> result = response.getParcelableArrayList(KEY_SIM_ACCOUNTS, android.provider.ContactsContract.SimAccount.class);
if (result == null) {
result = new ArrayList<>();
@@ -8821,7 +8821,7 @@ public final class ContactsContract {
public static Account getDefaultAccount(@NonNull ContentResolver resolver) {
Bundle response = resolver.call(ContactsContract.AUTHORITY_URI,
QUERY_DEFAULT_ACCOUNT_METHOD, null, null);
- return response.getParcelable(KEY_DEFAULT_ACCOUNT);
+ return response.getParcelable(KEY_DEFAULT_ACCOUNT, android.accounts.Account.class);
}
/**
diff --git a/core/java/android/provider/DocumentsContract.java b/core/java/android/provider/DocumentsContract.java
index 620fa6517ca5..1884d569adc3 100644
--- a/core/java/android/provider/DocumentsContract.java
+++ b/core/java/android/provider/DocumentsContract.java
@@ -1379,7 +1379,7 @@ public final class DocumentsContract {
final Bundle out = content.call(parentDocumentUri.getAuthority(),
METHOD_CREATE_DOCUMENT, null, in);
- return out.getParcelable(DocumentsContract.EXTRA_URI);
+ return out.getParcelable(DocumentsContract.EXTRA_URI, android.net.Uri.class);
} catch (Exception e) {
Log.w(TAG, "Failed to create document", e);
rethrowIfNecessary(e);
@@ -1445,7 +1445,7 @@ public final class DocumentsContract {
final Bundle out = content.call(documentUri.getAuthority(),
METHOD_RENAME_DOCUMENT, null, in);
- final Uri outUri = out.getParcelable(DocumentsContract.EXTRA_URI);
+ final Uri outUri = out.getParcelable(DocumentsContract.EXTRA_URI, android.net.Uri.class);
return (outUri != null) ? outUri : documentUri;
} catch (Exception e) {
Log.w(TAG, "Failed to rename document", e);
@@ -1494,7 +1494,7 @@ public final class DocumentsContract {
final Bundle out = content.call(sourceDocumentUri.getAuthority(),
METHOD_COPY_DOCUMENT, null, in);
- return out.getParcelable(DocumentsContract.EXTRA_URI);
+ return out.getParcelable(DocumentsContract.EXTRA_URI, android.net.Uri.class);
} catch (Exception e) {
Log.w(TAG, "Failed to copy document", e);
rethrowIfNecessary(e);
@@ -1522,7 +1522,7 @@ public final class DocumentsContract {
final Bundle out = content.call(sourceDocumentUri.getAuthority(),
METHOD_MOVE_DOCUMENT, null, in);
- return out.getParcelable(DocumentsContract.EXTRA_URI);
+ return out.getParcelable(DocumentsContract.EXTRA_URI, android.net.Uri.class);
} catch (Exception e) {
Log.w(TAG, "Failed to move document", e);
rethrowIfNecessary(e);
@@ -1642,7 +1642,7 @@ public final class DocumentsContract {
final Bundle out = content.call(treeUri.getAuthority(),
METHOD_FIND_DOCUMENT_PATH, null, in);
- return out.getParcelable(DocumentsContract.EXTRA_RESULT);
+ return out.getParcelable(DocumentsContract.EXTRA_RESULT, android.provider.DocumentsContract.Path.class);
} catch (Exception e) {
Log.w(TAG, "Failed to find path", e);
rethrowIfNecessary(e);
@@ -1715,7 +1715,7 @@ public final class DocumentsContract {
final Bundle out = content.call(uri.getAuthority(),
METHOD_CREATE_WEB_LINK_INTENT, null, in);
- return out.getParcelable(DocumentsContract.EXTRA_RESULT);
+ return out.getParcelable(DocumentsContract.EXTRA_RESULT, android.content.IntentSender.class);
} catch (Exception e) {
Log.w(TAG, "Failed to create a web link intent", e);
rethrowIfNecessary(e);
diff --git a/core/java/android/provider/DocumentsProvider.java b/core/java/android/provider/DocumentsProvider.java
index a5a24c0f1013..07d500176fe5 100644
--- a/core/java/android/provider/DocumentsProvider.java
+++ b/core/java/android/provider/DocumentsProvider.java
@@ -219,9 +219,9 @@ public abstract class DocumentsProvider extends ContentProvider {
/** {@hide} */
private void enforceTreeForExtraUris(Bundle extras) {
- enforceTree(extras.getParcelable(DocumentsContract.EXTRA_URI));
- enforceTree(extras.getParcelable(DocumentsContract.EXTRA_PARENT_URI));
- enforceTree(extras.getParcelable(DocumentsContract.EXTRA_TARGET_URI));
+ enforceTree(extras.getParcelable(DocumentsContract.EXTRA_URI, android.net.Uri.class));
+ enforceTree(extras.getParcelable(DocumentsContract.EXTRA_PARENT_URI, android.net.Uri.class));
+ enforceTree(extras.getParcelable(DocumentsContract.EXTRA_TARGET_URI, android.net.Uri.class));
}
/** {@hide} */
@@ -1091,11 +1091,11 @@ public abstract class DocumentsProvider extends ContentProvider {
enforceTreeForExtraUris(extras);
final Uri extraUri = validateIncomingNullableUri(
- extras.getParcelable(DocumentsContract.EXTRA_URI));
+ extras.getParcelable(DocumentsContract.EXTRA_URI, android.net.Uri.class));
final Uri extraTargetUri = validateIncomingNullableUri(
- extras.getParcelable(DocumentsContract.EXTRA_TARGET_URI));
+ extras.getParcelable(DocumentsContract.EXTRA_TARGET_URI, android.net.Uri.class));
final Uri extraParentUri = validateIncomingNullableUri(
- extras.getParcelable(DocumentsContract.EXTRA_PARENT_URI));
+ extras.getParcelable(DocumentsContract.EXTRA_PARENT_URI, android.net.Uri.class));
if (METHOD_EJECT_ROOT.equals(method)) {
// Given that certain system apps can hold MOUNT_UNMOUNT permission, but only apps
@@ -1436,7 +1436,7 @@ public abstract class DocumentsProvider extends ContentProvider {
enforceTree(uri);
final String documentId = getDocumentId(uri);
if (opts != null && opts.containsKey(ContentResolver.EXTRA_SIZE)) {
- final Point sizeHint = opts.getParcelable(ContentResolver.EXTRA_SIZE);
+ final Point sizeHint = opts.getParcelable(ContentResolver.EXTRA_SIZE, android.graphics.Point.class);
return openDocumentThumbnail(documentId, sizeHint, signal);
}
if ("*/*".equals(mimeTypeFilter)) {
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index a513d5eb961b..6c5066f4e5db 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -3168,7 +3168,7 @@ public final class Settings {
synchronized (NameValueCache.this) {
if (needsGenerationTracker) {
MemoryIntArray array = b.getParcelable(
- CALL_METHOD_TRACK_GENERATION_KEY);
+ CALL_METHOD_TRACK_GENERATION_KEY, android.util.MemoryIntArray.class);
final int index = b.getInt(
CALL_METHOD_GENERATION_INDEX_KEY, -1);
if (array != null && index >= 0) {
@@ -3354,7 +3354,7 @@ public final class Settings {
// All flags for the namespace
Map<String, String> flagsToValues =
- (HashMap) b.getSerializable(Settings.NameValueTable.VALUE);
+ (HashMap) b.getSerializable(Settings.NameValueTable.VALUE, java.util.HashMap.class);
// Only the flags requested by the caller
if (!names.isEmpty()) {
for (Map.Entry<String, String> flag : flagsToValues.entrySet()) {
@@ -3369,7 +3369,7 @@ public final class Settings {
synchronized (NameValueCache.this) {
if (needsGenerationTracker) {
MemoryIntArray array = b.getParcelable(
- CALL_METHOD_TRACK_GENERATION_KEY);
+ CALL_METHOD_TRACK_GENERATION_KEY, android.util.MemoryIntArray.class);
final int index = b.getInt(
CALL_METHOD_GENERATION_INDEX_KEY, -1);
if (array != null && index >= 0) {
diff --git a/core/java/android/service/autofill/FillRequest.java b/core/java/android/service/autofill/FillRequest.java
index 327cda3360bb..b4010a4eefda 100644
--- a/core/java/android/service/autofill/FillRequest.java
+++ b/core/java/android/service/autofill/FillRequest.java
@@ -453,7 +453,7 @@ public final class FillRequest implements Parcelable {
byte flg = in.readByte();
int id = in.readInt();
List<FillContext> fillContexts = new ArrayList<>();
- in.readParcelableList(fillContexts, FillContext.class.getClassLoader());
+ in.readParcelableList(fillContexts, FillContext.class.getClassLoader(), android.service.autofill.FillContext.class);
Bundle clientState = (flg & 0x4) == 0 ? null : in.readBundle();
int flags = in.readInt();
InlineSuggestionsRequest inlineSuggestionsRequest = (flg & 0x10) == 0 ? null : (InlineSuggestionsRequest) in.readTypedObject(InlineSuggestionsRequest.CREATOR);
diff --git a/core/java/android/service/contentsuggestions/ContentSuggestionsService.java b/core/java/android/service/contentsuggestions/ContentSuggestionsService.java
index 50efbac76f48..0b4739ea1afc 100644
--- a/core/java/android/service/contentsuggestions/ContentSuggestionsService.java
+++ b/core/java/android/service/contentsuggestions/ContentSuggestionsService.java
@@ -72,7 +72,7 @@ public abstract class ContentSuggestionsService extends Service {
Bitmap wrappedBuffer = null;
if (imageContextRequestExtras.containsKey(ContentSuggestionsManager.EXTRA_BITMAP)) {
wrappedBuffer = imageContextRequestExtras.getParcelable(
- ContentSuggestionsManager.EXTRA_BITMAP);
+ ContentSuggestionsManager.EXTRA_BITMAP, android.graphics.Bitmap.class);
} else {
if (contextImage != null) {
ColorSpace colorSpace = null;
diff --git a/core/java/android/service/controls/templates/ThumbnailTemplate.java b/core/java/android/service/controls/templates/ThumbnailTemplate.java
index a7c481e38e55..e058b76736fc 100644
--- a/core/java/android/service/controls/templates/ThumbnailTemplate.java
+++ b/core/java/android/service/controls/templates/ThumbnailTemplate.java
@@ -65,7 +65,7 @@ public final class ThumbnailTemplate extends ControlTemplate {
ThumbnailTemplate(Bundle b) {
super(b);
mActive = b.getBoolean(KEY_ACTIVE);
- mThumbnail = b.getParcelable(KEY_ICON);
+ mThumbnail = b.getParcelable(KEY_ICON, android.graphics.drawable.Icon.class);
mContentDescription = b.getCharSequence(KEY_CONTENT_DESCRIPTION, "");
}
diff --git a/core/java/android/service/controls/templates/ToggleRangeTemplate.java b/core/java/android/service/controls/templates/ToggleRangeTemplate.java
index cd6a2fc45612..4ad42a38200b 100644
--- a/core/java/android/service/controls/templates/ToggleRangeTemplate.java
+++ b/core/java/android/service/controls/templates/ToggleRangeTemplate.java
@@ -43,7 +43,7 @@ public final class ToggleRangeTemplate extends ControlTemplate {
*/
ToggleRangeTemplate(@NonNull Bundle b) {
super(b);
- mControlButton = b.getParcelable(KEY_BUTTON);
+ mControlButton = b.getParcelable(KEY_BUTTON, android.service.controls.templates.ControlButton.class);
mRangeTemplate = new RangeTemplate(b.getBundle(KEY_RANGE));
}
diff --git a/core/java/android/service/controls/templates/ToggleTemplate.java b/core/java/android/service/controls/templates/ToggleTemplate.java
index e4aa6b0d6cec..687e75064a9a 100644
--- a/core/java/android/service/controls/templates/ToggleTemplate.java
+++ b/core/java/android/service/controls/templates/ToggleTemplate.java
@@ -53,7 +53,7 @@ public final class ToggleTemplate extends ControlTemplate {
*/
ToggleTemplate(Bundle b) {
super(b);
- mButton = b.getParcelable(KEY_BUTTON);
+ mButton = b.getParcelable(KEY_BUTTON, android.service.controls.templates.ControlButton.class);
}
public boolean isChecked() {
diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java
index 2d461c6cf92e..b0c5d8387d74 100644
--- a/core/java/android/service/dreams/DreamService.java
+++ b/core/java/android/service/dreams/DreamService.java
@@ -993,7 +993,7 @@ public class DreamService extends Service implements Window.Callback {
if (!mWindowless) {
mOverlayConnection.bind(
/* context= */ this,
- intent.getParcelableExtra(EXTRA_DREAM_OVERLAY_COMPONENT),
+ intent.getParcelableExtra(EXTRA_DREAM_OVERLAY_COMPONENT, android.content.ComponentName.class),
new ComponentName(this, getClass()));
}
diff --git a/core/java/android/service/games/GameSessionTrampolineActivity.java b/core/java/android/service/games/GameSessionTrampolineActivity.java
index b23791842284..93f19d5bd41c 100644
--- a/core/java/android/service/games/GameSessionTrampolineActivity.java
+++ b/core/java/android/service/games/GameSessionTrampolineActivity.java
@@ -94,7 +94,7 @@ public final class GameSessionTrampolineActivity extends Activity {
try {
startActivityAsCaller(
- getIntent().getParcelableExtra(INTENT_KEY),
+ getIntent().getParcelableExtra(INTENT_KEY, android.content.Intent.class),
getIntent().getBundleExtra(OPTIONS_KEY),
false,
getUserId(),
@@ -102,7 +102,7 @@ public final class GameSessionTrampolineActivity extends Activity {
} catch (Exception e) {
Slog.w(TAG, "Unable to launch activity from game session");
AndroidFuture<GameSessionActivityResult> future = getIntent().getParcelableExtra(
- FUTURE_KEY);
+ FUTURE_KEY, com.android.internal.infra.AndroidFuture.class);
future.completeExceptionally(e);
finish();
overridePendingTransition(0, 0);
@@ -123,7 +123,7 @@ public final class GameSessionTrampolineActivity extends Activity {
}
AndroidFuture<GameSessionActivityResult> future = getIntent().getParcelableExtra(
- FUTURE_KEY);
+ FUTURE_KEY, com.android.internal.infra.AndroidFuture.class);
future.complete(new GameSessionActivityResult(resultCode, data));
finish();
overridePendingTransition(0, 0);
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index 65f0824a9b78..02176b0c123e 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -1379,7 +1379,7 @@ public abstract class NotificationListenerService extends Service {
private void maybePopulatePeople(Notification notification) {
if (getContext().getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.P) {
ArrayList<Person> people = notification.extras.getParcelableArrayList(
- Notification.EXTRA_PEOPLE_LIST);
+ Notification.EXTRA_PEOPLE_LIST, android.app.Person.class);
if (people != null && people.isEmpty()) {
int size = people.size();
String[] peopleArray = new String[size];
diff --git a/core/java/android/service/notification/StatusBarNotification.java b/core/java/android/service/notification/StatusBarNotification.java
index 66188cd19721..e2c84dcbb908 100644
--- a/core/java/android/service/notification/StatusBarNotification.java
+++ b/core/java/android/service/notification/StatusBarNotification.java
@@ -500,7 +500,7 @@ public class StatusBarNotification implements Parcelable {
template.hashCode());
}
ArrayList<Person> people = getNotification().extras.getParcelableArrayList(
- Notification.EXTRA_PEOPLE_LIST);
+ Notification.EXTRA_PEOPLE_LIST, android.app.Person.class);
if (people != null && !people.isEmpty()) {
logMaker.addTaggedData(MetricsEvent.FIELD_NOTIFICATION_PEOPLE, people.size());
}
diff --git a/core/java/android/service/restrictions/RestrictionsReceiver.java b/core/java/android/service/restrictions/RestrictionsReceiver.java
index e8d481a65b31..badd0c207bb9 100644
--- a/core/java/android/service/restrictions/RestrictionsReceiver.java
+++ b/core/java/android/service/restrictions/RestrictionsReceiver.java
@@ -77,7 +77,7 @@ public abstract class RestrictionsReceiver extends BroadcastReceiver {
String requestType = intent.getStringExtra(RestrictionsManager.EXTRA_REQUEST_TYPE);
String requestId = intent.getStringExtra(RestrictionsManager.EXTRA_REQUEST_ID);
PersistableBundle request = (PersistableBundle)
- intent.getParcelableExtra(RestrictionsManager.EXTRA_REQUEST_BUNDLE);
+ intent.getParcelableExtra(RestrictionsManager.EXTRA_REQUEST_BUNDLE, android.os.PersistableBundle.class);
onRequestPermission(context, packageName, requestType, requestId, request);
}
}
diff --git a/core/java/android/service/trust/TrustAgentService.java b/core/java/android/service/trust/TrustAgentService.java
index 559313a30dfa..ad4f9f718f7f 100644
--- a/core/java/android/service/trust/TrustAgentService.java
+++ b/core/java/android/service/trust/TrustAgentService.java
@@ -257,7 +257,7 @@ public class TrustAgentService extends Service {
Bundle data = msg.getData();
byte[] token = data.getByteArray(EXTRA_TOKEN);
long handle = data.getLong(EXTRA_TOKEN_HANDLE);
- UserHandle user = (UserHandle) data.getParcelable(EXTRA_USER_HANDLE);
+ UserHandle user = (UserHandle) data.getParcelable(EXTRA_USER_HANDLE, android.os.UserHandle.class);
onEscrowTokenAdded(token, handle, user);
break;
}
diff --git a/core/java/android/service/voice/VoiceInteractionSession.java b/core/java/android/service/voice/VoiceInteractionSession.java
index 7d17093b2707..42500b4cfcff 100644
--- a/core/java/android/service/voice/VoiceInteractionSession.java
+++ b/core/java/android/service/voice/VoiceInteractionSession.java
@@ -1547,7 +1547,7 @@ public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCall
list = Collections.emptyList();
} else {
final ParceledListSlice<DirectAction> pls = result.getParcelable(
- DirectAction.KEY_ACTIONS_LIST);
+ DirectAction.KEY_ACTIONS_LIST, android.content.pm.ParceledListSlice.class);
if (pls != null) {
final List<DirectAction> receivedList = pls.getList();
list = (receivedList != null) ? receivedList : Collections.emptyList();
diff --git a/core/java/android/speech/AlternativeSpans.java b/core/java/android/speech/AlternativeSpans.java
index 0de8c3e65c48..2277e55a7836 100644
--- a/core/java/android/speech/AlternativeSpans.java
+++ b/core/java/android/speech/AlternativeSpans.java
@@ -140,7 +140,7 @@ public final class AlternativeSpans implements Parcelable {
// static FieldType unparcelFieldName(Parcel in) { ... }
List<AlternativeSpan> spans = new ArrayList<>();
- in.readParcelableList(spans, AlternativeSpan.class.getClassLoader());
+ in.readParcelableList(spans, AlternativeSpan.class.getClassLoader(), android.speech.AlternativeSpan.class);
this.mSpans = spans;
com.android.internal.util.AnnotationValidations.validate(
diff --git a/core/java/android/speech/tts/TextToSpeechService.java b/core/java/android/speech/tts/TextToSpeechService.java
index 26c831428f1c..a00d8cfb36f7 100644
--- a/core/java/android/speech/tts/TextToSpeechService.java
+++ b/core/java/android/speech/tts/TextToSpeechService.java
@@ -742,7 +742,7 @@ public abstract class TextToSpeechService extends Service {
AudioAttributes audioAttributes =
(AudioAttributes) paramsBundle.getParcelable(
- Engine.KEY_PARAM_AUDIO_ATTRIBUTES);
+ Engine.KEY_PARAM_AUDIO_ATTRIBUTES, android.media.AudioAttributes.class);
if (audioAttributes == null) {
int streamType = paramsBundle.getInt(
Engine.KEY_PARAM_STREAM, Engine.DEFAULT_STREAM);
diff --git a/core/java/android/view/InsetsState.java b/core/java/android/view/InsetsState.java
index 11e02e03c4e4..6a0ec3368f19 100644
--- a/core/java/android/view/InsetsState.java
+++ b/core/java/android/view/InsetsState.java
@@ -909,6 +909,11 @@ public class InsetsState implements Parcelable {
if (source == null && otherSource == null) {
continue;
}
+ if (excludeInvisibleImeFrames && i == ITYPE_IME
+ && ((source == null && !otherSource.isVisible())
+ || (otherSource == null && !source.isVisible()))) {
+ continue;
+ }
if (source == null || otherSource == null) {
return false;
}
diff --git a/core/java/android/view/RemoteAccessibilityController.java b/core/java/android/view/RemoteAccessibilityController.java
index 28b567d94e6e..b0911d789fe1 100644
--- a/core/java/android/view/RemoteAccessibilityController.java
+++ b/core/java/android/view/RemoteAccessibilityController.java
@@ -24,6 +24,8 @@ import android.os.RemoteException;
import android.util.Log;
import android.view.accessibility.IAccessibilityEmbeddedConnection;
+import java.lang.ref.WeakReference;
+
class RemoteAccessibilityController {
private static final String TAG = "RemoteAccessibilityController";
private int mHostId;
@@ -80,12 +82,17 @@ class RemoteAccessibilityController {
/**
* Wrapper of accessibility embedded connection for embedded view hierarchy.
*/
- private final class RemoteAccessibilityEmbeddedConnection implements IBinder.DeathRecipient {
+ private static final class RemoteAccessibilityEmbeddedConnection
+ implements IBinder.DeathRecipient {
+ private final WeakReference<RemoteAccessibilityController> mController;
private final IAccessibilityEmbeddedConnection mConnection;
private final IBinder mLeashToken;
- RemoteAccessibilityEmbeddedConnection(IAccessibilityEmbeddedConnection connection,
+ RemoteAccessibilityEmbeddedConnection(
+ RemoteAccessibilityController controller,
+ IAccessibilityEmbeddedConnection connection,
IBinder leashToken) {
+ mController = new WeakReference<>(controller);
mConnection = connection;
mLeashToken = leashToken;
}
@@ -109,9 +116,13 @@ class RemoteAccessibilityController {
@Override
public void binderDied() {
unlinkToDeath();
- runOnUiThread(() -> {
- if (mConnectionWrapper == this) {
- mConnectionWrapper = null;
+ RemoteAccessibilityController controller = mController.get();
+ if (controller == null) {
+ return;
+ }
+ controller.runOnUiThread(() -> {
+ if (controller.mConnectionWrapper == this) {
+ controller.mConnectionWrapper = null;
}
});
}
@@ -128,7 +139,7 @@ class RemoteAccessibilityController {
}
if (connection != null && leashToken != null) {
mConnectionWrapper =
- new RemoteAccessibilityEmbeddedConnection(connection, leashToken);
+ new RemoteAccessibilityEmbeddedConnection(this, connection, leashToken);
mConnectionWrapper.linkToDeath();
}
} catch (RemoteException e) {
diff --git a/core/java/android/view/ScrollCaptureConnection.java b/core/java/android/view/ScrollCaptureConnection.java
index d70de74ee75f..c50f70a08063 100644
--- a/core/java/android/view/ScrollCaptureConnection.java
+++ b/core/java/android/view/ScrollCaptureConnection.java
@@ -214,7 +214,7 @@ public class ScrollCaptureConnection extends IScrollCaptureConnection.Stub imple
@BinderThread
@Override
- public void close() {
+ public synchronized void close() {
Trace.instantForTrack(TRACE_TAG_GRAPHICS, TRACE_TRACK, "close");
if (mActive) {
Log.w(TAG, "close(): capture session still active! Ending now.");
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index 785735c2b1e1..c97eb73c120b 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -25,11 +25,11 @@ import android.graphics.BLASTBufferQueue;
import android.graphics.FrameInfo;
import android.graphics.HardwareRenderer;
import android.graphics.Picture;
-import android.graphics.Point;
import android.graphics.RecordingCanvas;
import android.graphics.Rect;
import android.graphics.RenderNode;
import android.os.Trace;
+import android.util.DisplayMetrics;
import android.util.Log;
import android.view.Surface.OutOfResourcesException;
import android.view.View.AttachInfo;
@@ -596,11 +596,18 @@ public final class ThreadedRenderer extends HardwareRenderer {
*/
void setLightCenter(AttachInfo attachInfo) {
// Adjust light position for window offsets.
- final Point displaySize = attachInfo.mPoint;
- attachInfo.mDisplay.getRealSize(displaySize);
- final float lightX = displaySize.x / 2f - attachInfo.mWindowLeft;
+ DisplayMetrics displayMetrics = new DisplayMetrics();
+ attachInfo.mDisplay.getRealMetrics(displayMetrics);
+ final float lightX = displayMetrics.widthPixels / 2f - attachInfo.mWindowLeft;
final float lightY = mLightY - attachInfo.mWindowTop;
- setLightSourceGeometry(lightX, lightY, mLightZ, mLightRadius);
+ // To prevent shadow distortion on larger screens, scale the z position of the light source
+ // relative to the smallest screen dimension.
+ final float zRatio = Math.min(displayMetrics.widthPixels, displayMetrics.heightPixels)
+ / (450f * displayMetrics.density);
+ final float zWeightedAdjustment = (zRatio + 2) / 3f;
+ final float lightZ = mLightZ * zWeightedAdjustment;
+
+ setLightSourceGeometry(lightX, lightY, lightZ, mLightRadius);
}
/**
@@ -849,12 +856,18 @@ public final class ThreadedRenderer extends HardwareRenderer {
public void setLightCenter(final Display display,
final int windowLeft, final int windowTop) {
// Adjust light position for window offsets.
- final Point displaySize = new Point();
- display.getRealSize(displaySize);
- final float lightX = displaySize.x / 2f - windowLeft;
+ DisplayMetrics displayMetrics = new DisplayMetrics();
+ display.getRealMetrics(displayMetrics);
+ final float lightX = displayMetrics.widthPixels / 2f - windowLeft;
final float lightY = mLightY - windowTop;
-
- setLightSourceGeometry(lightX, lightY, mLightZ, mLightRadius);
+ // To prevent shadow distortion on larger screens, scale the z position of the light
+ // source relative to the smallest screen dimension.
+ final float zRatio = Math.min(displayMetrics.widthPixels, displayMetrics.heightPixels)
+ / (450f * displayMetrics.density);
+ final float zWeightedAdjustment = (zRatio + 2) / 3f;
+ final float lightZ = mLightZ * zWeightedAdjustment;
+
+ setLightSourceGeometry(lightX, lightY, lightZ, mLightRadius);
}
public RenderNode getRootNode() {
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 545782132099..1e9769e6270b 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -31893,7 +31893,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
RemoteCallback remoteCallback = new RemoteCallback(result ->
executor.execute(() -> {
- DisplayHash displayHash = result.getParcelable(EXTRA_DISPLAY_HASH);
+ DisplayHash displayHash = result.getParcelable(EXTRA_DISPLAY_HASH, android.view.displayhash.DisplayHash.class);
int errorCode = result.getInt(EXTRA_DISPLAY_HASH_ERROR_CODE,
DISPLAY_HASH_ERROR_UNKNOWN);
if (displayHash != null) {
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 8907420a203a..bcaa1b26879e 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -2805,6 +2805,7 @@ public final class ViewRootImpl implements ViewParent,
if (viewVisibilityChanged) {
mAttachInfo.mWindowVisibility = viewVisibility;
host.dispatchWindowVisibilityChanged(viewVisibility);
+ mAttachInfo.mTreeObserver.dispatchOnWindowVisibilityChange(viewVisibility);
if (viewUserVisibilityChanged) {
host.dispatchVisibilityAggregated(viewVisibility == View.VISIBLE);
}
diff --git a/core/java/android/view/ViewTreeObserver.java b/core/java/android/view/ViewTreeObserver.java
index 5a99ab2f5bdb..ed8350afc109 100644
--- a/core/java/android/view/ViewTreeObserver.java
+++ b/core/java/android/view/ViewTreeObserver.java
@@ -43,6 +43,7 @@ public final class ViewTreeObserver {
// Recursive listeners use CopyOnWriteArrayList
private CopyOnWriteArrayList<OnWindowFocusChangeListener> mOnWindowFocusListeners;
private CopyOnWriteArrayList<OnWindowAttachListener> mOnWindowAttachListeners;
+ private CopyOnWriteArrayList<OnWindowVisibilityChangeListener> mOnWindowVisibilityListeners;
private CopyOnWriteArrayList<OnGlobalFocusChangeListener> mOnGlobalFocusListeners;
@UnsupportedAppUsage
private CopyOnWriteArrayList<OnTouchModeChangeListener> mOnTouchModeChangeListeners;
@@ -106,6 +107,21 @@ public final class ViewTreeObserver {
}
/**
+ * Interface definition for a callback to be invoked when the view hierarchy's window
+ * visibility changes.
+ *
+ * @hide
+ */
+ public interface OnWindowVisibilityChangeListener {
+ /**
+ * Callback method to be invoked when the window visibility changes in the view tree.
+ *
+ * @param visibility The new visibility of the window.
+ */
+ void onWindowVisibilityChanged(@View.Visibility int visibility);
+ }
+
+ /**
* Interface definition for a callback to be invoked when the focus state within
* the view tree changes.
*/
@@ -386,6 +402,14 @@ public final class ViewTreeObserver {
}
}
+ if (observer.mOnWindowVisibilityListeners != null) {
+ if (mOnWindowVisibilityListeners != null) {
+ mOnWindowVisibilityListeners.addAll(observer.mOnWindowVisibilityListeners);
+ } else {
+ mOnWindowVisibilityListeners = observer.mOnWindowVisibilityListeners;
+ }
+ }
+
if (observer.mOnGlobalFocusListeners != null) {
if (mOnGlobalFocusListeners != null) {
mOnGlobalFocusListeners.addAll(observer.mOnGlobalFocusListeners);
@@ -540,6 +564,49 @@ public final class ViewTreeObserver {
}
/**
+ * Register a callback to be invoked when the window visibility changes.
+ *
+ * @param listener The callback to add
+ *
+ * @throws IllegalStateException If {@link #isAlive()} returns false
+ *
+ * @hide
+ */
+ public void addOnWindowVisibilityChangeListener(
+ @NonNull OnWindowVisibilityChangeListener listener) {
+ checkIsAlive();
+
+ if (mOnWindowVisibilityListeners == null) {
+ mOnWindowVisibilityListeners =
+ new CopyOnWriteArrayList<OnWindowVisibilityChangeListener>();
+ }
+
+ mOnWindowVisibilityListeners.add(listener);
+ }
+
+ /**
+ * Remove a previously installed window visibility callback.
+ *
+ * @param victim The callback to remove
+ *
+ * @throws IllegalStateException If {@link #isAlive()} returns false
+ *
+ * @see #addOnWindowVisibilityChangeListener(
+ * android.view.ViewTreeObserver.OnWindowVisibilityChangeListener)
+ *
+ * @hide
+ */
+ public void removeOnWindowVisibilityChangeListener(
+ @NonNull OnWindowVisibilityChangeListener victim) {
+ checkIsAlive();
+ if (mOnWindowVisibilityListeners == null) {
+ return;
+ }
+
+ mOnWindowVisibilityListeners.remove(victim);
+ }
+
+ /*
* Register a callback to be invoked when the focus state within the view tree changes.
*
* @param listener The callback to add
@@ -1026,6 +1093,23 @@ public final class ViewTreeObserver {
}
/**
+ * Notifies registered listeners that window visibility has changed.
+ */
+ void dispatchOnWindowVisibilityChange(int visibility) {
+ // NOTE: because of the use of CopyOnWriteArrayList, we *must* use an iterator to
+ // perform the dispatching. The iterator is a safe guard against listeners that
+ // could mutate the list by calling the various add/remove methods. This prevents
+ // the array from being modified while we iterate it.
+ final CopyOnWriteArrayList<OnWindowVisibilityChangeListener> listeners =
+ mOnWindowVisibilityListeners;
+ if (listeners != null && listeners.size() > 0) {
+ for (OnWindowVisibilityChangeListener listener : listeners) {
+ listener.onWindowVisibilityChanged(visibility);
+ }
+ }
+ }
+
+ /**
* Notifies registered listeners that focus has changed.
*/
@UnsupportedAppUsage
diff --git a/core/java/android/view/WindowInfo.java b/core/java/android/view/WindowInfo.java
index a5b8720c7dec..11d63c84d142 100644
--- a/core/java/android/view/WindowInfo.java
+++ b/core/java/android/view/WindowInfo.java
@@ -208,6 +208,8 @@ public class WindowInfo implements Parcelable {
mTransformMatrix[i] = 0;
}
mMagnificationSpec.clear();
+ title = null;
+ accessibilityIdOfAnchor = AccessibilityNodeInfo.UNDEFINED_NODE_ID;
}
public static final @android.annotation.NonNull Parcelable.Creator<WindowInfo> CREATOR =
diff --git a/core/java/android/view/WindowLayout.java b/core/java/android/view/WindowLayout.java
index 9b6b2b906e8e..0941ee8a714f 100644
--- a/core/java/android/view/WindowLayout.java
+++ b/core/java/android/view/WindowLayout.java
@@ -16,8 +16,6 @@
package android.view;
-import static android.view.Gravity.DISPLAY_CLIP_HORIZONTAL;
-import static android.view.Gravity.DISPLAY_CLIP_VERTICAL;
import static android.view.InsetsState.ITYPE_IME;
import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
import static android.view.InsetsState.ITYPE_STATUS_BAR;
@@ -275,17 +273,9 @@ public class WindowLayout {
Gravity.applyDisplay(attrs.gravity, outDisplayFrame, outFrame);
}
- if (extendedByCutout && !displayCutoutSafe.contains(outFrame)) {
- mTempRect.set(outFrame);
-
- // Move the frame into displayCutoutSafe.
- final int clipFlags = DISPLAY_CLIP_VERTICAL | DISPLAY_CLIP_HORIZONTAL;
- Gravity.applyDisplay(attrs.gravity & ~clipFlags, displayCutoutSafe,
+ if (extendedByCutout) {
+ extendFrameByCutout(attrs.gravity, displayCutoutSafe, outDisplayFrame, outFrame,
mTempRect);
-
- if (mTempRect.intersect(outDisplayFrame)) {
- outFrame.union(mTempRect);
- }
}
if (DEBUG) Log.d(TAG, "computeFrames " + attrs.getTitle()
@@ -301,6 +291,21 @@ public class WindowLayout {
+ " requestedVisibilities=" + requestedVisibilities);
}
+ public static void extendFrameByCutout(int gravity, Rect displayCutoutSafe,
+ Rect displayFrame, Rect inOutFrame, Rect tempRect) {
+ if (displayCutoutSafe.contains(inOutFrame)) {
+ return;
+ }
+ tempRect.set(inOutFrame);
+
+ // Move the frame into displayCutoutSafe.
+ Gravity.applyDisplay(0 /* gravity */, displayCutoutSafe, tempRect);
+
+ if (tempRect.intersect(displayFrame)) {
+ inOutFrame.union(tempRect);
+ }
+ }
+
public static void computeSurfaceSize(WindowManager.LayoutParams attrs, Rect maxBounds,
int requestedWidth, int requestedHeight, Rect winFrame, boolean dragResizing,
Point outSurfaceSize) {
diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java
index 20cdad42b4cc..dc4ccbad27be 100644
--- a/core/java/android/view/WindowManagerImpl.java
+++ b/core/java/android/view/WindowManagerImpl.java
@@ -213,7 +213,7 @@ public final class WindowManagerImpl implements WindowManager {
@Override
public void send(int resultCode, Bundle resultData) throws RemoteException {
List<KeyboardShortcutGroup> result =
- resultData.getParcelableArrayList(PARCEL_KEY_SHORTCUTS_ARRAY);
+ resultData.getParcelableArrayList(PARCEL_KEY_SHORTCUTS_ARRAY, android.view.KeyboardShortcutGroup.class);
receiver.onKeyboardShortcutsReceived(result);
}
};
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index 6a27eb5a5d82..dbefcfb5ef17 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -944,7 +944,7 @@ public final class AutofillManager {
return;
}
synchronized (mLock) {
- mLastAutofilledData = savedInstanceState.getParcelable(LAST_AUTOFILLED_DATA_TAG);
+ mLastAutofilledData = savedInstanceState.getParcelable(LAST_AUTOFILLED_DATA_TAG, android.view.autofill.ParcelableMap.class);
if (isActiveLocked()) {
Log.w(TAG, "New session was started before onCreate()");
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 59d3314257ed..1b14110b7330 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -1004,7 +1004,6 @@ public final class InputMethodManager {
}
}
}
- mBindSequence = res.sequence;
}
startInputInner(StartInputReason.BOUND_ACCESSIBILITY_SESSION_TO_IMMS, null,
0, 0, 0);
diff --git a/core/java/android/view/selectiontoolbar/ShowInfo.java b/core/java/android/view/selectiontoolbar/ShowInfo.java
index 594b6bc7400a..d9adef2c920b 100644
--- a/core/java/android/view/selectiontoolbar/ShowInfo.java
+++ b/core/java/android/view/selectiontoolbar/ShowInfo.java
@@ -284,7 +284,7 @@ public final class ShowInfo implements Parcelable {
boolean layoutRequired = (flg & 0x2) != 0;
long widgetToken = in.readLong();
List<ToolbarMenuItem> menuItems = new java.util.ArrayList<>();
- in.readParcelableList(menuItems, ToolbarMenuItem.class.getClassLoader());
+ in.readParcelableList(menuItems, ToolbarMenuItem.class.getClassLoader(), android.view.selectiontoolbar.ToolbarMenuItem.class);
Rect contentRect = (Rect) in.readTypedObject(Rect.CREATOR);
int suggestedWidth = in.readInt();
Rect viewPortOnScreen = (Rect) in.readTypedObject(Rect.CREATOR);
diff --git a/core/java/android/view/textclassifier/ExtrasUtils.java b/core/java/android/view/textclassifier/ExtrasUtils.java
index 9e2b6427eaea..ecb838c13112 100644
--- a/core/java/android/view/textclassifier/ExtrasUtils.java
+++ b/core/java/android/view/textclassifier/ExtrasUtils.java
@@ -58,7 +58,7 @@ public final class ExtrasUtils {
*/
@Nullable
public static Intent getActionIntent(Bundle container) {
- return container.getParcelable(ACTION_INTENT);
+ return container.getParcelable(ACTION_INTENT, android.content.Intent.class);
}
/**
@@ -69,7 +69,7 @@ public final class ExtrasUtils {
if (classification == null) {
return null;
}
- return classification.getExtras().getParcelableArrayList(ACTIONS_INTENTS);
+ return classification.getExtras().getParcelableArrayList(ACTIONS_INTENTS, android.content.Intent.class);
}
/**
diff --git a/core/java/android/view/translation/TranslationManager.java b/core/java/android/view/translation/TranslationManager.java
index db1c606bc99b..55c0726f259a 100644
--- a/core/java/android/view/translation/TranslationManager.java
+++ b/core/java/android/view/translation/TranslationManager.java
@@ -246,7 +246,7 @@ public final class TranslationManager {
return Collections.emptySet();
}
ParceledListSlice<TranslationCapability> listSlice =
- result.bundle.getParcelable(EXTRA_CAPABILITIES);
+ result.bundle.getParcelable(EXTRA_CAPABILITIES, android.content.pm.ParceledListSlice.class);
ArraySet<TranslationCapability> capabilities =
new ArraySet<>(listSlice == null ? null : listSlice.getList());
return capabilities;
@@ -466,7 +466,7 @@ public final class TranslationManager {
private void onTranslationCapabilityUpdate(Bundle bundle) {
TranslationCapability capability =
- (TranslationCapability) bundle.getParcelable(EXTRA_CAPABILITIES);
+ (TranslationCapability) bundle.getParcelable(EXTRA_CAPABILITIES, android.view.translation.TranslationCapability.class);
mListener.accept(capability);
}
}
diff --git a/core/java/android/window/TaskFragmentOrganizer.java b/core/java/android/window/TaskFragmentOrganizer.java
index 2ef49c3e2aac..68c934f6f0a6 100644
--- a/core/java/android/window/TaskFragmentOrganizer.java
+++ b/core/java/android/window/TaskFragmentOrganizer.java
@@ -220,7 +220,7 @@ public class TaskFragmentOrganizer extends WindowOrganizer {
@NonNull IBinder errorCallbackToken, @NonNull Bundle exceptionBundle) {
mExecutor.execute(() -> TaskFragmentOrganizer.this.onTaskFragmentError(
errorCallbackToken,
- (Throwable) exceptionBundle.getSerializable(KEY_ERROR_CALLBACK_EXCEPTION)));
+ (Throwable) exceptionBundle.getSerializable(KEY_ERROR_CALLBACK_EXCEPTION, java.lang.Throwable.class)));
}
@Override
diff --git a/core/java/com/android/internal/app/BlockedAppStreamingActivity.java b/core/java/com/android/internal/app/BlockedAppStreamingActivity.java
index ca111a49235e..d35f66519737 100644
--- a/core/java/com/android/internal/app/BlockedAppStreamingActivity.java
+++ b/core/java/com/android/internal/app/BlockedAppStreamingActivity.java
@@ -44,7 +44,7 @@ public class BlockedAppStreamingActivity extends AlertActivity {
Intent intent = getIntent();
CharSequence appLabel = null;
- ActivityInfo activityInfo = intent.getParcelableExtra(EXTRA_BLOCKED_ACTIVITY_INFO);
+ ActivityInfo activityInfo = intent.getParcelableExtra(EXTRA_BLOCKED_ACTIVITY_INFO, android.content.pm.ActivityInfo.class);
if (activityInfo != null) {
appLabel = activityInfo.loadLabel(getPackageManager());
}
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 819a8c589064..ff1afddbbb06 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -30,6 +30,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.Activity;
import android.app.ActivityManager;
+import android.app.ActivityOptions;
import android.app.SharedElementCallback;
import android.app.prediction.AppPredictionContext;
import android.app.prediction.AppPredictionManager;
@@ -101,7 +102,10 @@ import android.view.ViewGroup.LayoutParams;
import android.view.ViewTreeObserver;
import android.view.WindowInsets;
import android.view.animation.AccelerateInterpolator;
+import android.view.animation.AlphaAnimation;
+import android.view.animation.Animation;
import android.view.animation.DecelerateInterpolator;
+import android.view.animation.LinearInterpolator;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.Space;
@@ -197,6 +201,8 @@ public class ChooserActivity extends ResolverActivity implements
private static final String PLURALS_COUNT = "count";
private static final String PLURALS_FILE_NAME = "file_name";
+ private static final String IMAGE_EDITOR_SHARED_ELEMENT = "screenshot_preview_image";
+
private boolean mIsAppPredictorComponentAvailable;
private Map<ChooserTarget, AppTarget> mDirectShareAppTargetCache;
private Map<ChooserTarget, ShortcutInfo> mDirectShareShortcutInfoCache;
@@ -250,6 +256,11 @@ public class ChooserActivity extends ResolverActivity implements
private static final int DEFAULT_LIST_VIEW_UPDATE_DELAY_MS = 125;
+ private static final int URI_PERMISSION_INTENT_FLAGS = Intent.FLAG_GRANT_READ_URI_PERMISSION
+ | Intent.FLAG_GRANT_WRITE_URI_PERMISSION
+ | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION
+ | Intent.FLAG_GRANT_PREFIX_URI_PERMISSION;
+
@VisibleForTesting
int mListViewUpdateDelayMs = DeviceConfig.getInt(DeviceConfig.NAMESPACE_SYSTEMUI,
SystemUiDeviceConfigFlags.SHARESHEET_LIST_VIEW_UPDATE_DELAY,
@@ -305,6 +316,8 @@ public class ChooserActivity extends ResolverActivity implements
private boolean mRemoveSharedElements = false;
+ private View mContentView = null;
+
private class ContentPreviewCoordinator {
private static final int IMAGE_FADE_IN_MILLIS = 150;
private static final int IMAGE_LOAD_TIMEOUT = 1;
@@ -607,9 +620,9 @@ public class ChooserActivity extends ResolverActivity implements
mReferrerFillInIntent = new Intent().putExtra(Intent.EXTRA_REFERRER, getReferrer());
mChosenComponentSender = intent.getParcelableExtra(
- Intent.EXTRA_CHOSEN_COMPONENT_INTENT_SENDER);
+ Intent.EXTRA_CHOSEN_COMPONENT_INTENT_SENDER, android.content.IntentSender.class);
mRefinementIntentSender = intent.getParcelableExtra(
- Intent.EXTRA_CHOOSER_REFINEMENT_INTENT_SENDER);
+ Intent.EXTRA_CHOOSER_REFINEMENT_INTENT_SENDER, android.content.IntentSender.class);
setSafeForwardingMode(true);
mPinnedSharedPrefs = getPinnedSharedPrefs(this);
@@ -943,7 +956,7 @@ public class ChooserActivity extends ResolverActivity implements
ClipData clipData = null;
if (Intent.ACTION_SEND.equals(action)) {
String extraText = targetIntent.getStringExtra(Intent.EXTRA_TEXT);
- Uri extraStream = targetIntent.getParcelableExtra(Intent.EXTRA_STREAM);
+ Uri extraStream = targetIntent.getParcelableExtra(Intent.EXTRA_STREAM, android.net.Uri.class);
if (extraText != null) {
clipData = ClipData.newPlainText(null, extraText);
@@ -955,7 +968,7 @@ public class ChooserActivity extends ResolverActivity implements
}
} else if (Intent.ACTION_SEND_MULTIPLE.equals(action)) {
final ArrayList<Uri> streams = targetIntent.getParcelableArrayListExtra(
- Intent.EXTRA_STREAM);
+ Intent.EXTRA_STREAM, android.net.Uri.class);
clipData = ClipData.newUri(getContentResolver(), null, streams.get(0));
for (int i = 1; i < streams.size(); i++) {
clipData.addItem(getContentResolver(), new ClipData.Item(streams.get(i)));
@@ -990,6 +1003,7 @@ public class ChooserActivity extends ResolverActivity implements
protected void onResume() {
super.onResume();
Log.d(TAG, "onResume: " + getComponentName().flattenToShortString());
+ maybeCancelFinishAnimation();
}
@Override
@@ -1085,12 +1099,16 @@ public class ChooserActivity extends ResolverActivity implements
final ComponentName cn = getEditSharingComponent();
final Intent resolveIntent = new Intent(originalIntent);
+ // Retain only URI permission grant flags if present. Other flags may prevent the scene
+ // transition animation from running (i.e FLAG_ACTIVITY_NO_ANIMATION,
+ // FLAG_ACTIVITY_NEW_TASK, FLAG_ACTIVITY_NEW_DOCUMENT) but also not needed.
+ resolveIntent.setFlags(originalIntent.getFlags() & URI_PERMISSION_INTENT_FLAGS);
resolveIntent.setComponent(cn);
resolveIntent.setAction(Intent.ACTION_EDIT);
String originalAction = originalIntent.getAction();
if (Intent.ACTION_SEND.equals(originalAction)) {
if (resolveIntent.getData() == null) {
- Uri uri = resolveIntent.getParcelableExtra(Intent.EXTRA_STREAM);
+ Uri uri = resolveIntent.getParcelableExtra(Intent.EXTRA_STREAM, android.net.Uri.class);
if (uri != null) {
String mimeType = getContentResolver().getType(uri);
resolveIntent.setDataAndType(uri, mimeType);
@@ -1114,7 +1132,6 @@ public class ChooserActivity extends ResolverActivity implements
return dri;
}
-
@VisibleForTesting
protected TargetInfo getNearbySharingTarget(Intent originalIntent) {
final ComponentName cn = getNearbySharingComponent();
@@ -1217,15 +1234,30 @@ public class ChooserActivity extends ResolverActivity implements
"",
-1,
false);
+ View firstImgView = getFirstVisibleImgPreviewView();
// Action bar is user-independent, always start as primary
- safelyStartActivityAsUser(ti, getPersonalProfileUserHandle());
- finish();
+ if (firstImgView == null) {
+ safelyStartActivityAsUser(ti, getPersonalProfileUserHandle());
+ finish();
+ } else {
+ ActivityOptions options = ActivityOptions.makeSceneTransitionAnimation(
+ this, firstImgView, IMAGE_EDITOR_SHARED_ELEMENT);
+ safelyStartActivityAsUser(
+ ti, getPersonalProfileUserHandle(), options.toBundle());
+ startFinishAnimation();
+ }
}
);
b.setId(R.id.chooser_edit_button);
return b;
}
+ @Nullable
+ private View getFirstVisibleImgPreviewView() {
+ View firstImage = findViewById(R.id.content_preview_image_1_large);
+ return firstImage != null && firstImage.isVisibleToUser() ? firstImage : null;
+ }
+
private void addActionButton(ViewGroup parent, Button b) {
if (b == null) return;
final ViewGroup.MarginLayoutParams lp = new ViewGroup.MarginLayoutParams(
@@ -1335,14 +1367,14 @@ public class ChooserActivity extends ResolverActivity implements
String action = targetIntent.getAction();
if (Intent.ACTION_SEND.equals(action)) {
- Uri uri = targetIntent.getParcelableExtra(Intent.EXTRA_STREAM);
+ Uri uri = targetIntent.getParcelableExtra(Intent.EXTRA_STREAM, android.net.Uri.class);
imagePreview.findViewById(R.id.content_preview_image_1_large)
.setTransitionName(ChooserActivity.FIRST_IMAGE_PREVIEW_TRANSITION_NAME);
mPreviewCoord.loadUriIntoView(R.id.content_preview_image_1_large, uri, 0);
} else {
ContentResolver resolver = getContentResolver();
- List<Uri> uris = targetIntent.getParcelableArrayListExtra(Intent.EXTRA_STREAM);
+ List<Uri> uris = targetIntent.getParcelableArrayListExtra(Intent.EXTRA_STREAM, android.net.Uri.class);
List<Uri> imageUris = new ArrayList<>();
for (Uri uri : uris) {
if (isImageType(resolver.getType(uri))) {
@@ -1454,10 +1486,10 @@ public class ChooserActivity extends ResolverActivity implements
String action = targetIntent.getAction();
if (Intent.ACTION_SEND.equals(action)) {
- Uri uri = targetIntent.getParcelableExtra(Intent.EXTRA_STREAM);
+ Uri uri = targetIntent.getParcelableExtra(Intent.EXTRA_STREAM, android.net.Uri.class);
loadFileUriIntoView(uri, contentPreviewLayout);
} else {
- List<Uri> uris = targetIntent.getParcelableArrayListExtra(Intent.EXTRA_STREAM);
+ List<Uri> uris = targetIntent.getParcelableArrayListExtra(Intent.EXTRA_STREAM, android.net.Uri.class);
int uriCount = uris.size();
if (uriCount == 0) {
@@ -1541,10 +1573,10 @@ public class ChooserActivity extends ResolverActivity implements
private int findPreferredContentPreview(Intent targetIntent, ContentResolver resolver) {
String action = targetIntent.getAction();
if (Intent.ACTION_SEND.equals(action)) {
- Uri uri = targetIntent.getParcelableExtra(Intent.EXTRA_STREAM);
+ Uri uri = targetIntent.getParcelableExtra(Intent.EXTRA_STREAM, android.net.Uri.class);
return findPreferredContentPreview(uri, resolver);
} else if (Intent.ACTION_SEND_MULTIPLE.equals(action)) {
- List<Uri> uris = targetIntent.getParcelableArrayListExtra(Intent.EXTRA_STREAM);
+ List<Uri> uris = targetIntent.getParcelableArrayListExtra(Intent.EXTRA_STREAM, android.net.Uri.class);
if (uris == null || uris.isEmpty()) {
return CONTENT_PREVIEW_TEXT;
}
@@ -1573,6 +1605,14 @@ public class ChooserActivity extends ResolverActivity implements
}
@Override
+ protected void onStop() {
+ super.onStop();
+ if (maybeCancelFinishAnimation()) {
+ finish();
+ }
+ }
+
+ @Override
protected void onDestroy() {
super.onDestroy();
@@ -1914,12 +1954,12 @@ public class ChooserActivity extends ResolverActivity implements
IntentFilter intentFilter = new IntentFilter(intent.getAction(), intent.getType());
List<Uri> contentUris = new ArrayList<>();
if (Intent.ACTION_SEND.equals(intent.getAction())) {
- Uri uri = (Uri) intent.getParcelableExtra(Intent.EXTRA_STREAM);
+ Uri uri = (Uri) intent.getParcelableExtra(Intent.EXTRA_STREAM, android.net.Uri.class);
if (uri != null) {
contentUris.add(uri);
}
} else {
- List<Uri> uris = intent.getParcelableArrayListExtra(Intent.EXTRA_STREAM);
+ List<Uri> uris = intent.getParcelableArrayListExtra(Intent.EXTRA_STREAM, android.net.Uri.class);
if (uris != null) {
contentUris.addAll(uris);
}
@@ -2900,6 +2940,30 @@ public class ChooserActivity extends ResolverActivity implements
.setSubtype(previewType));
}
+ private void startFinishAnimation() {
+ View rootView = findRootView();
+ rootView.startAnimation(new FinishAnimation(this, rootView));
+ }
+
+ private boolean maybeCancelFinishAnimation() {
+ View rootView = findRootView();
+ Animation animation = rootView.getAnimation();
+ if (animation instanceof FinishAnimation) {
+ boolean hasEnded = animation.hasEnded();
+ animation.cancel();
+ rootView.clearAnimation();
+ return !hasEnded;
+ }
+ return false;
+ }
+
+ private View findRootView() {
+ if (mContentView == null) {
+ mContentView = findViewById(android.R.id.content);
+ }
+ return mContentView;
+ }
+
abstract static class ViewHolderBase extends RecyclerView.ViewHolder {
private int mViewType;
@@ -4000,6 +4064,66 @@ public class ChooserActivity extends ResolverActivity implements
}
}
+ /**
+ * Used in combination with the scene transition when launching the image editor
+ */
+ private static class FinishAnimation extends AlphaAnimation implements
+ Animation.AnimationListener {
+ private Activity mActivity;
+ private View mRootView;
+ private final float mFromAlpha;
+
+ FinishAnimation(Activity activity, View rootView) {
+ super(rootView.getAlpha(), 0.0f);
+ mActivity = activity;
+ mRootView = rootView;
+ mFromAlpha = rootView.getAlpha();
+ setInterpolator(new LinearInterpolator());
+ long duration = activity.getWindow().getTransitionBackgroundFadeDuration();
+ setDuration(duration);
+ // The scene transition animation looks better when it's not overlapped with this
+ // fade-out animation thus the delay.
+ // It is most likely that the image editor will cause this activity to stop and this
+ // animation will be cancelled in the background without running (i.e. we'll animate
+ // only when this activity remains partially visible after the image editor launch).
+ setStartOffset(duration);
+ super.setAnimationListener(this);
+ }
+
+ @Override
+ public void setAnimationListener(AnimationListener listener) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void cancel() {
+ mRootView.setAlpha(mFromAlpha);
+ cleanup();
+ super.cancel();
+ }
+
+ @Override
+ public void onAnimationStart(Animation animation) {
+ }
+
+ @Override
+ public void onAnimationEnd(Animation animation) {
+ if (mActivity != null) {
+ mActivity.finish();
+ cleanup();
+ }
+ }
+
+ @Override
+ public void onAnimationRepeat(Animation animation) {
+ }
+
+ private void cleanup() {
+ mActivity = null;
+ mRootView = null;
+ }
+ }
+
@Override
protected void maybeLogProfileChange() {
getChooserActivityLogger().logShareheetProfileChanged();
diff --git a/core/java/com/android/internal/app/ConfirmUserCreationActivity.java b/core/java/com/android/internal/app/ConfirmUserCreationActivity.java
index ee4d46dbbbd3..8833512c2217 100644
--- a/core/java/com/android/internal/app/ConfirmUserCreationActivity.java
+++ b/core/java/com/android/internal/app/ConfirmUserCreationActivity.java
@@ -62,7 +62,7 @@ public class ConfirmUserCreationActivity extends AlertActivity
mAccountName = intent.getStringExtra(UserManager.EXTRA_USER_ACCOUNT_NAME);
mAccountType = intent.getStringExtra(UserManager.EXTRA_USER_ACCOUNT_TYPE);
mAccountOptions = (PersistableBundle)
- intent.getParcelableExtra(UserManager.EXTRA_USER_ACCOUNT_OPTIONS);
+ intent.getParcelableExtra(UserManager.EXTRA_USER_ACCOUNT_OPTIONS, android.os.PersistableBundle.class);
mUserManager = getSystemService(UserManager.class);
diff --git a/core/java/com/android/internal/app/HarmfulAppWarningActivity.java b/core/java/com/android/internal/app/HarmfulAppWarningActivity.java
index 33209e110123..c19196f46d27 100644
--- a/core/java/com/android/internal/app/HarmfulAppWarningActivity.java
+++ b/core/java/com/android/internal/app/HarmfulAppWarningActivity.java
@@ -54,7 +54,7 @@ public class HarmfulAppWarningActivity extends AlertActivity implements
getWindow().addSystemFlags(SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
final Intent intent = getIntent();
mPackageName = intent.getStringExtra(Intent.EXTRA_PACKAGE_NAME);
- mTarget = intent.getParcelableExtra(Intent.EXTRA_INTENT);
+ mTarget = intent.getParcelableExtra(Intent.EXTRA_INTENT, android.content.IntentSender.class);
mHarmfulAppWarning = intent.getStringExtra(EXTRA_HARMFUL_APP_WARNING);
if (mPackageName == null || mTarget == null || mHarmfulAppWarning == null) {
@@ -107,7 +107,7 @@ public class HarmfulAppWarningActivity extends AlertActivity implements
case DialogInterface.BUTTON_NEGATIVE:
getPackageManager().setHarmfulAppWarning(mPackageName, null /*warning*/);
- final IntentSender target = getIntent().getParcelableExtra(Intent.EXTRA_INTENT);
+ final IntentSender target = getIntent().getParcelableExtra(Intent.EXTRA_INTENT, android.content.IntentSender.class);
try {
startIntentSenderForResult(target, -1 /*requestCode*/, null /*fillInIntent*/,
0 /*flagsMask*/, 0 /*flagsValue*/, 0 /*extraFlags*/);
diff --git a/core/java/com/android/internal/app/HeavyWeightSwitcherActivity.java b/core/java/com/android/internal/app/HeavyWeightSwitcherActivity.java
index 015238788191..801c934676d7 100644
--- a/core/java/com/android/internal/app/HeavyWeightSwitcherActivity.java
+++ b/core/java/com/android/internal/app/HeavyWeightSwitcherActivity.java
@@ -66,7 +66,7 @@ public class HeavyWeightSwitcherActivity extends Activity {
requestWindowFeature(Window.FEATURE_NO_TITLE);
- mStartIntent = (IntentSender)getIntent().getParcelableExtra(KEY_INTENT);
+ mStartIntent = (IntentSender)getIntent().getParcelableExtra(KEY_INTENT, android.content.IntentSender.class);
mHasResult = getIntent().getBooleanExtra(KEY_HAS_RESULT, false);
mCurApp = getIntent().getStringExtra(KEY_CUR_APP);
mCurTask = getIntent().getIntExtra(KEY_CUR_TASK, 0);
diff --git a/core/java/com/android/internal/app/IntentForwarderActivity.java b/core/java/com/android/internal/app/IntentForwarderActivity.java
index 070d8ff945ba..47b83be35f87 100644
--- a/core/java/com/android/internal/app/IntentForwarderActivity.java
+++ b/core/java/com/android/internal/app/IntentForwarderActivity.java
@@ -224,7 +224,7 @@ public class IntentForwarderActivity extends Activity {
int selectedProfile = findSelectedProfile(className);
sanitizeIntent(intentReceived);
intentReceived.putExtra(EXTRA_SELECTED_PROFILE, selectedProfile);
- Intent innerIntent = intentReceived.getParcelableExtra(Intent.EXTRA_INTENT);
+ Intent innerIntent = intentReceived.getParcelableExtra(Intent.EXTRA_INTENT, android.content.Intent.class);
if (innerIntent == null) {
Slog.wtf(TAG, "Cannot start a chooser intent with no extra " + Intent.EXTRA_INTENT);
return;
diff --git a/core/java/com/android/internal/app/LaunchAfterAuthenticationActivity.java b/core/java/com/android/internal/app/LaunchAfterAuthenticationActivity.java
index 20a025a3ff54..c14d958f91fb 100644
--- a/core/java/com/android/internal/app/LaunchAfterAuthenticationActivity.java
+++ b/core/java/com/android/internal/app/LaunchAfterAuthenticationActivity.java
@@ -54,7 +54,7 @@ public class LaunchAfterAuthenticationActivity extends Activity {
super.onCreate(icicle);
final IntentSender onSuccessIntent = getIntent().getParcelableExtra(
- EXTRA_ON_SUCCESS_INTENT);
+ EXTRA_ON_SUCCESS_INTENT, android.content.IntentSender.class);
requestDismissKeyguardIfNeeded(onSuccessIntent);
}
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index 40429c609150..f67e78572402 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -500,7 +500,7 @@ public class ResolverActivity extends Activity implements
// this happens, we check for it here and set the current profile's tab.
int selectedProfile = getCurrentProfile();
UserHandle intentUser = getIntent().hasExtra(EXTRA_CALLING_USER)
- ? getIntent().getParcelableExtra(EXTRA_CALLING_USER)
+ ? getIntent().getParcelableExtra(EXTRA_CALLING_USER, android.os.UserHandle.class)
: getUser();
if (!getUser().equals(intentUser)) {
if (getPersonalProfileUserHandle().equals(intentUser)) {
@@ -1314,7 +1314,7 @@ public class ResolverActivity extends Activity implements
StrictMode.disableDeathOnFileUriExposure();
try {
UserHandle currentUserHandle = mMultiProfilePagerAdapter.getCurrentUserHandle();
- safelyStartActivityInternal(cti, currentUserHandle);
+ safelyStartActivityInternal(cti, currentUserHandle, null);
} finally {
StrictMode.enableDeathOnFileUriExposure();
}
@@ -1327,18 +1327,23 @@ public class ResolverActivity extends Activity implements
*/
@VisibleForTesting
public void safelyStartActivityAsUser(TargetInfo cti, UserHandle user) {
+ safelyStartActivityAsUser(cti, user, null);
+ }
+
+ protected void safelyStartActivityAsUser(
+ TargetInfo cti, UserHandle user, @Nullable Bundle options) {
// We're dispatching intents that might be coming from legacy apps, so
// don't kill ourselves.
StrictMode.disableDeathOnFileUriExposure();
try {
- safelyStartActivityInternal(cti, user);
+ safelyStartActivityInternal(cti, user, options);
} finally {
StrictMode.enableDeathOnFileUriExposure();
}
}
-
- private void safelyStartActivityInternal(TargetInfo cti, UserHandle user) {
+ private void safelyStartActivityInternal(
+ TargetInfo cti, UserHandle user, @Nullable Bundle options) {
// If the target is suspended, the activity will not be successfully launched.
// Do not unregister from package manager updates in this case
if (!cti.isSuspended() && mRegistered) {
@@ -1356,14 +1361,14 @@ public class ResolverActivity extends Activity implements
Toast.makeText(this, mProfileSwitchMessage, Toast.LENGTH_LONG).show();
}
if (!mSafeForwardingMode) {
- if (cti.startAsUser(this, null, user)) {
+ if (cti.startAsUser(this, options, user)) {
onActivityStarted(cti);
maybeLogCrossProfileTargetLaunch(cti, user);
}
return;
}
try {
- if (cti.startAsCaller(this, null, user.getIdentifier())) {
+ if (cti.startAsCaller(this, options, user.getIdentifier())) {
onActivityStarted(cti);
maybeLogCrossProfileTargetLaunch(cti, user);
}
diff --git a/core/java/com/android/internal/app/ResolverListAdapter.java b/core/java/com/android/internal/app/ResolverListAdapter.java
index 2ed0f981692e..737d5e348249 100644
--- a/core/java/com/android/internal/app/ResolverListAdapter.java
+++ b/core/java/com/android/internal/app/ResolverListAdapter.java
@@ -265,6 +265,7 @@ public class ResolverListAdapter extends BaseAdapter {
return mResolverListController.getResolversForIntent(
/* shouldGetResolvedFilter= */ true,
mResolverListCommunicator.shouldGetActivityMetadata(),
+ mResolverListCommunicator.shouldGetOnlyDefaultActivities(),
mIntents);
}
}
@@ -727,6 +728,7 @@ public class ResolverListAdapter extends BaseAdapter {
protected List<ResolvedComponentInfo> getResolversForUser(UserHandle userHandle) {
return mResolverListController.getResolversForIntentAsUser(true,
mResolverListCommunicator.shouldGetActivityMetadata(),
+ mResolverListCommunicator.shouldGetOnlyDefaultActivities(),
mIntents, userHandle);
}
@@ -820,6 +822,12 @@ public class ResolverListAdapter extends BaseAdapter {
boolean shouldGetActivityMetadata();
+ /**
+ * @return true to filter only apps that can handle
+ * {@link android.content.Intent#CATEGORY_DEFAULT} intents
+ */
+ default boolean shouldGetOnlyDefaultActivities() { return true; };
+
Intent getTargetIntent();
void onHandlePackagesChanged(ResolverListAdapter listAdapter);
diff --git a/core/java/com/android/internal/app/ResolverListController.java b/core/java/com/android/internal/app/ResolverListController.java
index 27573631b2ce..100fcd817812 100644
--- a/core/java/com/android/internal/app/ResolverListController.java
+++ b/core/java/com/android/internal/app/ResolverListController.java
@@ -110,17 +110,19 @@ public class ResolverListController {
public List<ResolverActivity.ResolvedComponentInfo> getResolversForIntent(
boolean shouldGetResolvedFilter,
boolean shouldGetActivityMetadata,
+ boolean shouldGetOnlyDefaultActivities,
List<Intent> intents) {
return getResolversForIntentAsUser(shouldGetResolvedFilter, shouldGetActivityMetadata,
- intents, mUserHandle);
+ shouldGetOnlyDefaultActivities, intents, mUserHandle);
}
public List<ResolverActivity.ResolvedComponentInfo> getResolversForIntentAsUser(
boolean shouldGetResolvedFilter,
boolean shouldGetActivityMetadata,
+ boolean shouldGetOnlyDefaultActivities,
List<Intent> intents,
UserHandle userHandle) {
- int baseFlags = PackageManager.MATCH_DEFAULT_ONLY
+ int baseFlags = (shouldGetOnlyDefaultActivities ? PackageManager.MATCH_DEFAULT_ONLY : 0)
| PackageManager.MATCH_DIRECT_BOOT_AWARE
| PackageManager.MATCH_DIRECT_BOOT_UNAWARE
| (shouldGetResolvedFilter ? PackageManager.GET_RESOLVED_FILTER : 0)
diff --git a/core/java/com/android/internal/app/SuspendedAppActivity.java b/core/java/com/android/internal/app/SuspendedAppActivity.java
index ec224e50eb8d..02881372c97f 100644
--- a/core/java/com/android/internal/app/SuspendedAppActivity.java
+++ b/core/java/com/android/internal/app/SuspendedAppActivity.java
@@ -219,8 +219,8 @@ public class SuspendedAppActivity extends AlertActivity
}
mSuspendedPackage = intent.getStringExtra(EXTRA_SUSPENDED_PACKAGE);
mSuspendingPackage = intent.getStringExtra(EXTRA_SUSPENDING_PACKAGE);
- mSuppliedDialogInfo = intent.getParcelableExtra(EXTRA_DIALOG_INFO);
- mOnUnsuspend = intent.getParcelableExtra(EXTRA_UNSUSPEND_INTENT);
+ mSuppliedDialogInfo = intent.getParcelableExtra(EXTRA_DIALOG_INFO, android.content.pm.SuspendDialogInfo.class);
+ mOnUnsuspend = intent.getParcelableExtra(EXTRA_UNSUSPEND_INTENT, android.content.IntentSender.class);
if (mSuppliedDialogInfo != null) {
try {
mSuspendingAppResources = createContextAsUser(
diff --git a/core/java/com/android/internal/app/UnlaunchableAppActivity.java b/core/java/com/android/internal/app/UnlaunchableAppActivity.java
index e56d92b48528..077657216119 100644
--- a/core/java/com/android/internal/app/UnlaunchableAppActivity.java
+++ b/core/java/com/android/internal/app/UnlaunchableAppActivity.java
@@ -62,7 +62,7 @@ public class UnlaunchableAppActivity extends Activity
Intent intent = getIntent();
mReason = intent.getIntExtra(EXTRA_UNLAUNCHABLE_REASON, -1);
mUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
- mTarget = intent.getParcelableExtra(Intent.EXTRA_INTENT);
+ mTarget = intent.getParcelableExtra(Intent.EXTRA_INTENT, android.content.IntentSender.class);
if (mUserId == UserHandle.USER_NULL) {
Log.wtf(TAG, "Invalid user id: " + mUserId + ". Stopping.");
diff --git a/core/java/com/android/internal/net/VpnProfile.java b/core/java/com/android/internal/net/VpnProfile.java
index b334e9172729..396da5b8869d 100644
--- a/core/java/com/android/internal/net/VpnProfile.java
+++ b/core/java/com/android/internal/net/VpnProfile.java
@@ -204,7 +204,7 @@ public final class VpnProfile implements Cloneable, Parcelable {
excludeLocalRoutes = in.readBoolean();
requiresInternetValidation = in.readBoolean();
final PersistableBundle bundle =
- in.readParcelable(PersistableBundle.class.getClassLoader());
+ in.readParcelable(PersistableBundle.class.getClassLoader(), android.os.PersistableBundle.class);
ikeTunConnParams = (bundle == null) ? null
: TunnelConnectionParamsUtils.fromPersistableBundle(bundle);
}
diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java
index 13bf64334f61..a352063aa6ee 100644
--- a/core/java/com/android/internal/policy/DecorView.java
+++ b/core/java/com/android/internal/policy/DecorView.java
@@ -1440,8 +1440,9 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
int size, boolean verticalBar, boolean seascape, int sideMargin, boolean animate,
boolean force, WindowInsetsController controller) {
state.present = state.attributes.isPresent(
- controller.isRequestedVisible(state.attributes.insetsType),
- mWindow.getAttributes().flags, force);
+ (controller.isRequestedVisible(state.attributes.insetsType)
+ || mLastShouldAlwaysConsumeSystemBars),
+ mWindow.getAttributes().flags, force);
boolean show = state.attributes.isVisible(state.present, color,
mWindow.getAttributes().flags, force);
boolean showView = show && !isResizing() && !mHasCaption && size > 0;
diff --git a/core/java/com/android/internal/util/ScreenshotHelper.java b/core/java/com/android/internal/util/ScreenshotHelper.java
index f4f438b1f601..518fa530c9a0 100644
--- a/core/java/com/android/internal/util/ScreenshotHelper.java
+++ b/core/java/com/android/internal/util/ScreenshotHelper.java
@@ -217,8 +217,8 @@ public class ScreenshotHelper {
throw new IllegalArgumentException("Bundle does not contain a hardware bitmap");
}
- HardwareBuffer buffer = bundle.getParcelable(KEY_BUFFER);
- ParcelableColorSpace colorSpace = bundle.getParcelable(KEY_COLOR_SPACE);
+ HardwareBuffer buffer = bundle.getParcelable(KEY_BUFFER, android.hardware.HardwareBuffer.class);
+ ParcelableColorSpace colorSpace = bundle.getParcelable(KEY_COLOR_SPACE, android.graphics.ParcelableColorSpace.class);
return Bitmap.wrapHardwareBuffer(Objects.requireNonNull(buffer),
colorSpace.getColorSpace());
diff --git a/core/java/com/android/internal/widget/CallLayout.java b/core/java/com/android/internal/widget/CallLayout.java
index 83345dad8ed9..acb0e44f29a6 100644
--- a/core/java/com/android/internal/widget/CallLayout.java
+++ b/core/java/com/android/internal/widget/CallLayout.java
@@ -125,7 +125,7 @@ public class CallLayout extends FrameLayout {
*/
@RemotableViewMethod
public void setData(Bundle extras) {
- setUser(extras.getParcelable(Notification.EXTRA_CALL_PERSON));
+ setUser(extras.getParcelable(Notification.EXTRA_CALL_PERSON, android.app.Person.class));
updateCallLayout();
}
diff --git a/core/java/com/android/internal/widget/ConversationLayout.java b/core/java/com/android/internal/widget/ConversationLayout.java
index 4706affa3541..9f21760a49e0 100644
--- a/core/java/com/android/internal/widget/ConversationLayout.java
+++ b/core/java/com/android/internal/widget/ConversationLayout.java
@@ -390,11 +390,11 @@ public class ConversationLayout extends FrameLayout
= Notification.MessagingStyle.Message.getMessagesFromBundleArray(histMessages);
// mUser now set (would be nice to avoid the side effect but WHATEVER)
- setUser(extras.getParcelable(Notification.EXTRA_MESSAGING_PERSON));
+ setUser(extras.getParcelable(Notification.EXTRA_MESSAGING_PERSON, android.app.Person.class));
// Append remote input history to newMessages (again, side effect is lame but WHATEVS)
RemoteInputHistoryItem[] history = (RemoteInputHistoryItem[])
- extras.getParcelableArray(Notification.EXTRA_REMOTE_INPUT_HISTORY_ITEMS);
+ extras.getParcelableArray(Notification.EXTRA_REMOTE_INPUT_HISTORY_ITEMS, android.app.RemoteInputHistoryItem.class);
addRemoteInputHistoryToMessages(newMessages, history);
boolean showSpinner =
diff --git a/core/java/com/android/internal/widget/MessagingLayout.java b/core/java/com/android/internal/widget/MessagingLayout.java
index 9ac6ef77bc07..67b671e01413 100644
--- a/core/java/com/android/internal/widget/MessagingLayout.java
+++ b/core/java/com/android/internal/widget/MessagingLayout.java
@@ -164,9 +164,9 @@ public class MessagingLayout extends FrameLayout
Parcelable[] histMessages = extras.getParcelableArray(Notification.EXTRA_HISTORIC_MESSAGES);
List<Notification.MessagingStyle.Message> newHistoricMessages
= Notification.MessagingStyle.Message.getMessagesFromBundleArray(histMessages);
- setUser(extras.getParcelable(Notification.EXTRA_MESSAGING_PERSON));
+ setUser(extras.getParcelable(Notification.EXTRA_MESSAGING_PERSON, android.app.Person.class));
RemoteInputHistoryItem[] history = (RemoteInputHistoryItem[])
- extras.getParcelableArray(Notification.EXTRA_REMOTE_INPUT_HISTORY_ITEMS);
+ extras.getParcelableArray(Notification.EXTRA_REMOTE_INPUT_HISTORY_ITEMS, android.app.RemoteInputHistoryItem.class);
addRemoteInputHistoryToMessages(newMessages, history);
boolean showSpinner =
extras.getBoolean(Notification.EXTRA_SHOW_REMOTE_INPUT_SPINNER, false);
diff --git a/core/java/com/android/internal/widget/ResolverDrawerLayout.java b/core/java/com/android/internal/widget/ResolverDrawerLayout.java
index 1cdc10866f2c..af9c5a5cc0d5 100644
--- a/core/java/com/android/internal/widget/ResolverDrawerLayout.java
+++ b/core/java/com/android/internal/widget/ResolverDrawerLayout.java
@@ -53,7 +53,7 @@ public class ResolverDrawerLayout extends ViewGroup {
/**
* Max width of the whole drawer layout
*/
- private int mMaxWidth;
+ private final int mMaxWidth;
/**
* Max total visible height of views not marked always-show when in the closed/initial state
@@ -187,8 +187,10 @@ public class ResolverDrawerLayout extends ViewGroup {
}
public void setSmallCollapsed(boolean smallCollapsed) {
- mSmallCollapsed = smallCollapsed;
- requestLayout();
+ if (mSmallCollapsed != smallCollapsed) {
+ mSmallCollapsed = smallCollapsed;
+ requestLayout();
+ }
}
public boolean isSmallCollapsed() {
@@ -200,9 +202,10 @@ public class ResolverDrawerLayout extends ViewGroup {
}
public void setShowAtTop(boolean showOnTop) {
- mShowAtTop = showOnTop;
- invalidate();
- requestLayout();
+ if (mShowAtTop != showOnTop) {
+ mShowAtTop = showOnTop;
+ requestLayout();
+ }
}
public boolean getShowAtTop() {
@@ -220,6 +223,9 @@ public class ResolverDrawerLayout extends ViewGroup {
public void setCollapsibleHeightReserved(int heightPixels) {
final int oldReserved = mCollapsibleHeightReserved;
mCollapsibleHeightReserved = heightPixels;
+ if (oldReserved != mCollapsibleHeightReserved) {
+ requestLayout();
+ }
final int dReserved = mCollapsibleHeightReserved - oldReserved;
if (dReserved != 0 && mIsDragging) {
@@ -255,7 +261,7 @@ public class ResolverDrawerLayout extends ViewGroup {
if (getShowAtTop()) {
// Keep the drawer fully open.
- mCollapseOffset = 0;
+ setCollapseOffset(0);
return false;
}
@@ -264,9 +270,9 @@ public class ResolverDrawerLayout extends ViewGroup {
if (remainClosed && (oldCollapsibleHeight < mCollapsibleHeight
&& mCollapseOffset == oldCollapsibleHeight)) {
// Stay closed even at the new height.
- mCollapseOffset = mCollapsibleHeight;
+ setCollapseOffset(mCollapsibleHeight);
} else {
- mCollapseOffset = Math.min(mCollapseOffset, mCollapsibleHeight);
+ setCollapseOffset(Math.min(mCollapseOffset, mCollapsibleHeight));
}
final boolean isCollapsedNew = mCollapseOffset != 0;
if (isCollapsedOld != isCollapsedNew) {
@@ -274,11 +280,18 @@ public class ResolverDrawerLayout extends ViewGroup {
}
} else {
// Start out collapsed at first unless we restored state for otherwise
- mCollapseOffset = mOpenOnLayout ? 0 : mCollapsibleHeight;
+ setCollapseOffset(mOpenOnLayout ? 0 : mCollapsibleHeight);
}
return true;
}
+ private void setCollapseOffset(float collapseOffset) {
+ if (mCollapseOffset != collapseOffset) {
+ mCollapseOffset = collapseOffset;
+ requestLayout();
+ }
+ }
+
private int getMaxCollapsedHeight() {
return (isSmallCollapsed() ? mMaxCollapsedHeightSmall : mMaxCollapsedHeight)
+ mCollapsibleHeightReserved;
@@ -420,8 +433,7 @@ public class ResolverDrawerLayout extends ViewGroup {
case MotionEvent.ACTION_POINTER_DOWN: {
final int pointerIndex = ev.getActionIndex();
- final int pointerId = ev.getPointerId(pointerIndex);
- mActivePointerId = pointerId;
+ mActivePointerId = ev.getPointerId(pointerIndex);
mInitialTouchX = ev.getX(pointerIndex);
mInitialTouchY = mLastTouchY = ev.getY(pointerIndex);
}
@@ -924,7 +936,7 @@ public class ResolverDrawerLayout extends ViewGroup {
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
final int sourceWidth = MeasureSpec.getSize(widthMeasureSpec);
int widthSize = sourceWidth;
- int heightSize = MeasureSpec.getSize(heightMeasureSpec);
+ final int heightSize = MeasureSpec.getSize(heightMeasureSpec);
// Single-use layout; just ignore the mode and use available space.
// Clamp to maxWidth.
diff --git a/core/jni/android_os_Parcel.cpp b/core/jni/android_os_Parcel.cpp
index 0d530f6aa2bb..bb4ab39a59d1 100644
--- a/core/jni/android_os_Parcel.cpp
+++ b/core/jni/android_os_Parcel.cpp
@@ -549,10 +549,15 @@ static jbyteArray android_os_Parcel_marshall(JNIEnv* env, jclass clazz, jlong na
return NULL;
}
- // do not marshall if there are binder objects in the parcel
+ if (parcel->isForRpc()) {
+ jniThrowException(env, "java/lang/RuntimeException", "Tried to marshall an RPC Parcel.");
+ return NULL;
+ }
+
if (parcel->objectsCount())
{
- jniThrowException(env, "java/lang/RuntimeException", "Tried to marshall a Parcel that contained Binder objects.");
+ jniThrowException(env, "java/lang/RuntimeException",
+ "Tried to marshall a Parcel that contains objects (binders or FDs).");
return NULL;
}
diff --git a/core/res/res/drawable-nodpi/default_wallpaper.png b/core/res/res/drawable-nodpi/default_wallpaper.png
index 5152972d2a80..a23f5539cca7 100644
--- a/core/res/res/drawable-nodpi/default_wallpaper.png
+++ b/core/res/res/drawable-nodpi/default_wallpaper.png
Binary files differ
diff --git a/core/res/res/drawable-sw600dp-nodpi/default_wallpaper.png b/core/res/res/drawable-sw600dp-nodpi/default_wallpaper.png
index 26376fb87cbe..1e272e06221c 100644
--- a/core/res/res/drawable-sw600dp-nodpi/default_wallpaper.png
+++ b/core/res/res/drawable-sw600dp-nodpi/default_wallpaper.png
Binary files differ
diff --git a/core/res/res/drawable-sw720dp-nodpi/default_wallpaper.png b/core/res/res/drawable-sw720dp-nodpi/default_wallpaper.png
index 490ebeeb75c1..d10c77d2f7f3 100644
--- a/core/res/res/drawable-sw720dp-nodpi/default_wallpaper.png
+++ b/core/res/res/drawable-sw720dp-nodpi/default_wallpaper.png
Binary files differ
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 557706fd8dd3..1997261af879 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -684,7 +684,7 @@
<!-- Lighting and shadow properties -->
<dimen name="light_y">0dp</dimen>
- <dimen name="light_z">600dp</dimen>
+ <dimen name="light_z">500dp</dimen>
<dimen name="light_radius">800dp</dimen>
<item type="dimen" format="float" name="ambient_shadow_alpha">0.039</item>
<item type="dimen" format="float" name="spot_shadow_alpha">0.19</item>
diff --git a/core/tests/coretests/src/android/view/WindowInfoTest.java b/core/tests/coretests/src/android/view/WindowInfoTest.java
index afc2c002db08..f9e3f43b562c 100644
--- a/core/tests/coretests/src/android/view/WindowInfoTest.java
+++ b/core/tests/coretests/src/android/view/WindowInfoTest.java
@@ -30,6 +30,7 @@ import android.graphics.Matrix;
import android.os.IBinder;
import android.os.Parcel;
import android.platform.test.annotations.Presubmit;
+import android.text.TextUtils;
import android.view.accessibility.AccessibilityNodeInfo;
import androidx.test.filters.SmallTest;
@@ -82,22 +83,7 @@ public class WindowInfoTest {
public void testDefaultValues() {
WindowInfo w = WindowInfo.obtain();
- assertEquals(0, w.type);
- assertEquals(0, w.layer);
- assertEquals(AccessibilityNodeInfo.UNDEFINED_NODE_ID, w.accessibilityIdOfAnchor);
- assertEquals(Display.INVALID_DISPLAY, w.displayId);
- assertEquals(ActivityTaskManager.INVALID_TASK_ID, w.taskId);
- assertNull(w.title);
- assertNull(w.token);
- assertNull(w.childTokens);
- assertNull(w.parentToken);
- assertNull(w.activityToken);
- assertFalse(w.focused);
- assertFalse(w.inPictureInPicture);
- assertFalse(w.hasFlagWatchOutsideTouch);
- assertTrue(w.regionInScreen.isEmpty());
- assertEquals(w.mTransformMatrix.length, 9);
- assertTrue(w.mMagnificationSpec.isNop());
+ assertDefaultValue(w);
}
@SmallTest
@@ -114,6 +100,37 @@ public class WindowInfoTest {
}
}
+ @SmallTest
+ @Test
+ public void testRecycle_fallbackToDefaultValues() {
+ WindowInfo w = WindowInfo.obtain();
+ initTestWindowInfo(w);
+ w.recycle();
+
+ assertDefaultValue(w);
+ }
+
+ private static void assertDefaultValue(WindowInfo windowinfo) {
+ assertEquals(0, windowinfo.type);
+ assertEquals(0, windowinfo.layer);
+ assertEquals(AccessibilityNodeInfo.UNDEFINED_NODE_ID, windowinfo.accessibilityIdOfAnchor);
+ assertEquals(Display.INVALID_DISPLAY, windowinfo.displayId);
+ assertEquals(ActivityTaskManager.INVALID_TASK_ID, windowinfo.taskId);
+ assertNull(windowinfo.title);
+ assertNull(windowinfo.token);
+ if (windowinfo.childTokens != null) {
+ assertTrue(windowinfo.childTokens.isEmpty());
+ }
+ assertNull(windowinfo.parentToken);
+ assertNull(windowinfo.activityToken);
+ assertFalse(windowinfo.focused);
+ assertFalse(windowinfo.inPictureInPicture);
+ assertFalse(windowinfo.hasFlagWatchOutsideTouch);
+ assertTrue(windowinfo.regionInScreen.isEmpty());
+ assertEquals(windowinfo.mTransformMatrix.length, 9);
+ assertTrue(windowinfo.mMagnificationSpec.isNop());
+ }
+
private boolean areWindowsEqual(WindowInfo w1, WindowInfo w2) {
boolean equality = w1.toString().contentEquals(w2.toString());
equality &= w1.token == w2.token;
@@ -123,6 +140,7 @@ public class WindowInfoTest {
equality &= w1.regionInScreen.equals(w2.regionInScreen);
equality &= w1.mMagnificationSpec.equals(w2.mMagnificationSpec);
equality &= Arrays.equals(w1.mTransformMatrix, w2.mTransformMatrix);
+ equality &= TextUtils.equals(w1.title, w2.title);
return equality;
}
diff --git a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
index 82148422aabf..e8c7ce0b312b 100644
--- a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
+++ b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
@@ -266,6 +266,7 @@ public class ChooserActivityTest {
.getResolversForIntent(
Mockito.anyBoolean(),
Mockito.anyBoolean(),
+ Mockito.anyBoolean(),
Mockito.isA(List.class)))
.thenReturn(resolvedComponentInfos);
final IChooserWrapper activity = (IChooserWrapper) mActivityRule.launchActivity(
@@ -289,6 +290,7 @@ public class ChooserActivityTest {
.getResolversForIntent(
Mockito.anyBoolean(),
Mockito.anyBoolean(),
+ Mockito.anyBoolean(),
Mockito.isA(List.class)))
.thenReturn(resolvedComponentInfos);
mActivityRule.launchActivity(Intent.createChooser(sendIntent, "chooser test"));
@@ -309,6 +311,7 @@ public class ChooserActivityTest {
.getResolversForIntent(
Mockito.anyBoolean(),
Mockito.anyBoolean(),
+ Mockito.anyBoolean(),
Mockito.isA(List.class)))
.thenReturn(resolvedComponentInfos);
mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
@@ -329,6 +332,7 @@ public class ChooserActivityTest {
.getResolversForIntent(
Mockito.anyBoolean(),
Mockito.anyBoolean(),
+ Mockito.anyBoolean(),
Mockito.isA(List.class)))
.thenReturn(resolvedComponentInfos);
mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
@@ -352,6 +356,7 @@ public class ChooserActivityTest {
.getResolversForIntent(
Mockito.anyBoolean(),
Mockito.anyBoolean(),
+ Mockito.anyBoolean(),
Mockito.isA(List.class)))
.thenReturn(resolvedComponentInfos);
mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
@@ -378,6 +383,7 @@ public class ChooserActivityTest {
.getResolversForIntent(
Mockito.anyBoolean(),
Mockito.anyBoolean(),
+ Mockito.anyBoolean(),
Mockito.isA(List.class)))
.thenReturn(resolvedComponentInfos);
mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
@@ -403,6 +409,7 @@ public class ChooserActivityTest {
.getResolversForIntent(
Mockito.anyBoolean(),
Mockito.anyBoolean(),
+ Mockito.anyBoolean(),
Mockito.isA(List.class)))
.thenReturn(resolvedComponentInfos);
mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
@@ -424,6 +431,7 @@ public class ChooserActivityTest {
.getResolversForIntent(
Mockito.anyBoolean(),
Mockito.anyBoolean(),
+ Mockito.anyBoolean(),
Mockito.isA(List.class)))
.thenReturn(resolvedComponentInfos);
@@ -478,6 +486,7 @@ public class ChooserActivityTest {
.getResolversForIntent(
Mockito.anyBoolean(),
Mockito.anyBoolean(),
+ Mockito.anyBoolean(),
Mockito.isA(List.class)))
.thenReturn(resolvedComponentInfos);
@@ -518,6 +527,7 @@ public class ChooserActivityTest {
.getResolversForIntent(
Mockito.anyBoolean(),
Mockito.anyBoolean(),
+ Mockito.anyBoolean(),
Mockito.isA(List.class)))
.thenReturn(resolvedComponentInfos);
@@ -552,6 +562,7 @@ public class ChooserActivityTest {
.getResolversForIntent(
Mockito.anyBoolean(),
Mockito.anyBoolean(),
+ Mockito.anyBoolean(),
Mockito.isA(List.class)))
.thenReturn(null);
Intent sendIntent = createSendTextIntent();
@@ -587,6 +598,7 @@ public class ChooserActivityTest {
.getResolversForIntent(
Mockito.anyBoolean(),
Mockito.anyBoolean(),
+ Mockito.anyBoolean(),
Mockito.isA(List.class)))
.thenReturn(resolvedComponentInfos);
@@ -649,6 +661,7 @@ public class ChooserActivityTest {
when(ChooserActivityOverrideData.getInstance().resolverListController.getResolversForIntent(
Mockito.anyBoolean(),
Mockito.anyBoolean(),
+ Mockito.anyBoolean(),
Mockito.isA(List.class))).thenReturn(resolvedComponentInfos);
when(ChooserActivityOverrideData.getInstance().resolverListController.getLastChosen())
.thenReturn(resolvedComponentInfos.get(0).getResolveInfoAt(0));
@@ -688,6 +701,7 @@ public class ChooserActivityTest {
when(ChooserActivityOverrideData.getInstance().resolverListController.getResolversForIntent(
Mockito.anyBoolean(),
Mockito.anyBoolean(),
+ Mockito.anyBoolean(),
Mockito.isA(List.class))).thenReturn(resolvedComponentInfos);
final IChooserWrapper activity = (IChooserWrapper)
@@ -720,6 +734,7 @@ public class ChooserActivityTest {
when(ChooserActivityOverrideData.getInstance().resolverListController.getResolversForIntent(
Mockito.anyBoolean(),
Mockito.anyBoolean(),
+ Mockito.anyBoolean(),
Mockito.isA(List.class))).thenReturn(resolvedComponentInfos);
final ChooserActivity activity =
@@ -747,6 +762,7 @@ public class ChooserActivityTest {
when(ChooserActivityOverrideData.getInstance().resolverListController.getResolversForIntent(
Mockito.anyBoolean(),
Mockito.anyBoolean(),
+ Mockito.anyBoolean(),
Mockito.isA(List.class))).thenReturn(resolvedComponentInfos);
MetricsLogger mockLogger = ChooserActivityOverrideData.getInstance().metricsLogger;
@@ -776,6 +792,7 @@ public class ChooserActivityTest {
when(ChooserActivityOverrideData.getInstance().resolverListController.getResolversForIntent(
Mockito.anyBoolean(),
Mockito.anyBoolean(),
+ Mockito.anyBoolean(),
Mockito.isA(List.class))).thenReturn(resolvedComponentInfos);
final IChooserWrapper activity = (IChooserWrapper)
@@ -846,6 +863,7 @@ public class ChooserActivityTest {
when(ChooserActivityOverrideData.getInstance().resolverListController.getResolversForIntent(
Mockito.anyBoolean(),
Mockito.anyBoolean(),
+ Mockito.anyBoolean(),
Mockito.isA(List.class))).thenReturn(resolvedComponentInfos);
final IChooserWrapper activity = (IChooserWrapper)
@@ -922,6 +940,7 @@ public class ChooserActivityTest {
.getResolversForIntent(
Mockito.anyBoolean(),
Mockito.anyBoolean(),
+ Mockito.anyBoolean(),
Mockito.isA(List.class)))
.thenReturn(resolvedComponentInfos);
mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
@@ -958,6 +977,7 @@ public class ChooserActivityTest {
.getResolversForIntent(
Mockito.anyBoolean(),
Mockito.anyBoolean(),
+ Mockito.anyBoolean(),
Mockito.isA(List.class)))
.thenReturn(resolvedComponentInfos);
mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
@@ -997,6 +1017,7 @@ public class ChooserActivityTest {
.getResolversForIntent(
Mockito.anyBoolean(),
Mockito.anyBoolean(),
+ Mockito.anyBoolean(),
Mockito.isA(List.class)))
.thenReturn(resolvedComponentInfos);
mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
@@ -1091,6 +1112,7 @@ public class ChooserActivityTest {
when(ChooserActivityOverrideData.getInstance().resolverListController.getResolversForIntent(
Mockito.anyBoolean(),
Mockito.anyBoolean(),
+ Mockito.anyBoolean(),
Mockito.isA(List.class))).thenReturn(resolvedComponentInfos);
mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
@@ -1124,6 +1146,7 @@ public class ChooserActivityTest {
.getResolversForIntent(
Mockito.anyBoolean(),
Mockito.anyBoolean(),
+ Mockito.anyBoolean(),
Mockito.isA(List.class)))
.thenReturn(resolvedComponentInfos);
@@ -1157,6 +1180,7 @@ public class ChooserActivityTest {
.getResolversForIntent(
Mockito.anyBoolean(),
Mockito.anyBoolean(),
+ Mockito.anyBoolean(),
Mockito.isA(List.class)))
.thenReturn(resolvedComponentInfos);
mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
@@ -1189,6 +1213,7 @@ public class ChooserActivityTest {
.getResolversForIntent(
Mockito.anyBoolean(),
Mockito.anyBoolean(),
+ Mockito.anyBoolean(),
Mockito.isA(List.class)))
.thenReturn(resolvedComponentInfos);
mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
@@ -1218,6 +1243,7 @@ public class ChooserActivityTest {
.getResolversForIntent(
Mockito.anyBoolean(),
Mockito.anyBoolean(),
+ Mockito.anyBoolean(),
Mockito.isA(List.class)))
.thenReturn(resolvedComponentInfos);
@@ -1250,6 +1276,7 @@ public class ChooserActivityTest {
.getResolversForIntent(
Mockito.anyBoolean(),
Mockito.anyBoolean(),
+ Mockito.anyBoolean(),
Mockito.isA(List.class)))
.thenReturn(resolvedComponentInfos);
@@ -1284,6 +1311,7 @@ public class ChooserActivityTest {
.getResolversForIntent(
Mockito.anyBoolean(),
Mockito.anyBoolean(),
+ Mockito.anyBoolean(),
Mockito.isA(List.class)))
.thenReturn(resolvedComponentInfos);
when(
@@ -1323,6 +1351,7 @@ public class ChooserActivityTest {
.getResolversForIntent(
Mockito.anyBoolean(),
Mockito.anyBoolean(),
+ Mockito.anyBoolean(),
Mockito.isA(List.class)))
.thenReturn(resolvedComponentInfos);
@@ -1365,6 +1394,7 @@ public class ChooserActivityTest {
.getResolversForIntent(
Mockito.anyBoolean(),
Mockito.anyBoolean(),
+ Mockito.anyBoolean(),
Mockito.isA(List.class)))
.thenReturn(resolvedComponentInfos);
@@ -1409,6 +1439,7 @@ public class ChooserActivityTest {
.getResolversForIntent(
Mockito.anyBoolean(),
Mockito.anyBoolean(),
+ Mockito.anyBoolean(),
Mockito.isA(List.class)))
.thenReturn(resolvedComponentInfos);
@@ -1485,6 +1516,7 @@ public class ChooserActivityTest {
.getResolversForIntent(
Mockito.anyBoolean(),
Mockito.anyBoolean(),
+ Mockito.anyBoolean(),
Mockito.isA(List.class)))
.thenReturn(resolvedComponentInfos);
@@ -1566,6 +1598,7 @@ public class ChooserActivityTest {
.getResolversForIntent(
Mockito.anyBoolean(),
Mockito.anyBoolean(),
+ Mockito.anyBoolean(),
Mockito.isA(List.class)))
.thenReturn(resolvedComponentInfos);
// Create direct share target
@@ -1638,6 +1671,7 @@ public class ChooserActivityTest {
.getResolversForIntent(
Mockito.anyBoolean(),
Mockito.anyBoolean(),
+ Mockito.anyBoolean(),
Mockito.isA(List.class)))
.thenReturn(resolvedComponentInfos);
// Create direct share target
@@ -1745,6 +1779,7 @@ public class ChooserActivityTest {
.getResolversForIntent(
Mockito.anyBoolean(),
Mockito.anyBoolean(),
+ Mockito.anyBoolean(),
Mockito.isA(List.class)))
.thenReturn(resolvedComponentInfos);
@@ -2060,6 +2095,7 @@ public class ChooserActivityTest {
.getResolversForIntent(
Mockito.anyBoolean(),
Mockito.anyBoolean(),
+ Mockito.anyBoolean(),
Mockito.isA(List.class)))
.thenReturn(resolvedComponentInfos);
@@ -2142,6 +2178,7 @@ public class ChooserActivityTest {
.getResolversForIntent(
Mockito.anyBoolean(),
Mockito.anyBoolean(),
+ Mockito.anyBoolean(),
Mockito.isA(List.class)))
.thenReturn(resolvedComponentInfos);
@@ -2229,6 +2266,7 @@ public class ChooserActivityTest {
.getResolversForIntent(
Mockito.anyBoolean(),
Mockito.anyBoolean(),
+ Mockito.anyBoolean(),
Mockito.isA(List.class)))
.thenReturn(resolvedComponentInfos);
@@ -2298,6 +2336,7 @@ public class ChooserActivityTest {
.getResolversForIntent(
Mockito.anyBoolean(),
Mockito.anyBoolean(),
+ Mockito.anyBoolean(),
Mockito.isA(List.class)))
.thenReturn(resolvedComponentInfos);
@@ -2446,6 +2485,7 @@ public class ChooserActivityTest {
.getResolversForIntent(
Mockito.anyBoolean(),
Mockito.anyBoolean(),
+ Mockito.anyBoolean(),
Mockito.isA(List.class)))
.thenReturn(new ArrayList<>(personalResolvedComponentInfos));
Intent sendIntent = createSendTextIntent();
@@ -2475,6 +2515,7 @@ public class ChooserActivityTest {
.getResolversForIntent(
Mockito.anyBoolean(),
Mockito.anyBoolean(),
+ Mockito.anyBoolean(),
Mockito.isA(List.class)))
.thenReturn(new ArrayList<>(personalResolvedComponentInfos));
Intent sendIntent = createSendTextIntent();
@@ -2528,6 +2569,7 @@ public class ChooserActivityTest {
.getResolversForIntent(
Mockito.anyBoolean(),
Mockito.anyBoolean(),
+ Mockito.anyBoolean(),
Mockito.isA(List.class)))
.thenReturn(new ArrayList<>(personalResolvedComponentInfos));
Intent chooserIntent = createChooserIntent(createSendTextIntent(),
@@ -2664,6 +2706,7 @@ public class ChooserActivityTest {
when(ChooserActivityOverrideData.getInstance().resolverListController.getResolversForIntent(
Mockito.anyBoolean(),
Mockito.anyBoolean(),
+ Mockito.anyBoolean(),
Mockito.isA(List.class)))
.thenReturn(new ArrayList<>(personalResolvedComponentInfos));
// Create caller target which is duplicate with one of app targets
@@ -3057,6 +3100,7 @@ public class ChooserActivityTest {
.getResolversForIntent(
Mockito.anyBoolean(),
Mockito.anyBoolean(),
+ Mockito.anyBoolean(),
Mockito.isA(List.class)))
.thenReturn(new ArrayList<>(personalResolvedComponentInfos));
when(
@@ -3066,6 +3110,7 @@ public class ChooserActivityTest {
.getResolversForIntent(
Mockito.anyBoolean(),
Mockito.anyBoolean(),
+ Mockito.anyBoolean(),
Mockito.isA(List.class)))
.thenReturn(new ArrayList<>(workResolvedComponentInfos));
when(
@@ -3075,6 +3120,7 @@ public class ChooserActivityTest {
.getResolversForIntentAsUser(
Mockito.anyBoolean(),
Mockito.anyBoolean(),
+ Mockito.anyBoolean(),
Mockito.isA(List.class),
eq(UserHandle.SYSTEM)))
.thenReturn(new ArrayList<>(personalResolvedComponentInfos));
@@ -3131,6 +3177,7 @@ public class ChooserActivityTest {
.getResolversForIntent(
Mockito.anyBoolean(),
Mockito.anyBoolean(),
+ Mockito.anyBoolean(),
Mockito.isA(List.class)))
.thenReturn(resolvedComponentInfos);
}
diff --git a/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java b/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java
index 43fba529182e..92c05b0fe9fc 100644
--- a/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java
+++ b/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java
@@ -96,6 +96,7 @@ public class ResolverActivityTest {
when(sOverrides.resolverListController.getResolversForIntent(Mockito.anyBoolean(),
Mockito.anyBoolean(),
+ Mockito.anyBoolean(),
Mockito.isA(List.class))).thenReturn(resolvedComponentInfos);
final ResolverWrapperActivity activity = mActivityRule.launchActivity(sendIntent);
@@ -127,6 +128,7 @@ public class ResolverActivityTest {
when(sOverrides.resolverListController.getResolversForIntent(Mockito.anyBoolean(),
Mockito.anyBoolean(),
+ Mockito.anyBoolean(),
Mockito.isA(List.class))).thenReturn(resolvedComponentInfos);
waitForIdle();
@@ -171,6 +173,7 @@ public class ResolverActivityTest {
when(sOverrides.resolverListController.getResolversForIntent(Mockito.anyBoolean(),
Mockito.anyBoolean(),
+ Mockito.anyBoolean(),
Mockito.isA(List.class))).thenReturn(resolvedComponentInfos);
waitForIdle();
@@ -203,6 +206,7 @@ public class ResolverActivityTest {
when(sOverrides.resolverListController.getResolversForIntent(Mockito.anyBoolean(),
Mockito.anyBoolean(),
+ Mockito.anyBoolean(),
Mockito.isA(List.class))).thenReturn(resolvedComponentInfos);
when(sOverrides.resolverListController.getLastChosen())
.thenReturn(resolvedComponentInfos.get(0).getResolveInfoAt(0));
@@ -273,6 +277,7 @@ public class ResolverActivityTest {
when(sOverrides.resolverListController.getResolversForIntent(Mockito.anyBoolean(),
Mockito.anyBoolean(),
+ Mockito.anyBoolean(),
Mockito.isA(List.class))).thenReturn(resolvedComponentInfos);
final ResolverWrapperActivity activity = mActivityRule.launchActivity(sendIntent);
@@ -317,6 +322,7 @@ public class ResolverActivityTest {
when(sOverrides.resolverListController.getResolversForIntent(Mockito.anyBoolean(),
Mockito.anyBoolean(),
+ Mockito.anyBoolean(),
Mockito.isA(List.class))).thenReturn(resolvedComponentInfos);
when(sOverrides.resolverListController.getLastChosen())
.thenReturn(resolvedComponentInfos.get(1).getResolveInfoAt(0));
@@ -807,6 +813,7 @@ public class ResolverActivityTest {
createResolvedComponentsForTestWithOtherProfile(2, /* userId */ 10);
when(sOverrides.resolverListController.getResolversForIntent(Mockito.anyBoolean(),
Mockito.anyBoolean(),
+ Mockito.anyBoolean(),
Mockito.isA(List.class)))
.thenReturn(new ArrayList<>(personalResolvedComponentInfos));
Intent sendIntent = createSendImageIntent();
@@ -831,6 +838,7 @@ public class ResolverActivityTest {
createResolvedComponentsForTest(1);
when(sOverrides.resolverListController.getResolversForIntent(Mockito.anyBoolean(),
Mockito.anyBoolean(),
+ Mockito.anyBoolean(),
Mockito.isA(List.class)))
.thenReturn(new ArrayList<>(personalResolvedComponentInfos));
Intent sendIntent = createSendImageIntent();
@@ -888,6 +896,7 @@ public class ResolverActivityTest {
when(sOverrides.resolverListController.getResolversForIntent(Mockito.anyBoolean(),
Mockito.anyBoolean(),
+ Mockito.anyBoolean(),
Mockito.isA(List.class))).thenReturn(resolvedComponentInfos);
when(sOverrides.resolverListController.getLastChosen())
.thenReturn(resolvedComponentInfos.get(1).getResolveInfoAt(0));
@@ -965,13 +974,16 @@ public class ResolverActivityTest {
List<ResolvedComponentInfo> workResolvedComponentInfos) {
when(sOverrides.resolverListController.getResolversForIntent(Mockito.anyBoolean(),
Mockito.anyBoolean(),
+ Mockito.anyBoolean(),
Mockito.isA(List.class)))
.thenReturn(new ArrayList<>(personalResolvedComponentInfos));
when(sOverrides.workResolverListController.getResolversForIntent(Mockito.anyBoolean(),
Mockito.anyBoolean(),
+ Mockito.anyBoolean(),
Mockito.isA(List.class))).thenReturn(workResolvedComponentInfos);
when(sOverrides.workResolverListController.getResolversForIntentAsUser(Mockito.anyBoolean(),
Mockito.anyBoolean(),
+ Mockito.anyBoolean(),
Mockito.isA(List.class),
eq(UserHandle.SYSTEM)))
.thenReturn(new ArrayList<>(personalResolvedComponentInfos));
diff --git a/core/tests/coretests/src/com/android/internal/app/ResolverListControllerTest.java b/core/tests/coretests/src/com/android/internal/app/ResolverListControllerTest.java
index e16d44854516..42593f60094b 100644
--- a/core/tests/coretests/src/com/android/internal/app/ResolverListControllerTest.java
+++ b/core/tests/coretests/src/com/android/internal/app/ResolverListControllerTest.java
@@ -20,11 +20,14 @@ import static junit.framework.Assert.assertEquals;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.hasSize;
+import static org.mockito.ArgumentMatchers.intThat;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyLong;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.usage.IUsageStatsManager;
@@ -48,6 +51,7 @@ import com.android.internal.app.ResolverActivity.ResolvedComponentInfo;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentMatcher;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.invocation.InvocationOnMock;
@@ -78,6 +82,8 @@ public class ResolverListControllerTest {
Configuration config = new Configuration();
config.locale = Locale.getDefault();
List<ResolveInfo> services = new ArrayList<>();
+ mUsm = new UsageStatsManager(mMockContext, mMockService);
+ when(mMockContext.getSystemService(Context.USAGE_STATS_SERVICE)).thenReturn(mUsm);
when(mMockPackageManager.queryIntentServices(any(), anyInt())).thenReturn(services);
when(mMockResources.getConfiguration()).thenReturn(config);
when(mMockContext.getResources()).thenReturn(mMockResources);
@@ -112,8 +118,6 @@ public class ResolverListControllerTest {
doAnswer(answer).when(mMockService).reportChooserSelection(
anyString(), anyInt(), anyString(), any(), anyString());
when(mMockContext.getOpPackageName()).thenReturn(refererPackage);
- mUsm = new UsageStatsManager(mMockContext, mMockService);
- when(mMockContext.getSystemService(Context.USAGE_STATS_SERVICE)).thenReturn(mUsm);
mController = new ResolverListController(mMockContext, mMockPackageManager, sendIntent,
refererPackage, UserHandle.USER_CURRENT, /* userHandle */ UserHandle.SYSTEM);
mController.sort(new ArrayList<ResolvedComponentInfo>());
@@ -129,8 +133,6 @@ public class ResolverListControllerTest {
Intent sendIntent = createSendImageIntent(annotation);
String refererPackage = "test_referer_package";
List<ResolvedComponentInfo> resolvedComponents = createResolvedComponentsForTest(10);
- mUsm = new UsageStatsManager(mMockContext, mMockService);
- when(mMockContext.getSystemService(Context.USAGE_STATS_SERVICE)).thenReturn(mUsm);
mController = new ResolverListController(mMockContext, mMockPackageManager, sendIntent,
refererPackage, UserHandle.USER_CURRENT, /* userHandle */ UserHandle.SYSTEM);
List<ResolvedComponentInfo> topKList = new ArrayList<>(resolvedComponents);
@@ -151,6 +153,102 @@ public class ResolverListControllerTest {
sortList, topKList);
}
+ @Test
+ public void getResolversForIntent_usesResultsFromPackageManager() {
+ mockStats();
+ List<ResolveInfo> infos = new ArrayList<>();
+ infos.add(ResolverDataProvider.createResolveInfo(0, UserHandle.USER_CURRENT));
+ when(mMockPackageManager.queryIntentActivitiesAsUser(any(), anyInt(),
+ any(UserHandle.class))).thenReturn(infos);
+ mController = new ResolverListController(mMockContext, mMockPackageManager,
+ createSendImageIntent("test"), null, UserHandle.USER_CURRENT,
+ /* userHandle= */ UserHandle.SYSTEM);
+ List<Intent> intents = new ArrayList<>();
+ intents.add(createActionMainIntent());
+
+ List<ResolvedComponentInfo> resolvers = mController
+ .getResolversForIntent(
+ /* shouldGetResolvedFilter= */ true,
+ /* shouldGetActivityMetadata= */ true,
+ /* shouldGetOnlyDefaultActivities= */ true,
+ intents);
+
+ assertThat(resolvers, hasSize(1));
+ assertThat(resolvers.get(0).getResolveInfoAt(0), is(infos.get(0)));
+ }
+
+ @Test
+ public void getResolversForIntent_shouldGetOnlyDefaultActivitiesTrue_addsFlag() {
+ mockStats();
+ List<ResolveInfo> infos = new ArrayList<>();
+ infos.add(ResolverDataProvider.createResolveInfo(0, UserHandle.USER_CURRENT));
+ when(mMockPackageManager.queryIntentActivitiesAsUser(any(), anyInt(),
+ any(UserHandle.class))).thenReturn(infos);
+ mController = new ResolverListController(mMockContext, mMockPackageManager,
+ createSendImageIntent("test"), null, UserHandle.USER_CURRENT,
+ /* userHandle= */ UserHandle.SYSTEM);
+ List<Intent> intents = new ArrayList<>();
+ intents.add(createActionMainIntent());
+
+ mController
+ .getResolversForIntent(
+ /* shouldGetResolvedFilter= */ true,
+ /* shouldGetActivityMetadata= */ true,
+ /* shouldGetOnlyDefaultActivities= */ true,
+ intents);
+
+ verify(mMockPackageManager).queryIntentActivitiesAsUser(any(),
+ containsFlag(PackageManager.MATCH_DEFAULT_ONLY), any());
+ }
+
+ @Test
+ public void getResolversForIntent_shouldGetOnlyDefaultActivitiesFalse_doesNotAddFlag() {
+ mockStats();
+ List<ResolveInfo> infos = new ArrayList<>();
+ infos.add(ResolverDataProvider.createResolveInfo(0, UserHandle.USER_CURRENT));
+ when(mMockPackageManager.queryIntentActivitiesAsUser(any(), anyInt(),
+ any(UserHandle.class))).thenReturn(infos);
+ mController = new ResolverListController(mMockContext, mMockPackageManager,
+ createSendImageIntent("test"), null, UserHandle.USER_CURRENT,
+ /* userHandle= */ UserHandle.SYSTEM);
+ List<Intent> intents = new ArrayList<>();
+ intents.add(createActionMainIntent());
+
+ mController
+ .getResolversForIntent(
+ /* shouldGetResolvedFilter= */ true,
+ /* shouldGetActivityMetadata= */ true,
+ /* shouldGetOnlyDefaultActivities= */ false,
+ intents);
+
+ verify(mMockPackageManager).queryIntentActivitiesAsUser(any(),
+ doesNotContainFlag(PackageManager.MATCH_DEFAULT_ONLY), any());
+ }
+
+ private int containsFlag(int flag) {
+ return intThat(new FlagMatcher(flag, /* contains= */ true));
+ }
+
+ private int doesNotContainFlag(int flag) {
+ return intThat(new FlagMatcher(flag, /* contains= */ false));
+ }
+
+ public static class FlagMatcher implements ArgumentMatcher<Integer> {
+
+ private final int mFlag;
+ private final boolean mContains;
+
+ public FlagMatcher(int flag, boolean contains) {
+ mFlag = flag;
+ mContains = contains;
+ }
+
+ @Override
+ public boolean matches(Integer integer) {
+ return ((integer & mFlag) != 0) == mContains;
+ }
+ }
+
private UsageStats initStats(String packageName, String action,
String annotation, int count) {
ArrayMap<String, ArrayMap<String, Integer>> chooserCounts = new ArrayMap<>();
@@ -174,6 +272,24 @@ public class ResolverListControllerTest {
return sendIntent;
}
+ private Intent createActionMainIntent() {
+ Intent sendIntent = new Intent();
+ sendIntent.setAction(Intent.ACTION_MAIN);
+ sendIntent.addCategory(Intent.CATEGORY_LAUNCHER);
+ return sendIntent;
+ }
+
+ private void mockStats() {
+ final List<UsageStats> slices = new ArrayList<>();
+ ParceledListSlice<UsageStats> stats = new ParceledListSlice<>(slices);
+ try {
+ when(mMockService.queryUsageStats(anyInt(), anyLong(), anyLong(), anyString(),
+ anyInt())).thenReturn(stats);
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ }
+ }
+
private Integer getCount(
UsageStatsManager usm, String packageName, String action, String annotation) {
if (usm == null) {
diff --git a/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java b/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java
index 8d3751e6ad6c..47f70ddf2d42 100644
--- a/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java
+++ b/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java
@@ -207,8 +207,8 @@ public class ActivityThreadClientTest {
final Configuration currentConfig = new Configuration();
assertFalse("Must not report change if no public diff",
- shouldReportChange(0 /* publicDiff */, currentConfig, newConfig,
- null /* sizeBuckets */, 0 /* handledConfigChanges */));
+ shouldReportChange(currentConfig, newConfig, null /* sizeBuckets */,
+ 0 /* handledConfigChanges */));
final int[] verticalThresholds = {100, 400};
final SizeConfigurationBuckets buckets = new SizeConfigurationBuckets(
@@ -221,25 +221,25 @@ public class ActivityThreadClientTest {
newConfig.screenHeightDp = 300;
assertFalse("Must not report changes if the diff is small and not handled",
- shouldReportChange(CONFIG_SCREEN_SIZE /* publicDiff */, currentConfig,
- newConfig, buckets, CONFIG_FONT_SCALE /* handledConfigChanges */));
+ shouldReportChange(currentConfig, newConfig, buckets,
+ CONFIG_FONT_SCALE /* handledConfigChanges */));
assertTrue("Must report changes if the small diff is handled",
- shouldReportChange(CONFIG_SCREEN_SIZE /* publicDiff */, currentConfig, newConfig,
- buckets, CONFIG_SCREEN_SIZE /* handledConfigChanges */));
+ shouldReportChange(currentConfig, newConfig, buckets,
+ CONFIG_SCREEN_SIZE /* handledConfigChanges */));
currentConfig.fontScale = 0.8f;
newConfig.fontScale = 1.2f;
assertTrue("Must report handled changes regardless of small unhandled change",
- shouldReportChange(CONFIG_SCREEN_SIZE | CONFIG_FONT_SCALE /* publicDiff */,
- currentConfig, newConfig, buckets, CONFIG_FONT_SCALE /* handledConfigChanges */));
+ shouldReportChange(currentConfig, newConfig, buckets,
+ CONFIG_FONT_SCALE /* handledConfigChanges */));
newConfig.screenHeightDp = 500;
assertFalse("Must not report changes if there's unhandled big changes",
- shouldReportChange(CONFIG_SCREEN_SIZE | CONFIG_FONT_SCALE /* publicDiff */,
- currentConfig, newConfig, buckets, CONFIG_FONT_SCALE /* handledConfigChanges */));
+ shouldReportChange(currentConfig, newConfig, buckets,
+ CONFIG_FONT_SCALE /* handledConfigChanges */));
}
private void recreateAndVerifyNoRelaunch(ActivityThread activityThread, TestActivity activity) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
index f061f8bc178a..e35e4ac8881c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
@@ -406,7 +406,9 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
private boolean shouldDispatchToLauncher(int backType) {
return backType == BackNavigationInfo.TYPE_RETURN_TO_HOME
&& mBackToLauncherCallback != null
- && mEnableAnimations.get();
+ && mEnableAnimations.get()
+ && mBackNavigationInfo != null
+ && mBackNavigationInfo.getDepartingAnimationTarget() != null;
}
private static void dispatchOnBackStarted(IOnBackInvokedCallback callback) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java
index 5ebe384d84b7..8bc16bcc9d9d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java
@@ -206,12 +206,12 @@ public class DividerView extends FrameLayout implements View.OnTouchListener {
mSplitLayout = layout;
mSplitWindowManager = splitWindowManager;
mViewHost = viewHost;
- mDividerBounds.set(layout.getDividerBounds());
+ layout.getDividerBounds(mDividerBounds);
onInsetsChanged(insetsState, false /* animate */);
}
void onInsetsChanged(InsetsState insetsState, boolean animate) {
- mTempRect.set(mSplitLayout.getDividerBounds());
+ mSplitLayout.getDividerBounds(mTempRect);
final InsetsSource taskBarInsetsSource =
insetsState.getSource(InsetsState.ITYPE_EXTRA_NAVIGATION_BAR);
// Only insets the divider bar with task bar when it's expanded so that the rounded corners
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitDecorManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitDecorManager.java
index 484294ab295b..6fb021ea5e2f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitDecorManager.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitDecorManager.java
@@ -56,6 +56,7 @@ import com.android.wm.shell.common.SurfaceUtils;
public class SplitDecorManager extends WindowlessWindowManager {
private static final String TAG = SplitDecorManager.class.getSimpleName();
private static final String RESIZING_BACKGROUND_SURFACE_NAME = "ResizingBackground";
+ private static final String GAP_BACKGROUND_SURFACE_NAME = "GapBackground";
private static final long FADE_DURATION = 133;
private final IconProvider mIconProvider;
@@ -67,6 +68,7 @@ public class SplitDecorManager extends WindowlessWindowManager {
private SurfaceControl mHostLeash;
private SurfaceControl mIconLeash;
private SurfaceControl mBackgroundLeash;
+ private SurfaceControl mGapBackgroundLeash;
private boolean mShown;
private boolean mIsResizing;
@@ -141,6 +143,10 @@ public class SplitDecorManager extends WindowlessWindowManager {
t.remove(mBackgroundLeash);
mBackgroundLeash = null;
}
+ if (mGapBackgroundLeash != null) {
+ t.remove(mGapBackgroundLeash);
+ mGapBackgroundLeash = null;
+ }
mHostLeash = null;
mIcon = null;
mResizingIconView = null;
@@ -150,7 +156,7 @@ public class SplitDecorManager extends WindowlessWindowManager {
/** Showing resizing hint. */
public void onResizing(ActivityManager.RunningTaskInfo resizingTask, Rect newBounds,
- SurfaceControl.Transaction t) {
+ Rect sideBounds, SurfaceControl.Transaction t) {
if (mResizingIconView == null) {
return;
}
@@ -176,6 +182,19 @@ public class SplitDecorManager extends WindowlessWindowManager {
.setLayer(mBackgroundLeash, Integer.MAX_VALUE - 1);
}
+ if (mGapBackgroundLeash == null) {
+ final boolean isLandscape = newBounds.height() == sideBounds.height();
+ final int left = isLandscape ? mBounds.width() : 0;
+ final int top = isLandscape ? 0 : mBounds.height();
+ mGapBackgroundLeash = SurfaceUtils.makeColorLayer(mHostLeash,
+ GAP_BACKGROUND_SURFACE_NAME, mSurfaceSession);
+ // Fill up another side bounds area.
+ t.setColor(mGapBackgroundLeash, getResizingBackgroundColor(resizingTask))
+ .setLayer(mGapBackgroundLeash, Integer.MAX_VALUE - 2)
+ .setPosition(mGapBackgroundLeash, left, top)
+ .setWindowCrop(mGapBackgroundLeash, sideBounds.width(), sideBounds.height());
+ }
+
if (mIcon == null && resizingTask.topActivityInfo != null) {
mIcon = mIconProvider.getIcon(resizingTask.topActivityInfo);
mResizingIconView.setImageDrawable(mIcon);
@@ -225,6 +244,7 @@ public class SplitDecorManager extends WindowlessWindowManager {
}
if (mShown) {
startFadeAnimation(false /* show */, true /* isResized */);
+ mShown = false;
} else {
// Decor surface is hidden so release it directly.
releaseDecor(t);
@@ -249,7 +269,9 @@ public class SplitDecorManager extends WindowlessWindowManager {
@Override
public void onAnimationStart(@NonNull Animator animation) {
if (show) {
- animT.show(mBackgroundLeash).show(mIconLeash).apply();
+ animT.show(mBackgroundLeash).show(mIconLeash).show(mGapBackgroundLeash).apply();
+ } else {
+ animT.hide(mGapBackgroundLeash).apply();
}
}
@@ -280,6 +302,11 @@ public class SplitDecorManager extends WindowlessWindowManager {
mBackgroundLeash = null;
}
+ if (mGapBackgroundLeash != null) {
+ t.remove(mGapBackgroundLeash);
+ mGapBackgroundLeash = null;
+ }
+
if (mIcon != null) {
mResizingIconView.setVisibility(View.GONE);
mResizingIconView.setImageDrawable(null);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
index c962de67a93b..5801d43aaefd 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
@@ -200,6 +200,44 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange
return outBounds;
}
+ /** Gets bounds of the primary split with screen based coordinate on the param Rect. */
+ public void getBounds1(Rect rect) {
+ rect.set(mBounds1);
+ }
+
+ /** Gets bounds of the primary split with parent based coordinate on the param Rect. */
+ public void getRefBounds1(Rect rect) {
+ getBounds1(rect);
+ rect.offset(-mRootBounds.left, -mRootBounds.top);
+ }
+
+ /** Gets bounds of the secondary split with screen based coordinate on the param Rect. */
+ public void getBounds2(Rect rect) {
+ rect.set(mBounds2);
+ }
+
+ /** Gets bounds of the secondary split with parent based coordinate on the param Rect. */
+ public void getRefBounds2(Rect rect) {
+ getBounds2(rect);
+ rect.offset(-mRootBounds.left, -mRootBounds.top);
+ }
+
+ /** Gets root bounds of the whole split layout on the param Rect. */
+ public void getRootBounds(Rect rect) {
+ rect.set(mRootBounds);
+ }
+
+ /** Gets bounds of divider window with screen based coordinate on the param Rect. */
+ public void getDividerBounds(Rect rect) {
+ rect.set(mDividerBounds);
+ }
+
+ /** Gets bounds of divider window with parent based coordinate on the param Rect. */
+ public void getRefDividerBounds(Rect rect) {
+ getDividerBounds(rect);
+ rect.offset(-mRootBounds.left, -mRootBounds.top);
+ }
+
/** Returns leash of the current divider bar. */
@Nullable
public SurfaceControl getDividerLeash() {
@@ -560,8 +598,8 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange
t.setPosition(leash, distX, distY);
t.setWindowCrop(leash, width, height);
} else {
- final int offsetX = width - start.width();
- final int offsetY = height - start.height();
+ final int offsetX = width - tempStart.width();
+ final int offsetY = height - tempStart.height();
t.setPosition(leash, distX + offsetX, distY + offsetY);
mTempRect.set(0, 0, width, height);
mTempRect.offsetTo(-offsetX, -offsetY);
@@ -610,15 +648,15 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange
boolean applyResizingOffset) {
final SurfaceControl dividerLeash = getDividerLeash();
if (dividerLeash != null) {
- mTempRect.set(getRefDividerBounds());
+ getRefDividerBounds(mTempRect);
t.setPosition(dividerLeash, mTempRect.left, mTempRect.top);
// Resets layer of divider bar to make sure it is always on top.
t.setLayer(dividerLeash, Integer.MAX_VALUE);
}
- mTempRect.set(getRefBounds1());
+ getRefBounds1(mTempRect);
t.setPosition(leash1, mTempRect.left, mTempRect.top)
.setWindowCrop(leash1, mTempRect.width(), mTempRect.height());
- mTempRect.set(getRefBounds2());
+ getRefBounds2(mTempRect);
t.setPosition(leash2, mTempRect.left, mTempRect.top)
.setWindowCrop(leash2, mTempRect.width(), mTempRect.height());
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java
index 6373728344a4..435d8eaa563e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java
@@ -45,12 +45,10 @@ import android.app.WindowConfiguration;
import android.content.ActivityNotFoundException;
import android.content.ClipData;
import android.content.ClipDescription;
-import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.LauncherApps;
-import android.content.pm.ResolveInfo;
import android.graphics.Insets;
import android.graphics.Rect;
import android.os.Bundle;
@@ -64,19 +62,15 @@ import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import com.android.internal.logging.InstanceId;
-import com.android.internal.protolog.common.ProtoLog;
import com.android.wm.shell.R;
import com.android.wm.shell.common.DisplayLayout;
-import com.android.wm.shell.common.split.SplitLayout;
import com.android.wm.shell.common.split.SplitScreenConstants.SplitPosition;
-import com.android.wm.shell.protolog.ShellProtoLogGroup;
import com.android.wm.shell.splitscreen.SplitScreenController;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.List;
-import java.util.Objects;
/**
* The policy for handling drag and drop operations to shell.
@@ -269,47 +263,11 @@ public class DragAndDropPolicy {
mStarter.startShortcut(packageName, id, position, opts, user);
} else {
final PendingIntent launchIntent = intent.getParcelableExtra(EXTRA_PENDING_INTENT);
- mStarter.startIntent(launchIntent, getStartIntentFillInIntent(launchIntent, position),
- position, opts);
+ mStarter.startIntent(launchIntent, null /* fillIntent */, position, opts);
}
}
/**
- * Returns the fill-in intent to use when starting an app from a drop.
- */
- @VisibleForTesting
- Intent getStartIntentFillInIntent(PendingIntent launchIntent, @SplitPosition int position) {
- // Get the drag app
- final List<ResolveInfo> infos = launchIntent.queryIntentComponents(0 /* flags */);
- final ComponentName dragIntentActivity = !infos.isEmpty()
- ? infos.get(0).activityInfo.getComponentName()
- : null;
-
- // Get the current app (either fullscreen or the remaining app post-drop if in splitscreen)
- final boolean inSplitScreen = mSplitScreen != null
- && mSplitScreen.isSplitScreenVisible();
- final ComponentName currentActivity;
- if (!inSplitScreen) {
- currentActivity = mSession.runningTaskInfo != null
- ? mSession.runningTaskInfo.baseIntent.getComponent()
- : null;
- } else {
- final ActivityManager.RunningTaskInfo nonReplacedTaskInfo =
- mSplitScreen.getTaskInfo(SplitLayout.reversePosition(position));
- currentActivity = nonReplacedTaskInfo.baseIntent.getComponent();
- }
-
- if (Objects.equals(currentActivity, dragIntentActivity)) {
- // Only apply MULTIPLE_TASK if we are dragging the same activity
- final Intent fillInIntent = new Intent();
- fillInIntent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
- ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP, "Adding MULTIPLE_TASK");
- return fillInIntent;
- }
- return null;
- }
-
- /**
* Per-drag session data.
*/
private static class DragSession {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java
index 4ce45e142c64..c6f7974e43bc 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java
@@ -200,7 +200,7 @@ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Lis
void notifyPipAnimating(boolean animating) {
mPipMenuView.setEduTextActive(!animating);
if (!animating) {
- mPipMenuView.onPipTransitionFinished();
+ mPipMenuView.onPipTransitionFinished(mTvPipBoundsState.isTvPipExpanded());
}
}
@@ -267,7 +267,6 @@ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Lis
void updateExpansionState() {
mPipMenuView.setExpandedModeEnabled(mTvPipBoundsState.isTvExpandedPipSupported()
&& mTvPipBoundsState.getDesiredTvExpandedAspectRatio() != 0);
- mPipMenuView.setIsExpanded(mTvPipBoundsState.isTvPipExpanded());
}
private Rect calculateMenuSurfaceBounds(Rect pipBounds) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuView.java
index 1c30755583b1..57d3a44ed2af 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuView.java
@@ -266,7 +266,7 @@ public class TvPipMenuView extends FrameLayout implements View.OnClickListener {
}
}
- void onPipTransitionFinished() {
+ void onPipTransitionFinished(boolean isTvPipExpanded) {
ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
"%s: onPipTransitionFinished()", TAG);
@@ -277,6 +277,8 @@ public class TvPipMenuView extends FrameLayout implements View.OnClickListener {
.setInterpolator(TvPipInterpolators.ENTER)
.start();
+ setIsExpanded(isTvPipExpanded);
+
// Update buttons.
if (mSwitchingOrientation) {
mActionButtonsContainer.animate()
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
index ee493668994d..046b1a2541b4 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
@@ -18,6 +18,9 @@ package com.android.wm.shell.splitscreen;
import static android.app.ActivityManager.START_SUCCESS;
import static android.app.ActivityManager.START_TASK_TO_FRONT;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
import static android.content.Intent.FLAG_ACTIVITY_NO_USER_ACTION;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.RemoteAnimationTarget.MODE_OPENING;
@@ -58,7 +61,9 @@ import androidx.annotation.IntDef;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.InstanceId;
+import com.android.internal.protolog.common.ProtoLog;
import com.android.launcher3.icons.IconProvider;
import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
import com.android.wm.shell.ShellTaskOrganizer;
@@ -74,6 +79,7 @@ import com.android.wm.shell.common.annotations.ExternalThread;
import com.android.wm.shell.common.split.SplitLayout;
import com.android.wm.shell.common.split.SplitScreenConstants.SplitPosition;
import com.android.wm.shell.draganddrop.DragAndDropPolicy;
+import com.android.wm.shell.protolog.ShellProtoLogGroup;
import com.android.wm.shell.recents.RecentTasksController;
import com.android.wm.shell.splitscreen.SplitScreen.StageType;
import com.android.wm.shell.transition.LegacyTransitions;
@@ -95,7 +101,7 @@ import java.util.concurrent.Executor;
*/
// TODO(b/198577848): Implement split screen flicker test to consolidate CUJ of split screen.
public class SplitScreenController implements DragAndDropPolicy.Starter,
- RemoteCallable<SplitScreenController> {
+ RemoteCallable<SplitScreenController>, ShellTaskOrganizer.FocusListener {
private static final String TAG = SplitScreenController.class.getSimpleName();
static final int EXIT_REASON_UNKNOWN = 0;
@@ -143,6 +149,8 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
// outside the bounds of the roots by being reparented into a higher level fullscreen container
private SurfaceControl mSplitTasksContainerLayer;
+ private ActivityManager.RunningTaskInfo mFocusingTaskInfo;
+
public SplitScreenController(ShellTaskOrganizer shellTaskOrganizer,
SyncTransactionQueue syncQueue, Context context,
RootTaskDisplayAreaOrganizer rootTDAOrganizer,
@@ -164,6 +172,7 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
mLogger = new SplitscreenEventLogger();
mIconProvider = iconProvider;
mRecentTasksOptional = recentTasks;
+ mTaskOrganizer.addFocusListener(this);
}
public SplitScreen asSplitScreen() {
@@ -180,6 +189,11 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
return mMainExecutor;
}
+ @Override
+ public void onFocusTaskChanged(ActivityManager.RunningTaskInfo taskInfo) {
+ mFocusingTaskInfo = taskInfo;
+ }
+
public void onOrganizerRegistered() {
if (mStageCoordinator == null) {
// TODO: Multi-display
@@ -341,14 +355,21 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
options = mStageCoordinator.resolveStartStage(STAGE_TYPE_UNDEFINED, position, options,
null /* wct */);
- // Flag this as a no-user-action launch to prevent sending user leaving event to the
- // current top activity since it's going to be put into another side of the split. This
- // prevents the current top activity from going into pip mode due to user leaving event.
if (fillInIntent == null) {
fillInIntent = new Intent();
}
+ // Flag this as a no-user-action launch to prevent sending user leaving event to the
+ // current top activity since it's going to be put into another side of the split. This
+ // prevents the current top activity from going into pip mode due to user leaving event.
fillInIntent.addFlags(FLAG_ACTIVITY_NO_USER_ACTION);
+ // Flag with MULTIPLE_TASK if this is launching the same activity into both sides of the
+ // split.
+ if (isLaunchingAdjacently(intent.getIntent(), position)) {
+ fillInIntent.addFlags(FLAG_ACTIVITY_MULTIPLE_TASK);
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN, "Adding MULTIPLE_TASK");
+ }
+
intent.send(mContext, 0, fillInIntent, null /* onFinished */, null /* handler */,
null /* requiredPermission */, options);
} catch (PendingIntent.CanceledException e) {
@@ -358,6 +379,8 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
private void startIntentLegacy(PendingIntent intent, @Nullable Intent fillInIntent,
@SplitPosition int position, @Nullable Bundle options) {
+ boolean startSameActivityAdjacently = isLaunchingAdjacently(intent.getIntent(), position);
+
final WindowContainerTransaction evictWct = new WindowContainerTransaction();
mStageCoordinator.prepareEvictChildTasks(position, evictWct);
@@ -368,14 +391,7 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
IRemoteAnimationFinishedCallback finishedCallback,
SurfaceControl.Transaction t) {
if (apps == null || apps.length == 0) {
- final ActivityManager.RunningTaskInfo pairedTaskInfo =
- getTaskInfo(SplitLayout.reversePosition(position));
- final ComponentName pairedActivity = pairedTaskInfo != null
- ? pairedTaskInfo.baseIntent.getComponent() : null;
- final ComponentName intentActivity = intent.getIntent() != null
- ? intent.getIntent().getComponent() : null;
-
- if (Objects.equals(pairedActivity, intentActivity)) {
+ if (startSameActivityAdjacently) {
// Switch split position if dragging the same activity to another side.
setSideStagePosition(SplitLayout.reversePosition(
mStageCoordinator.getSideStagePosition()));
@@ -417,11 +433,47 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
fillInIntent = new Intent();
}
fillInIntent.addFlags(FLAG_ACTIVITY_NO_USER_ACTION);
+ if (startSameActivityAdjacently) {
+ fillInIntent.addFlags(FLAG_ACTIVITY_MULTIPLE_TASK);
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN, "Adding MULTIPLE_TASK");
+ }
wct.sendPendingIntent(intent, fillInIntent, options);
mSyncQueue.queue(transition, WindowManager.TRANSIT_OPEN, wct);
}
+ /** Returns {@code true} if it's launching the same component on both sides of the split. */
+ @VisibleForTesting
+ boolean isLaunchingAdjacently(@Nullable Intent startIntent,
+ @SplitPosition int position) {
+ if (startIntent == null) {
+ return false;
+ }
+
+ final ComponentName launchingActivity = startIntent.getComponent();
+ if (launchingActivity == null) {
+ return false;
+ }
+
+ if (isSplitScreenVisible()) {
+ final ActivityManager.RunningTaskInfo pairedTaskInfo =
+ getTaskInfo(SplitLayout.reversePosition(position));
+ final ComponentName pairedActivity = pairedTaskInfo != null
+ ? pairedTaskInfo.baseIntent.getComponent() : null;
+ return Objects.equals(launchingActivity, pairedActivity);
+ }
+
+ if (mFocusingTaskInfo != null
+ // TODO (b/238032411): have an API to determine whether an activity is valid for
+ // split screen or not.
+ && mFocusingTaskInfo.getWindowingMode() == WINDOWING_MODE_FULLSCREEN
+ && mFocusingTaskInfo.getActivityType() == ACTIVITY_TYPE_STANDARD) {
+ return Objects.equals(mFocusingTaskInfo.baseIntent.getComponent(), launchingActivity);
+ }
+
+ return false;
+ }
+
RemoteAnimationTarget[] onGoingToRecentsLegacy(RemoteAnimationTarget[] apps) {
if (isSplitScreenVisible()) {
// Evict child tasks except the top visible one under split root to ensure it could be
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
index 59b0afe22acb..55e7dacc4087 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
@@ -171,6 +171,9 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
private final ShellExecutor mMainExecutor;
private final Optional<RecentTasksController> mRecentTasks;
+ private final Rect mTempRect1 = new Rect();
+ private final Rect mTempRect2 = new Rect();
+
/**
* A single-top root task which the split divider attached to.
*/
@@ -749,7 +752,6 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
wct.reorder(mRootTaskInfo.token, false /* onTop */);
mTaskOrganizer.applyTransaction(wct);
mSyncQueue.runInSync(t -> {
- setResizingSplits(false /* resizing */);
t.setWindowCrop(mMainStage.mRootLeash, null)
.setWindowCrop(mSideStage.mRootLeash, null);
setDividerVisibility(false, t);
@@ -1148,12 +1150,11 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
mDividerFadeInAnimator.cancel();
return;
}
+ mSplitLayout.getRefDividerBounds(mTempRect1);
transaction.show(dividerLeash);
transaction.setAlpha(dividerLeash, 0);
transaction.setLayer(dividerLeash, Integer.MAX_VALUE);
- transaction.setPosition(dividerLeash,
- mSplitLayout.getRefDividerBounds().left,
- mSplitLayout.getRefDividerBounds().top);
+ transaction.setPosition(dividerLeash, mTempRect1.left, mTempRect1.top);
transaction.apply();
}
@@ -1212,7 +1213,6 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
return;
}
- setResizingSplits(false /* resizing */);
final int dismissTop = mainStageToTop ? STAGE_TYPE_MAIN : STAGE_TYPE_SIDE;
final WindowContainerTransaction wct = new WindowContainerTransaction();
prepareExitSplitScreen(dismissTop, wct);
@@ -1243,10 +1243,11 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
public void onLayoutSizeChanging(SplitLayout layout) {
final SurfaceControl.Transaction t = mTransactionPool.acquire();
t.setFrameTimelineVsync(Choreographer.getInstance().getVsyncId());
- setResizingSplits(true /* resizing */);
updateSurfaceBounds(layout, t, true /* applyResizingOffset */);
- mMainStage.onResizing(getMainStageBounds(), t);
- mSideStage.onResizing(getSideStageBounds(), t);
+ getMainStageBounds(mTempRect1);
+ getSideStageBounds(mTempRect2);
+ mMainStage.onResizing(mTempRect1, mTempRect2, t);
+ mSideStage.onResizing(mTempRect2, mTempRect1, t);
t.apply();
mTransactionPool.release(t);
}
@@ -1258,7 +1259,6 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
sendOnBoundsChanged();
mSyncQueue.queue(wct);
mSyncQueue.runInSync(t -> {
- setResizingSplits(false /* resizing */);
updateSurfaceBounds(layout, t, false /* applyResizingOffset */);
mMainStage.onResized(t);
mSideStage.onResized(t);
@@ -1293,16 +1293,6 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
applyResizingOffset);
}
- void setResizingSplits(boolean resizing) {
- if (resizing == mResizingSplits) return;
- try {
- ActivityTaskManager.getService().setSplitScreenResizing(resizing);
- mResizingSplits = resizing;
- } catch (RemoteException e) {
- Slog.w(TAG, "Error calling setSplitScreenResizing", e);
- }
- }
-
@Override
public int getSplitItemPosition(WindowContainerToken token) {
if (token == null) {
@@ -1353,8 +1343,6 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
private void onDisplayChange(int displayId, int fromRotation, int toRotation,
@Nullable DisplayAreaInfo newDisplayAreaInfo, WindowContainerTransaction wct) {
if (!mMainStage.isActive()) return;
- // Only do this when shell transition
- if (!ENABLE_SHELL_TRANSITIONS) return;
mDisplayLayout.rotateTo(mContext.getResources(), toRotation);
mSplitLayout.rotateTo(toRotation, mDisplayLayout.stableInsets());
@@ -1386,6 +1374,22 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
? mSplitLayout.getBounds2() : mSplitLayout.getBounds1();
}
+ private void getSideStageBounds(Rect rect) {
+ if (mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT) {
+ mSplitLayout.getBounds1(rect);
+ } else {
+ mSplitLayout.getBounds2(rect);
+ }
+ }
+
+ private void getMainStageBounds(Rect rect) {
+ if (mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT) {
+ mSplitLayout.getBounds2(rect);
+ } else {
+ mSplitLayout.getBounds1(rect);
+ }
+ }
+
/**
* Get the stage that should contain this `taskInfo`. The stage doesn't necessarily contain
* this task (yet) so this can also be used to identify which stage to put a task into.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
index 23eec96a5d8f..99e750629729 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
@@ -200,11 +200,6 @@ class StageTaskListener implements ShellTaskOrganizer.TaskListener {
@Override
@CallSuper
public void onTaskInfoChanged(ActivityManager.RunningTaskInfo taskInfo) {
- if (!taskInfo.supportsMultiWindow) {
- // Leave split screen if the task no longer supports multi window.
- mCallbacks.onNoLongerSupportMultiWindow();
- return;
- }
if (mRootTaskInfo.taskId == taskInfo.taskId) {
// Inflates split decor view only when the root task is visible.
if (mRootTaskInfo.isVisible != taskInfo.isVisible) {
@@ -217,6 +212,12 @@ class StageTaskListener implements ShellTaskOrganizer.TaskListener {
}
mRootTaskInfo = taskInfo;
} else if (taskInfo.parentTaskId == mRootTaskInfo.taskId) {
+ if (!taskInfo.supportsMultiWindow) {
+ // Leave split screen if the task no longer supports multi window.
+ mCallbacks.onNoLongerSupportMultiWindow();
+ return;
+ }
+
mChildrenTaskInfo.put(taskInfo.taskId, taskInfo);
mCallbacks.onChildTaskStatusChanged(taskInfo.taskId, true /* present */,
taskInfo.isVisible);
@@ -285,9 +286,9 @@ class StageTaskListener implements ShellTaskOrganizer.TaskListener {
}
}
- void onResizing(Rect newBounds, SurfaceControl.Transaction t) {
+ void onResizing(Rect newBounds, Rect sideBounds, SurfaceControl.Transaction t) {
if (mSplitDecorManager != null && mRootTaskInfo != null) {
- mSplitDecorManager.onResizing(mRootTaskInfo, newBounds, t);
+ mSplitDecorManager.onResizing(mRootTaskInfo, newBounds, sideBounds, t);
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java
index 572516d2f8c9..cdca051a4ee5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java
@@ -95,6 +95,7 @@ public class CaptionWindowDecoration extends WindowDecoration<WindowDecorLinearL
mDragResizeCallback = dragResizeCallback;
}
+ @Override
void relayout(ActivityManager.RunningTaskInfo taskInfo) {
final int shadowRadiusDp = taskInfo.isFocused
? DECOR_SHADOW_FOCUSED_THICKNESS_IN_DIP : DECOR_SHADOW_UNFOCUSED_THICKNESS_IN_DIP;
@@ -119,8 +120,8 @@ public class CaptionWindowDecoration extends WindowDecoration<WindowDecorLinearL
});
if (mResult.mRootView == null) {
- // This means the task is hidden. Nothing is set up in this case including the
- // decoration surface.
+ // This means something blocks the window decor from showing, e.g. the task is hidden.
+ // Nothing is set up in this case including the decoration surface.
return;
}
if (oldRootView != mResult.mRootView) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java
index 0c5022832162..c19a33abf8a4 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java
@@ -38,6 +38,8 @@ import android.window.WindowContainerTransaction;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.DisplayController;
+import java.util.function.Supplier;
+
/**
* Manages a container surface and a windowless window to show window decoration. Responsible to
* update window decoration window state and layout parameters on task info changes and so that
@@ -53,7 +55,8 @@ import com.android.wm.shell.common.DisplayController;
*
* @param <T> The type of the root view
*/
-public class WindowDecoration<T extends View & TaskFocusStateConsumer> implements AutoCloseable {
+public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer>
+ implements AutoCloseable {
private static final int[] CAPTION_INSETS_TYPES = { InsetsState.ITYPE_CAPTION_BAR };
/**
@@ -62,6 +65,20 @@ public class WindowDecoration<T extends View & TaskFocusStateConsumer> implement
final Context mContext;
final DisplayController mDisplayController;
final ShellTaskOrganizer mTaskOrganizer;
+ final Supplier<SurfaceControl.Builder> mSurfaceControlBuilderSupplier;
+ final SurfaceControlViewHostFactory mSurfaceControlViewHostFactory;
+ private final DisplayController.OnDisplaysChangedListener mOnDisplaysChangedListener =
+ new DisplayController.OnDisplaysChangedListener() {
+ @Override
+ public void onDisplayAdded(int displayId) {
+ if (mTaskInfo.displayId != displayId) {
+ return;
+ }
+
+ mDisplayController.removeDisplayWindowListener(this);
+ relayout(mTaskInfo);
+ }
+ };
RunningTaskInfo mTaskInfo;
final SurfaceControl mTaskSurface;
@@ -71,7 +88,7 @@ public class WindowDecoration<T extends View & TaskFocusStateConsumer> implement
SurfaceControl mDecorationContainerSurface;
SurfaceControl mTaskBackgroundSurface;
- private CaptionWindowManager mCaptionWindowManager;
+ private final CaptionWindowManager mCaptionWindowManager;
private SurfaceControlViewHost mViewHost;
private final Rect mCaptionInsetsRect = new Rect();
@@ -84,11 +101,25 @@ public class WindowDecoration<T extends View & TaskFocusStateConsumer> implement
ShellTaskOrganizer taskOrganizer,
RunningTaskInfo taskInfo,
SurfaceControl taskSurface) {
+ this(context, displayController, taskOrganizer, taskInfo, taskSurface,
+ SurfaceControl.Builder::new, new SurfaceControlViewHostFactory() {});
+ }
+
+ WindowDecoration(
+ Context context,
+ DisplayController displayController,
+ ShellTaskOrganizer taskOrganizer,
+ RunningTaskInfo taskInfo,
+ SurfaceControl taskSurface,
+ Supplier<SurfaceControl.Builder> surfaceControlBuilderSupplier,
+ SurfaceControlViewHostFactory surfaceControlViewHostFactory) {
mContext = context;
mDisplayController = displayController;
mTaskOrganizer = taskOrganizer;
mTaskInfo = taskInfo;
mTaskSurface = taskSurface;
+ mSurfaceControlBuilderSupplier = surfaceControlBuilderSupplier;
+ mSurfaceControlViewHostFactory = surfaceControlViewHostFactory;
mDisplay = mDisplayController.getDisplay(mTaskInfo.displayId);
mDecorWindowContext = mContext.createConfigurationContext(mTaskInfo.getConfiguration());
@@ -99,6 +130,15 @@ public class WindowDecoration<T extends View & TaskFocusStateConsumer> implement
new CaptionWindowManager(mTaskInfo.getConfiguration(), mTaskSurface);
}
+ /**
+ * Used by {@link WindowDecoration} to trigger a new relayout because the requirements for a
+ * relayout weren't satisfied are satisfied now.
+ *
+ * @param taskInfo The previous {@link RunningTaskInfo} passed into {@link #relayout} or the
+ * constructor.
+ */
+ abstract void relayout(RunningTaskInfo taskInfo);
+
void relayout(RunningTaskInfo taskInfo, int layoutResId, T rootView, float captionHeightDp,
Rect outsetsDp, float shadowRadiusDp, SurfaceControl.Transaction t,
WindowContainerTransaction wct, RelayoutResult<T> outResult) {
@@ -110,7 +150,7 @@ public class WindowDecoration<T extends View & TaskFocusStateConsumer> implement
}
if (!mTaskInfo.isVisible) {
- close();
+ releaseViews();
t.hide(mTaskSurface);
return;
}
@@ -123,10 +163,14 @@ public class WindowDecoration<T extends View & TaskFocusStateConsumer> implement
rootView = null; // Clear it just in case we use it accidentally
final Configuration taskConfig = mTaskInfo.getConfiguration();
if (oldTaskConfig.densityDpi != taskConfig.densityDpi
+ || mDisplay == null
|| mDisplay.getDisplayId() != mTaskInfo.displayId) {
- close();
+ releaseViews();
- mDisplay = mDisplayController.getDisplay(mTaskInfo.displayId);
+ if (!obtainDisplayOrRegisterListener()) {
+ outResult.mRootView = null;
+ return;
+ }
mDecorWindowContext = mContext.createConfigurationContext(taskConfig);
if (layoutResId != 0) {
outResult.mRootView =
@@ -141,7 +185,7 @@ public class WindowDecoration<T extends View & TaskFocusStateConsumer> implement
// DecorationContainerSurface
if (mDecorationContainerSurface == null) {
- final SurfaceControl.Builder builder = new SurfaceControl.Builder();
+ final SurfaceControl.Builder builder = mSurfaceControlBuilderSupplier.get();
mDecorationContainerSurface = builder
.setName("Decor container of Task=" + mTaskInfo.taskId)
.setContainerLayer()
@@ -168,7 +212,7 @@ public class WindowDecoration<T extends View & TaskFocusStateConsumer> implement
// TaskBackgroundSurface
if (mTaskBackgroundSurface == null) {
- final SurfaceControl.Builder builder = new SurfaceControl.Builder();
+ final SurfaceControl.Builder builder = mSurfaceControlBuilderSupplier.get();
mTaskBackgroundSurface = builder
.setName("Background of Task=" + mTaskInfo.taskId)
.setEffectLayer()
@@ -195,7 +239,7 @@ public class WindowDecoration<T extends View & TaskFocusStateConsumer> implement
lp.setTitle("Caption of Task=" + mTaskInfo.taskId);
lp.setTrustedOverlay();
if (mViewHost == null) {
- mViewHost = new SurfaceControlViewHost(mDecorWindowContext, mDisplay,
+ mViewHost = mSurfaceControlViewHostFactory.create(mDecorWindowContext, mDisplay,
mCaptionWindowManager, true);
mViewHost.setView(outResult.mRootView, lp);
} else {
@@ -225,8 +269,22 @@ public class WindowDecoration<T extends View & TaskFocusStateConsumer> implement
.show(mTaskSurface);
}
- @Override
- public void close() {
+ /**
+ * Obtains the {@link Display} instance for the display ID in {@link #mTaskInfo} if it exists or
+ * registers {@link #mOnDisplaysChangedListener} if it doesn't.
+ *
+ * @return {@code true} if the {@link Display} instance exists; or {@code false} otherwise
+ */
+ private boolean obtainDisplayOrRegisterListener() {
+ mDisplay = mDisplayController.getDisplay(mTaskInfo.displayId);
+ if (mDisplay == null) {
+ mDisplayController.addDisplayWindowListener(mOnDisplaysChangedListener);
+ return false;
+ }
+ return true;
+ }
+
+ private void releaseViews() {
if (mViewHost != null) {
mViewHost.release();
mViewHost = null;
@@ -243,6 +301,12 @@ public class WindowDecoration<T extends View & TaskFocusStateConsumer> implement
}
}
+ @Override
+ public void close() {
+ mDisplayController.removeDisplayWindowListener(mOnDisplaysChangedListener);
+ releaseViews();
+ }
+
static class RelayoutResult<T extends View & TaskFocusStateConsumer> {
int mWidth;
int mHeight;
@@ -267,4 +331,11 @@ public class WindowDecoration<T extends View & TaskFocusStateConsumer> implement
super.setConfiguration(configuration);
}
}
+
+ interface SurfaceControlViewHostFactory {
+ default SurfaceControlViewHost create(
+ Context c, Display d, WindowlessWindowManager wmm, boolean useSfChoreographer) {
+ return new SurfaceControlViewHost(c, d, wmm, useSfChoreographer);
+ }
+ }
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/PipAppHelper.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/PipAppHelper.kt
index 216445fe9356..48f9a7e586d8 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/PipAppHelper.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/PipAppHelper.kt
@@ -116,6 +116,10 @@ class PipAppHelper(instrumentation: Instrumentation) : BaseAppHelper(
clickObject(ENTER_PIP_ON_USER_LEAVE_HINT)
}
+ fun enableAutoEnterForPipActivity() {
+ clickObject(ENTER_PIP_AUTOENTER)
+ }
+
fun clickStartMediaSessionButton() {
clickObject(MEDIA_SESSION_START_RADIO_BUTTON_ID)
}
@@ -214,5 +218,6 @@ class PipAppHelper(instrumentation: Instrumentation) : BaseAppHelper(
private const val WITH_CUSTOM_ACTIONS_BUTTON_ID = "with_custom_actions"
private const val MEDIA_SESSION_START_RADIO_BUTTON_ID = "media_session_start"
private const val ENTER_PIP_ON_USER_LEAVE_HINT = "enter_pip_on_leave_manual"
+ private const val ENTER_PIP_AUTOENTER = "enter_pip_on_leave_autoenter"
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/AutoEnterPipOnGoToHomeTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/AutoEnterPipOnGoToHomeTest.kt
new file mode 100644
index 000000000000..ce624f2b5bbe
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/AutoEnterPipOnGoToHomeTest.kt
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.pip
+
+import android.platform.test.annotations.FlakyTest
+import androidx.test.filters.RequiresDevice
+import com.android.launcher3.tapl.LauncherInstrumentation
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.annotation.Group3
+import com.android.server.wm.flicker.dsl.FlickerBuilder
+import org.junit.Assume
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test entering pip from an app via auto-enter property when navigating to home.
+ *
+ * To run this test: `atest WMShellFlickerTests:AutoEnterPipOnGoToHomeTest`
+ *
+ * Actions:
+ * Launch an app in full screen
+ * Select "Auto-enter PiP" radio button
+ * Press Home button or swipe up to go Home and put [pipApp] in pip mode
+ *
+ * Notes:
+ * 1. All assertions are inherited from [EnterPipTest]
+ * 2. Part of the test setup occurs automatically via
+ * [com.android.server.wm.flicker.TransitionRunnerWithRules],
+ * including configuring navigation mode, initial orientation and ensuring no
+ * apps are running before setup
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@FlakyTest(bugId = 238367575)
+@Group3
+class AutoEnterPipOnGoToHomeTest(testSpec: FlickerTestParameter) : EnterPipTest(testSpec) {
+ protected val taplInstrumentation = LauncherInstrumentation()
+ /**
+ * Defines the transition used to run the test
+ */
+ override val transition: FlickerBuilder.() -> Unit
+ get() = {
+ setupAndTeardown(this)
+ setup {
+ eachRun {
+ pipApp.launchViaIntent(wmHelper)
+ pipApp.enableAutoEnterForPipActivity()
+ }
+ }
+ teardown {
+ eachRun {
+ // close gracefully so that onActivityUnpinned() can be called before force exit
+ pipApp.closePipWindow(wmHelper)
+ pipApp.exit(wmHelper)
+ }
+ }
+ transitions {
+ taplInstrumentation.goHome()
+ }
+ }
+
+ override fun pipLayerReduces() {
+ val layerName = pipApp.component.toLayerName()
+ testSpec.assertLayers {
+ val pipLayerList = this.layers { it.name.contains(layerName) && it.isVisible }
+ pipLayerList.zipWithNext { previous, current ->
+ current.visibleRegion.notBiggerThan(previous.visibleRegion.region)
+ }
+ }
+ }
+
+ /**
+ * Checks that [pipApp] window is animated towards default position in right bottom corner
+ */
+ @Test
+ fun pipLayerMovesTowardsRightBottomCorner() {
+ // in gestural nav the swipe makes PiP first go upwards
+ Assume.assumeFalse(testSpec.isGesturalNavigation)
+ val layerName = pipApp.component.toLayerName()
+ testSpec.assertLayers {
+ val pipLayerList = this.layers { it.name.contains(layerName) && it.isVisible }
+ // Pip animates towards the right bottom corner, but because it is being resized at the
+ // same time, it is possible it shrinks first quickly below the default position and get
+ // moved up after that in just few last frames
+ pipLayerList.zipWithNext { previous, current ->
+ current.visibleRegion.isToTheRightBottom(previous.visibleRegion.region, 3)
+ }
+ }
+ }
+
+ override fun focusChanges() {
+ // in gestural nav the focus goes to different activity on swipe up
+ Assume.assumeFalse(testSpec.isGesturalNavigation)
+ super.focusChanges()
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTest.kt
index cb84fc441f75..9b12e2a04bf3 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTest.kt
@@ -35,7 +35,7 @@ import org.junit.runners.Parameterized
* Actions:
* Launch an app in full screen
* Select "Via code behind" radio button
- * Press Home button to put [pipApp] in pip mode
+ * Press Home button or swipe up to go Home and put [pipApp] in pip mode
*
* Notes:
* 1. All assertions are inherited from [EnterPipTest]
diff --git a/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/res/layout/activity_pip.xml b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/res/layout/activity_pip.xml
index e9e7bb61660d..229098313afa 100644
--- a/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/res/layout/activity_pip.xml
+++ b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/res/layout/activity_pip.xml
@@ -64,6 +64,13 @@
android:layout_height="wrap_content"
android:text="Via code behind"
android:onClick="onAutoPipSelected"/>
+
+ <RadioButton
+ android:id="@+id/enter_pip_on_leave_autoenter"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Auto-enter PiP"
+ android:onClick="onAutoPipSelected"/>
</RadioGroup>
<RadioGroup
diff --git a/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/src/com/android/wm/shell/flicker/testapp/PipActivity.java b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/src/com/android/wm/shell/flicker/testapp/PipActivity.java
index a39aa4dc7bde..615b1730579c 100644
--- a/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/src/com/android/wm/shell/flicker/testapp/PipActivity.java
+++ b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/src/com/android/wm/shell/flicker/testapp/PipActivity.java
@@ -236,6 +236,10 @@ public class PipActivity extends Activity {
mPipParamsBuilder.setAutoEnterEnabled(false);
setPictureInPictureParams(mPipParamsBuilder.build());
break;
+ case R.id.enter_pip_on_leave_autoenter:
+ mPipParamsBuilder.setAutoEnterEnabled(true);
+ setPictureInPictureParams(mPipParamsBuilder.build());
+ break;
}
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/MockSurfaceControlHelper.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/MockSurfaceControlHelper.java
new file mode 100644
index 000000000000..49228720b81d
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/MockSurfaceControlHelper.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell;
+
+import static org.mockito.Mockito.RETURNS_SELF;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+
+import android.view.SurfaceControl;
+
+/**
+ * Helper class to provide mocks for {@link SurfaceControl.Builder} and
+ * {@link SurfaceControl.Transaction} with method chaining support.
+ */
+public class MockSurfaceControlHelper {
+ private MockSurfaceControlHelper() {}
+
+ /**
+ * Creates a mock {@link SurfaceControl.Builder} that supports method chaining and return the
+ * given {@link SurfaceControl} when calling {@link SurfaceControl.Builder#build()}.
+ *
+ * @param mockSurfaceControl the first {@link SurfaceControl} to return
+ * @param mockSurfaceControls following {@link SurfaceControl} to return
+ * @return the mock of {@link SurfaceControl.Builder}
+ */
+ public static SurfaceControl.Builder createMockSurfaceControlBuilder(
+ SurfaceControl mockSurfaceControl, SurfaceControl... mockSurfaceControls) {
+ final SurfaceControl.Builder mockBuilder = mock(SurfaceControl.Builder.class, RETURNS_SELF);
+ doReturn(mockSurfaceControl, (Object[]) mockSurfaceControls)
+ .when(mockBuilder)
+ .build();
+ return mockBuilder;
+ }
+
+ /**
+ * Creates a mock {@link SurfaceControl.Transaction} that supports method chaining.
+ * @return the mock of {@link SurfaceControl.Transaction}
+ */
+ public static SurfaceControl.Transaction createMockSurfaceControlTransaction() {
+ return mock(SurfaceControl.Transaction.class, RETURNS_SELF);
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/TestRunningTaskInfoBuilder.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/TestRunningTaskInfoBuilder.java
index 51eec27cfc0e..c0720cf04028 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/TestRunningTaskInfoBuilder.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/TestRunningTaskInfoBuilder.java
@@ -25,8 +25,10 @@ import static org.mockito.Mockito.mock;
import android.app.ActivityManager;
import android.app.WindowConfiguration;
+import android.graphics.Point;
import android.graphics.Rect;
import android.os.IBinder;
+import android.view.Display;
import android.window.IWindowContainerToken;
import android.window.WindowContainerToken;
@@ -38,6 +40,10 @@ public final class TestRunningTaskInfoBuilder {
private int mParentTaskId = INVALID_TASK_ID;
private @WindowConfiguration.ActivityType int mActivityType = ACTIVITY_TYPE_STANDARD;
private @WindowConfiguration.WindowingMode int mWindowingMode = WINDOWING_MODE_UNDEFINED;
+ private int mDisplayId = Display.DEFAULT_DISPLAY;
+ private ActivityManager.TaskDescription.Builder mTaskDescriptionBuilder = null;
+ private final Point mPositionInParent = new Point();
+ private boolean mIsVisible = false;
public static WindowContainerToken createMockWCToken() {
final IWindowContainerToken itoken = mock(IWindowContainerToken.class);
@@ -68,17 +74,42 @@ public final class TestRunningTaskInfoBuilder {
return this;
}
+ public TestRunningTaskInfoBuilder setDisplayId(int displayId) {
+ mDisplayId = displayId;
+ return this;
+ }
+
+ public TestRunningTaskInfoBuilder setTaskDescriptionBuilder(
+ ActivityManager.TaskDescription.Builder builder) {
+ mTaskDescriptionBuilder = builder;
+ return this;
+ }
+
+ public TestRunningTaskInfoBuilder setPositionInParent(int x, int y) {
+ mPositionInParent.set(x, y);
+ return this;
+ }
+
+ public TestRunningTaskInfoBuilder setVisible(boolean isVisible) {
+ mIsVisible = isVisible;
+ return this;
+ }
+
public ActivityManager.RunningTaskInfo build() {
final ActivityManager.RunningTaskInfo info = new ActivityManager.RunningTaskInfo();
- info.parentTaskId = INVALID_TASK_ID;
info.taskId = sNextTaskId++;
info.parentTaskId = mParentTaskId;
+ info.displayId = mDisplayId;
info.configuration.windowConfiguration.setBounds(mBounds);
info.configuration.windowConfiguration.setActivityType(mActivityType);
info.configuration.windowConfiguration.setWindowingMode(mWindowingMode);
info.token = mToken;
info.isResizeable = true;
info.supportsMultiWindow = true;
+ info.taskDescription =
+ mTaskDescriptionBuilder != null ? mTaskDescriptionBuilder.build() : null;
+ info.positionInParent = mPositionInParent;
+ info.isVisible = mIsVisible;
return info;
}
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java
index 7e6595f1abe2..00617b1a3a3d 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java
@@ -34,7 +34,6 @@ import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPL
import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_RIGHT;
import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_TOP;
-import static junit.framework.Assert.assertNull;
import static junit.framework.Assert.assertTrue;
import static junit.framework.Assert.fail;
@@ -57,7 +56,6 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
-import android.content.pm.ResolveInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Insets;
@@ -265,62 +263,6 @@ public class DragAndDropPolicyTest {
}
}
- @Test
- public void testLaunchMultipleTask_differentActivity() {
- setRunningTask(mFullscreenAppTask);
- mPolicy.start(mLandscapeDisplayLayout, mActivityClipData, mLoggerSessionId);
- Intent fillInIntent = mPolicy.getStartIntentFillInIntent(mock(PendingIntent.class), 0);
- assertNull(fillInIntent);
- }
-
- @Test
- public void testLaunchMultipleTask_differentActivity_inSplitscreen() {
- setRunningTask(mFullscreenAppTask);
- doReturn(true).when(mSplitScreenStarter).isSplitScreenVisible();
- doReturn(mFullscreenAppTask).when(mSplitScreenStarter).getTaskInfo(anyInt());
- mPolicy.start(mLandscapeDisplayLayout, mActivityClipData, mLoggerSessionId);
- Intent fillInIntent = mPolicy.getStartIntentFillInIntent(mock(PendingIntent.class), 0);
- assertNull(fillInIntent);
- }
-
- @Test
- public void testLaunchMultipleTask_sameActivity() {
- setRunningTask(mFullscreenAppTask);
-
- // Replace the mocked drag pending intent and ensure it resolves to the same activity
- PendingIntent launchIntent = mock(PendingIntent.class);
- ResolveInfo launchInfo = new ResolveInfo();
- launchInfo.activityInfo = mFullscreenAppTask.topActivityInfo;
- doReturn(Collections.singletonList(launchInfo))
- .when(launchIntent).queryIntentComponents(anyInt());
- mActivityClipData.getItemAt(0).getIntent().putExtra(ClipDescription.EXTRA_PENDING_INTENT,
- launchIntent);
-
- mPolicy.start(mLandscapeDisplayLayout, mActivityClipData, mLoggerSessionId);
- Intent fillInIntent = mPolicy.getStartIntentFillInIntent(launchIntent, 0);
- assertTrue((fillInIntent.getFlags() & Intent.FLAG_ACTIVITY_MULTIPLE_TASK) != 0);
- }
-
- @Test
- public void testLaunchMultipleTask_sameActivity_inSplitScreen() {
- setRunningTask(mFullscreenAppTask);
-
- // Replace the mocked drag pending intent and ensure it resolves to the same activity
- PendingIntent launchIntent = mock(PendingIntent.class);
- ResolveInfo launchInfo = new ResolveInfo();
- launchInfo.activityInfo = mFullscreenAppTask.topActivityInfo;
- doReturn(Collections.singletonList(launchInfo))
- .when(launchIntent).queryIntentComponents(anyInt());
- mActivityClipData.getItemAt(0).getIntent().putExtra(ClipDescription.EXTRA_PENDING_INTENT,
- launchIntent);
-
- doReturn(true).when(mSplitScreenStarter).isSplitScreenVisible();
- doReturn(mFullscreenAppTask).when(mSplitScreenStarter).getTaskInfo(anyInt());
- mPolicy.start(mLandscapeDisplayLayout, mActivityClipData, mLoggerSessionId);
- Intent fillInIntent = mPolicy.getStartIntentFillInIntent(launchIntent, 0);
- assertTrue((fillInIntent.getFlags() & Intent.FLAG_ACTIVITY_MULTIPLE_TASK) != 0);
- }
-
private Target filterTargetByType(ArrayList<Target> targets, int type) {
for (Target t : targets) {
if (type == t.type) {
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipAnimationControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipAnimationControllerTest.java
index c685fdc1f09c..52d78ca7a004 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipAnimationControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipAnimationControllerTest.java
@@ -21,6 +21,7 @@ import static android.view.Surface.ROTATION_0;
import static android.view.Surface.ROTATION_270;
import static android.view.Surface.ROTATION_90;
+import static com.android.wm.shell.MockSurfaceControlHelper.createMockSurfaceControlTransaction;
import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_LEAVE_PIP;
import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_TO_PIP;
@@ -37,6 +38,7 @@ import android.view.SurfaceControl;
import androidx.test.filters.SmallTest;
+import com.android.wm.shell.MockSurfaceControlHelper;
import com.android.wm.shell.ShellTestCase;
import org.junit.Before;
@@ -103,7 +105,8 @@ public class PipAnimationControllerTest extends ShellTestCase {
final PipAnimationController.PipTransitionAnimator oldAnimator = mPipAnimationController
.getAnimator(mTaskInfo, mLeash, baseValue, startValue, endValue1, null,
TRANSITION_DIRECTION_TO_PIP, 0, ROTATION_0);
- oldAnimator.setSurfaceControlTransactionFactory(PipDummySurfaceControlTx::new);
+ oldAnimator.setSurfaceControlTransactionFactory(
+ MockSurfaceControlHelper::createMockSurfaceControlTransaction);
oldAnimator.start();
final PipAnimationController.PipTransitionAnimator newAnimator = mPipAnimationController
@@ -133,7 +136,7 @@ public class PipAnimationControllerTest extends ShellTestCase {
@Test
public void pipTransitionAnimator_rotatedEndValue() {
- final PipDummySurfaceControlTx tx = new PipDummySurfaceControlTx();
+ final SurfaceControl.Transaction tx = createMockSurfaceControlTransaction();
final Rect startBounds = new Rect(200, 700, 400, 800);
final Rect endBounds = new Rect(0, 0, 500, 1000);
// Fullscreen to PiP.
@@ -183,7 +186,8 @@ public class PipAnimationControllerTest extends ShellTestCase {
final PipAnimationController.PipTransitionAnimator animator = mPipAnimationController
.getAnimator(mTaskInfo, mLeash, baseValue, startValue, endValue, null,
TRANSITION_DIRECTION_TO_PIP, 0, ROTATION_0);
- animator.setSurfaceControlTransactionFactory(PipDummySurfaceControlTx::new);
+ animator.setSurfaceControlTransactionFactory(
+ MockSurfaceControlHelper::createMockSurfaceControlTransaction);
animator.setPipAnimationCallback(mPipAnimationCallback);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipDummySurfaceControlTx.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipDummySurfaceControlTx.java
deleted file mode 100644
index ccf8f6e03844..000000000000
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipDummySurfaceControlTx.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.wm.shell.pip;
-
-import android.graphics.Matrix;
-import android.view.SurfaceControl;
-
-/**
- * A dummy {@link SurfaceControl.Transaction} class for testing purpose and supports
- * method chaining.
- */
-public class PipDummySurfaceControlTx extends SurfaceControl.Transaction {
- @Override
- public SurfaceControl.Transaction setAlpha(SurfaceControl leash, float alpha) {
- return this;
- }
-
- @Override
- public SurfaceControl.Transaction setPosition(SurfaceControl leash, float x, float y) {
- return this;
- }
-
- @Override
- public SurfaceControl.Transaction setWindowCrop(SurfaceControl leash, int w, int h) {
- return this;
- }
-
- @Override
- public SurfaceControl.Transaction setCornerRadius(SurfaceControl leash, float radius) {
- return this;
- }
-
- @Override
- public SurfaceControl.Transaction setShadowRadius(SurfaceControl leash, float radius) {
- return this;
- }
-
- @Override
- public SurfaceControl.Transaction setMatrix(SurfaceControl leash, Matrix matrix,
- float[] float9) {
- return this;
- }
-
- @Override
- public SurfaceControl.Transaction setFrameTimelineVsync(long frameTimelineVsyncId) {
- return this;
- }
-
- @Override
- public void apply() {}
-}
-
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java
index e8e6254697c2..b351f8fcf838 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java
@@ -44,6 +44,7 @@ import android.util.Size;
import android.view.DisplayInfo;
import android.window.WindowContainerToken;
+import com.android.wm.shell.MockSurfaceControlHelper;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.ShellTestCase;
import com.android.wm.shell.TestShellExecutor;
@@ -246,7 +247,8 @@ public class PipTaskOrganizerTest extends ShellTestCase {
mPipBoundsState.setDisplayLayout(new DisplayLayout(info,
mContext.getResources(), true, true));
mSpiedPipTaskOrganizer.setOneShotAnimationType(PipAnimationController.ANIM_TYPE_ALPHA);
- mSpiedPipTaskOrganizer.setSurfaceControlTransactionFactory(PipDummySurfaceControlTx::new);
+ mSpiedPipTaskOrganizer.setSurfaceControlTransactionFactory(
+ MockSurfaceControlHelper::createMockSurfaceControlTransaction);
doNothing().when(mSpiedPipTaskOrganizer).enterPipWithAlphaAnimation(any(), anyLong());
doNothing().when(mSpiedPipTaskOrganizer).scheduleAnimateResizePip(any(), anyInt(), any());
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitScreenControllerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitScreenControllerTests.java
new file mode 100644
index 000000000000..c90a8259a9ef
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitScreenControllerTests.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.splitscreen;
+
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
+
+import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+
+import android.app.ActivityManager;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import com.android.launcher3.icons.IconProvider;
+import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
+import com.android.wm.shell.ShellTaskOrganizer;
+import com.android.wm.shell.ShellTestCase;
+import com.android.wm.shell.common.DisplayController;
+import com.android.wm.shell.common.DisplayImeController;
+import com.android.wm.shell.common.DisplayInsetsController;
+import com.android.wm.shell.common.ShellExecutor;
+import com.android.wm.shell.common.SyncTransactionQueue;
+import com.android.wm.shell.common.TransactionPool;
+import com.android.wm.shell.recents.RecentTasksController;
+import com.android.wm.shell.transition.Transitions;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.Optional;
+
+/**
+ * Tests for {@link SplitScreenController}
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class SplitScreenControllerTests extends ShellTestCase {
+
+ @Mock ShellTaskOrganizer mTaskOrganizer;
+ @Mock SyncTransactionQueue mSyncQueue;
+ @Mock RootTaskDisplayAreaOrganizer mRootTDAOrganizer;
+ @Mock ShellExecutor mMainExecutor;
+ @Mock DisplayController mDisplayController;
+ @Mock DisplayImeController mDisplayImeController;
+ @Mock DisplayInsetsController mDisplayInsetsController;
+ @Mock Transitions mTransitions;
+ @Mock TransactionPool mTransactionPool;
+ @Mock IconProvider mIconProvider;
+ @Mock Optional<RecentTasksController> mRecentTasks;
+
+ private SplitScreenController mSplitScreenController;
+
+ @Before
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+ mSplitScreenController = spy(new SplitScreenController(mTaskOrganizer, mSyncQueue, mContext,
+ mRootTDAOrganizer, mMainExecutor, mDisplayController, mDisplayImeController,
+ mDisplayInsetsController, mTransitions, mTransactionPool, mIconProvider,
+ mRecentTasks));
+ }
+
+ @Test
+ public void testIsLaunchingAdjacently_notInSplitScreen() {
+ doReturn(false).when(mSplitScreenController).isSplitScreenVisible();
+
+ // Verify launching the same activity returns true.
+ Intent startIntent = createStartIntent("startActivity");
+ ActivityManager.RunningTaskInfo focusTaskInfo =
+ createTaskInfo(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, startIntent);
+ mSplitScreenController.onFocusTaskChanged(focusTaskInfo);
+ assertTrue(mSplitScreenController.isLaunchingAdjacently(
+ startIntent, SPLIT_POSITION_TOP_OR_LEFT));
+
+ // Verify launching different activity returns false.
+ Intent diffIntent = createStartIntent("diffActivity");
+ focusTaskInfo =
+ createTaskInfo(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, diffIntent);
+ mSplitScreenController.onFocusTaskChanged(focusTaskInfo);
+ assertFalse(mSplitScreenController.isLaunchingAdjacently(
+ startIntent, SPLIT_POSITION_TOP_OR_LEFT));
+ }
+
+ @Test
+ public void testIsLaunchingAdjacently_inSplitScreen() {
+ doReturn(true).when(mSplitScreenController).isSplitScreenVisible();
+
+ // Verify launching the same activity returns true.
+ Intent startIntent = createStartIntent("startActivity");
+ ActivityManager.RunningTaskInfo pairingTaskInfo =
+ createTaskInfo(WINDOWING_MODE_MULTI_WINDOW, ACTIVITY_TYPE_STANDARD, startIntent);
+ doReturn(pairingTaskInfo).when(mSplitScreenController).getTaskInfo(anyInt());
+ assertTrue(mSplitScreenController.isLaunchingAdjacently(
+ startIntent, SPLIT_POSITION_TOP_OR_LEFT));
+
+ // Verify launching different activity returns false.
+ Intent diffIntent = createStartIntent("diffActivity");
+ pairingTaskInfo =
+ createTaskInfo(WINDOWING_MODE_MULTI_WINDOW, ACTIVITY_TYPE_STANDARD, diffIntent);
+ doReturn(pairingTaskInfo).when(mSplitScreenController).getTaskInfo(anyInt());
+ assertFalse(mSplitScreenController.isLaunchingAdjacently(
+ startIntent, SPLIT_POSITION_TOP_OR_LEFT));
+ }
+
+ private Intent createStartIntent(String activityName) {
+ Intent intent = new Intent();
+ intent.setComponent(new ComponentName(mContext, activityName));
+ return intent;
+ }
+
+ private ActivityManager.RunningTaskInfo createTaskInfo(int winMode, int actType,
+ Intent strIntent) {
+ ActivityManager.RunningTaskInfo info = new ActivityManager.RunningTaskInfo();
+ info.configuration.windowConfiguration.setActivityType(actType);
+ info.configuration.windowConfiguration.setWindowingMode(winMode);
+ info.supportsMultiWindow = true;
+ info.baseIntent = strIntent;
+ info.baseActivity = strIntent.getComponent();
+ ActivityInfo activityInfo = new ActivityInfo();
+ activityInfo.packageName = info.baseActivity.getPackageName();
+ activityInfo.name = info.baseActivity.getClassName();
+ info.topActivityInfo = activityInfo;
+ return info;
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java
new file mode 100644
index 000000000000..680034bd2ea5
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java
@@ -0,0 +1,178 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.windowdecor;
+
+import static com.android.wm.shell.MockSurfaceControlHelper.createMockSurfaceControlBuilder;
+import static com.android.wm.shell.MockSurfaceControlHelper.createMockSurfaceControlTransaction;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyBoolean;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.same;
+import static org.mockito.Mockito.verify;
+
+import android.app.ActivityManager;
+import android.content.Context;
+import android.graphics.Color;
+import android.graphics.Rect;
+import android.testing.AndroidTestingRunner;
+import android.view.Display;
+import android.view.SurfaceControl;
+import android.view.SurfaceControlViewHost;
+import android.view.View;
+import android.window.WindowContainerTransaction;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.wm.shell.ShellTaskOrganizer;
+import com.android.wm.shell.ShellTestCase;
+import com.android.wm.shell.TestRunningTaskInfoBuilder;
+import com.android.wm.shell.common.DisplayController;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+
+import java.util.function.Supplier;
+
+/**
+ * Tests for {@link WindowDecoration}.
+ *
+ * Build/Install/Run:
+ * atest WMShellUnitTests:WindowDecorationTests
+ */
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+public class WindowDecorationTests extends ShellTestCase {
+ private static final int CAPTION_HEIGHT_DP = 32;
+ private static final int SHADOW_RADIUS_DP = 5;
+
+ private final Rect mOutsetsDp = new Rect();
+ private final WindowDecoration.RelayoutResult<TestView> mRelayoutResult =
+ new WindowDecoration.RelayoutResult<>();
+
+ @Mock
+ private DisplayController mMockDisplayController;
+ @Mock
+ private ShellTaskOrganizer mMockShellTaskOrganizer;
+ @Mock
+ private WindowDecoration.SurfaceControlViewHostFactory mMockSurfaceControlViewHostFactory;
+ @Mock
+ private SurfaceControlViewHost mMockSurfaceControlViewHost;
+ @Mock
+ private TestView mMockView;
+ @Mock
+ private WindowContainerTransaction mMockWindowContainerTransaction;
+
+ private SurfaceControl.Builder mMockSurfaceControlBuilder;
+ private SurfaceControl.Transaction mMockSurfaceControlTransaction;
+
+ @Before
+ public void setUp() {
+ mMockSurfaceControlBuilder = createMockSurfaceControlBuilder(mock(SurfaceControl.class));
+ mMockSurfaceControlTransaction = createMockSurfaceControlTransaction();
+
+ doReturn(mMockSurfaceControlViewHost).when(mMockSurfaceControlViewHostFactory)
+ .create(any(), any(), any(), anyBoolean());
+ }
+
+ @Test
+ public void testNotCrashWhenDisplayAppearsAfterTask() {
+ doReturn(mock(Display.class)).when(mMockDisplayController)
+ .getDisplay(Display.DEFAULT_DISPLAY);
+
+ final int displayId = Display.DEFAULT_DISPLAY + 1;
+ final ActivityManager.TaskDescription.Builder taskDescriptionBuilder =
+ new ActivityManager.TaskDescription.Builder()
+ .setBackgroundColor(Color.BLACK);
+ final ActivityManager.RunningTaskInfo taskInfo = new TestRunningTaskInfoBuilder()
+ .setDisplayId(displayId)
+ .setTaskDescriptionBuilder(taskDescriptionBuilder)
+ .setVisible(true)
+ .build();
+
+ final TestWindowDecoration windowDecor =
+ createWindowDecoration(taskInfo, new SurfaceControl());
+ windowDecor.relayout(taskInfo);
+
+ // It shouldn't show the window decoration when it can't obtain the display instance.
+ assertThat(mRelayoutResult.mRootView).isNull();
+
+ final ArgumentCaptor<DisplayController.OnDisplaysChangedListener> listenerArgumentCaptor =
+ ArgumentCaptor.forClass(DisplayController.OnDisplaysChangedListener.class);
+ verify(mMockDisplayController).addDisplayWindowListener(listenerArgumentCaptor.capture());
+ final DisplayController.OnDisplaysChangedListener listener =
+ listenerArgumentCaptor.getValue();
+
+ // Adding an irrelevant display shouldn't change the result.
+ listener.onDisplayAdded(Display.DEFAULT_DISPLAY);
+ assertThat(mRelayoutResult.mRootView).isNull();
+
+ final Display mockDisplay = mock(Display.class);
+ doReturn(mockDisplay).when(mMockDisplayController).getDisplay(displayId);
+
+ listener.onDisplayAdded(displayId);
+
+ // The listener should be removed when the display shows up.
+ verify(mMockDisplayController).removeDisplayWindowListener(same(listener));
+
+ assertThat(mRelayoutResult.mRootView).isSameInstanceAs(mMockView);
+ verify(mMockSurfaceControlViewHostFactory)
+ .create(any(), eq(mockDisplay), any(), anyBoolean());
+ verify(mMockSurfaceControlViewHost).setView(same(mMockView), any());
+ }
+
+ private TestWindowDecoration createWindowDecoration(
+ ActivityManager.RunningTaskInfo taskInfo, SurfaceControl testSurface) {
+ return new TestWindowDecoration(mContext, mMockDisplayController, mMockShellTaskOrganizer,
+ taskInfo, testSurface, () -> mMockSurfaceControlBuilder,
+ mMockSurfaceControlViewHostFactory);
+ }
+
+ private static class TestView extends View implements TaskFocusStateConsumer {
+ private TestView(Context context) {
+ super(context);
+ }
+
+ @Override
+ public void setTaskFocusState(boolean focused) {}
+ }
+
+ private class TestWindowDecoration extends WindowDecoration<TestView> {
+ TestWindowDecoration(Context context, DisplayController displayController,
+ ShellTaskOrganizer taskOrganizer, ActivityManager.RunningTaskInfo taskInfo,
+ SurfaceControl taskSurface,
+ Supplier<SurfaceControl.Builder> surfaceControlBuilderSupplier,
+ SurfaceControlViewHostFactory surfaceControlViewHostFactory) {
+ super(context, displayController, taskOrganizer, taskInfo, taskSurface,
+ surfaceControlBuilderSupplier, surfaceControlViewHostFactory);
+ }
+
+ @Override
+ void relayout(ActivityManager.RunningTaskInfo taskInfo) {
+ relayout(null /* taskInfo */, 0 /* layoutResId */, mMockView, CAPTION_HEIGHT_DP,
+ mOutsetsDp, SHADOW_RADIUS_DP, mMockSurfaceControlTransaction,
+ mMockWindowContainerTransaction, mRelayoutResult);
+ }
+ }
+}
diff --git a/libs/hwui/Readback.cpp b/libs/hwui/Readback.cpp
index 79953aa6adc9..1191b92a0aeb 100644
--- a/libs/hwui/Readback.cpp
+++ b/libs/hwui/Readback.cpp
@@ -102,11 +102,36 @@ CopyResult Readback::copySurfaceInto(ANativeWindow* window, const Rect& inSrcRec
SkRect srcRect = inSrcRect.toSkRect();
- SkRect imageSrcRect =
- SkRect::MakeLTRB(cropRect.left, cropRect.top, cropRect.right, cropRect.bottom);
- if (imageSrcRect.isEmpty()) {
- imageSrcRect = SkRect::MakeIWH(description.width, description.height);
+ SkRect imageSrcRect = SkRect::MakeIWH(description.width, description.height);
+ SkISize imageWH = SkISize::Make(description.width, description.height);
+ if (cropRect.left < cropRect.right && cropRect.top < cropRect.bottom) {
+ imageSrcRect =
+ SkRect::MakeLTRB(cropRect.left, cropRect.top, cropRect.right, cropRect.bottom);
+ imageWH = SkISize::Make(cropRect.right - cropRect.left, cropRect.bottom - cropRect.top);
+
+ // Chroma channels of YUV420 images are subsampled we may need to shrink the crop region by
+ // a whole texel on each side. Since skia still adds its own 0.5 inset, we apply an
+ // additional 0.5 inset. See GLConsumer::computeTransformMatrix for details.
+ float shrinkAmount = 0.0f;
+ switch (description.format) {
+ // Use HAL formats since some AHB formats are only available in vndk
+ case HAL_PIXEL_FORMAT_YCBCR_420_888:
+ case HAL_PIXEL_FORMAT_YV12:
+ case HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED:
+ shrinkAmount = 0.5f;
+ break;
+ default:
+ break;
+ }
+
+ // Shrink the crop if it has more than 1-px and differs from the buffer size.
+ if (imageWH.width() > 1 && imageWH.width() < (int32_t)description.width)
+ imageSrcRect = imageSrcRect.makeInset(shrinkAmount, 0);
+
+ if (imageWH.height() > 1 && imageWH.height() < (int32_t)description.height)
+ imageSrcRect = imageSrcRect.makeInset(0, shrinkAmount);
}
+
ALOGV("imageSrcRect = " RECT_STRING, SK_RECT_ARGS(imageSrcRect));
// Represents the "logical" width/height of the texture. That is, the dimensions of the buffer
@@ -165,7 +190,7 @@ CopyResult Readback::copySurfaceInto(ANativeWindow* window, const Rect& inSrcRec
*/
SkMatrix m;
- const SkRect imageDstRect = SkRect::MakeIWH(imageSrcRect.width(), imageSrcRect.height());
+ const SkRect imageDstRect = SkRect::Make(imageWH);
const float px = imageDstRect.centerX();
const float py = imageDstRect.centerY();
if (windowTransform & NATIVE_WINDOW_TRANSFORM_FLIP_H) {
diff --git a/location/java/android/location/SettingInjectorService.java b/location/java/android/location/SettingInjectorService.java
index d6f8a7ca3cfc..2aa812b6756e 100644
--- a/location/java/android/location/SettingInjectorService.java
+++ b/location/java/android/location/SettingInjectorService.java
@@ -179,7 +179,7 @@ public abstract class SettingInjectorService extends Service {
* intent.
*/
private void sendStatus(Intent intent, String summary, boolean enabled) {
- Messenger messenger = intent.getParcelableExtra(MESSENGER_KEY);
+ Messenger messenger = intent.getParcelableExtra(MESSENGER_KEY, android.os.Messenger.class);
// Bail out to avoid crashing GmsCore with incoming malicious Intent.
if (messenger == null) {
return;
diff --git a/media/java/android/media/AudioAttributes.java b/media/java/android/media/AudioAttributes.java
index ded9597b68ef..546f0c665a98 100644
--- a/media/java/android/media/AudioAttributes.java
+++ b/media/java/android/media/AudioAttributes.java
@@ -1286,6 +1286,8 @@ public final class AudioAttributes implements Parcelable {
/**
* Specifying if haptic should be muted or not when playing audio-haptic coupled data.
* By default, haptic channels are disabled.
+ * <p>This will be ignored if the caller doesn't have the
+ * {@link android.Manifest.permission#VIBRATE} permission.
* @param muted true to force muting haptic channels.
* @return the same Builder instance.
*/
diff --git a/media/java/android/media/MediaMetadata.java b/media/java/android/media/MediaMetadata.java
index db5e52a44c8a..7b3a56801a35 100644
--- a/media/java/android/media/MediaMetadata.java
+++ b/media/java/android/media/MediaMetadata.java
@@ -500,7 +500,7 @@ public final class MediaMetadata implements Parcelable {
public Rating getRating(@RatingKey String key) {
Rating rating = null;
try {
- rating = mBundle.getParcelable(key);
+ rating = mBundle.getParcelable(key, android.media.Rating.class);
} catch (Exception e) {
// ignore, value was not a bitmap
Log.w(TAG, "Failed to retrieve a key as Rating.", e);
@@ -518,7 +518,7 @@ public final class MediaMetadata implements Parcelable {
public Bitmap getBitmap(@BitmapKey String key) {
Bitmap bmp = null;
try {
- bmp = mBundle.getParcelable(key);
+ bmp = mBundle.getParcelable(key, android.graphics.Bitmap.class);
} catch (Exception e) {
// ignore, value was not a bitmap
Log.w(TAG, "Failed to retrieve a key as Bitmap.", e);
diff --git a/media/java/android/media/MediaRouter.java b/media/java/android/media/MediaRouter.java
index 7d57734defc5..d7fc205d28d3 100644
--- a/media/java/android/media/MediaRouter.java
+++ b/media/java/android/media/MediaRouter.java
@@ -3184,7 +3184,7 @@ public class MediaRouter {
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(DisplayManager.ACTION_WIFI_DISPLAY_STATUS_CHANGED)) {
updateWifiDisplayStatus((WifiDisplayStatus) intent.getParcelableExtra(
- DisplayManager.EXTRA_WIFI_DISPLAY_STATUS));
+ DisplayManager.EXTRA_WIFI_DISPLAY_STATUS, android.hardware.display.WifiDisplayStatus.class));
}
}
}
diff --git a/media/java/android/media/RemoteController.java b/media/java/android/media/RemoteController.java
index 00fc2757a702..a6e8fa0644df 100644
--- a/media/java/android/media/RemoteController.java
+++ b/media/java/android/media/RemoteController.java
@@ -407,7 +407,7 @@ import java.util.List;
mEditableKeys = editableKeys;
mEditorArtwork = (Bitmap) metadata.getParcelable(
- String.valueOf(MediaMetadataEditor.BITMAP_KEY_ARTWORK));
+ String.valueOf(MediaMetadataEditor.BITMAP_KEY_ARTWORK), android.graphics.Bitmap.class);
if (mEditorArtwork != null) {
cleanupBitmapFromBundle(MediaMetadataEditor.BITMAP_KEY_ARTWORK);
}
diff --git a/media/java/android/media/audiofx/HapticGenerator.java b/media/java/android/media/audiofx/HapticGenerator.java
index fe7f29e1fc00..d2523ef43b9e 100644
--- a/media/java/android/media/audiofx/HapticGenerator.java
+++ b/media/java/android/media/audiofx/HapticGenerator.java
@@ -91,7 +91,8 @@ public class HapticGenerator extends AudioEffect implements AutoCloseable {
}
/**
- * Enable or disable the effect.
+ * Enable or disable the effect. The effect can only be enabled if the caller has the
+ * {@link android.Manifest.permission#VIBRATE} permission.
*
* @param enabled the requested enable state
* @return {@link #SUCCESS} in case of success, {@link #ERROR_INVALID_OPERATION}
diff --git a/media/java/android/media/session/MediaSession.java b/media/java/android/media/session/MediaSession.java
index bc00c404b11e..9e265d8339dd 100644
--- a/media/java/android/media/session/MediaSession.java
+++ b/media/java/android/media/session/MediaSession.java
@@ -917,7 +917,7 @@ public final class MediaSession {
public boolean onMediaButtonEvent(@NonNull Intent mediaButtonIntent) {
if (mSession != null && mHandler != null
&& Intent.ACTION_MEDIA_BUTTON.equals(mediaButtonIntent.getAction())) {
- KeyEvent ke = mediaButtonIntent.getParcelableExtra(Intent.EXTRA_KEY_EVENT);
+ KeyEvent ke = mediaButtonIntent.getParcelableExtra(Intent.EXTRA_KEY_EVENT, android.view.KeyEvent.class);
if (ke != null && ke.getAction() == KeyEvent.ACTION_DOWN) {
PlaybackState state = mSession.mPlaybackState;
long validActions = state == null ? 0 : state.getActions();
diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml
index 861d84d752be..8e702dbabdbe 100644
--- a/packages/SettingsLib/res/values-fa/strings.xml
+++ b/packages/SettingsLib/res/values-fa/strings.xml
@@ -576,7 +576,7 @@
<string name="user_setup_dialog_message" msgid="269931619868102841">"مطمئن شوید شخص در دسترس است تا دستگاه را بگیرد و فضایش را تنظیم کند"</string>
<string name="user_setup_profile_dialog_message" msgid="4788197052296962620">"اکنون نمایه را تنظیم می‌کنید؟"</string>
<string name="user_setup_button_setup_now" msgid="1708269547187760639">"اکنون تنظیم شود"</string>
- <string name="user_setup_button_setup_later" msgid="8712980133555493516">"اکنون نه"</string>
+ <string name="user_setup_button_setup_later" msgid="8712980133555493516">"حالا نه"</string>
<string name="user_add_user_type_title" msgid="551279664052914497">"افزودن"</string>
<string name="user_new_user_name" msgid="60979820612818840">"کاربر جدید"</string>
<string name="user_new_profile_name" msgid="2405500423304678841">"نمایه جدید"</string>
diff --git a/packages/SettingsLib/res/values-mn/strings.xml b/packages/SettingsLib/res/values-mn/strings.xml
index 78c7ab48d778..75abf997a8cf 100644
--- a/packages/SettingsLib/res/values-mn/strings.xml
+++ b/packages/SettingsLib/res/values-mn/strings.xml
@@ -100,13 +100,13 @@
<string name="bluetooth_connected_no_a2dp" msgid="8566874395813947092">"Холбогдсон (медиа байхгүй)<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string>
<string name="bluetooth_connected_no_map" msgid="3381860077002724689">"Холбогдсон (мессежийн хандалт байхгүй)<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string>
<string name="bluetooth_connected_no_headset_no_a2dp" msgid="2893204819854215433">"Холбогдсон (утас эсвэл медиа байхгүй)<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string>
- <string name="bluetooth_connected_battery_level" msgid="5410325759372259950">"Холбогдсон, батерей <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g><xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g>"</string>
- <string name="bluetooth_connected_no_headset_battery_level" msgid="2661863370509206428">"Холбогдсон (утас байхгүй), батерей <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g><xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g>"</string>
- <string name="bluetooth_connected_no_a2dp_battery_level" msgid="6499078454894324287">"Холбогдсон (медиа байхгүй), батерей <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g><xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g>"</string>
- <string name="bluetooth_connected_no_headset_no_a2dp_battery_level" msgid="8477440576953067242">"Холбогдсон (утас эсвэл медиа байхгүй), батерей <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g><xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g>"</string>
- <string name="bluetooth_active_battery_level" msgid="3450745316700494425">"Идэвхтэй, батерей <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <string name="bluetooth_connected_battery_level" msgid="5410325759372259950">"Холбогдсон, батарей <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g><xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g>"</string>
+ <string name="bluetooth_connected_no_headset_battery_level" msgid="2661863370509206428">"Холбогдсон (утас байхгүй), батарей <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g><xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g>"</string>
+ <string name="bluetooth_connected_no_a2dp_battery_level" msgid="6499078454894324287">"Холбогдсон (медиа байхгүй), батарей <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g><xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g>"</string>
+ <string name="bluetooth_connected_no_headset_no_a2dp_battery_level" msgid="8477440576953067242">"Холбогдсон (утас эсвэл медиа байхгүй), батарей <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g><xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g>"</string>
+ <string name="bluetooth_active_battery_level" msgid="3450745316700494425">"Идэвхтэй, батарей <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_active_battery_level_untethered" msgid="2706188607604205362">"Идэвхтэй, Зүүн: Батарей <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, Баруун: Батарей <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string>
- <string name="bluetooth_battery_level" msgid="2893696778200201555">"Батерей <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
+ <string name="bluetooth_battery_level" msgid="2893696778200201555">"Батарей <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"Зүүн: Батарей <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, Баруун: Батарей <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string>
<string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Идэвхтэй"</string>
<string name="bluetooth_hearing_aid_left_active" msgid="7084887715570971441">"Идэвхтэй, зөвхөн зүүн тал"</string>
diff --git a/packages/SettingsLib/res/values-my/strings.xml b/packages/SettingsLib/res/values-my/strings.xml
index 083e55a7e1fc..3c7e5b3a883f 100644
--- a/packages/SettingsLib/res/values-my/strings.xml
+++ b/packages/SettingsLib/res/values-my/strings.xml
@@ -183,8 +183,8 @@
<string name="running_process_item_user_label" msgid="3988506293099805796">"အသုံးပြုသူ- <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
<string name="launch_defaults_some" msgid="3631650616557252926">"မူရင်းအချို့ သတ်မှတ်ပြီး"</string>
<string name="launch_defaults_none" msgid="8049374306261262709">"မူရင်း သတ်မှတ်မထားပါ။"</string>
- <string name="tts_settings" msgid="8130616705989351312">"စာသားမှစကားပြောပြောင်း ဆက်တင်များ"</string>
- <string name="tts_settings_title" msgid="7602210956640483039">"စာသားမှ စကားပြောသို့ အထွက်"</string>
+ <string name="tts_settings" msgid="8130616705989351312">"စာ-မှ-စကားပြောင်းခြင်း ဆက်တင်များ"</string>
+ <string name="tts_settings_title" msgid="7602210956640483039">"စာ-မှ-စကားသို့ အထွက်"</string>
<string name="tts_default_rate_title" msgid="3964187817364304022">"စကားပြောနှုန်း"</string>
<string name="tts_default_rate_summary" msgid="3781937042151716987">"စာတမ်းအားပြောဆိုသော အမြန်နှုန်း"</string>
<string name="tts_default_pitch_title" msgid="6988592215554485479">"အသံအနိမ့်အမြင့်"</string>
@@ -198,7 +198,7 @@
<string name="tts_install_data_title" msgid="1829942496472751703">"အသံဒေတာများကို ထည့်သွင်းခြင်း"</string>
<string name="tts_install_data_summary" msgid="3608874324992243851">"စကားသံပေါင်းစပ်မှုအတွက်လိုအပ်သောအသံဒေတာအား ထည့်သွင်းမည်"</string>
<string name="tts_engine_security_warning" msgid="3372432853837988146">"ဤစကားသံပေါင်းစပ်စနစ်အားအသုံးပြုရာရာတွင် သင့်ကိုယ်ရေးအချက်အလက်များဖြစ်သော စကားဝှက်များနှင့် ကရက်ဒစ်ကတ်နံပါတ်စသည်တို့အပါအဝင် သင်ပြောဆိုသောစာသားများအားလုံးကို ရယူသွားမည်ဖြစ်သည်။ ဤစနစ်သည် <xliff:g id="TTS_PLUGIN_ENGINE_NAME">%s</xliff:g> မှ လာပါသည်။ ဤစကားသံပေါင်းစပ်စနစ်ကို အသုံးပြုမလား။"</string>
- <string name="tts_engine_network_required" msgid="8722087649733906851">"ဤဘာသာစကားသည် စာသားမှ အသံထွက်ရန် အလုပ်လုပ်သော ကွန်ရက်ချိတ်ဆက်မှု လိုအပ်သည်။"</string>
+ <string name="tts_engine_network_required" msgid="8722087649733906851">"ဤဘာသာစကားသည် စာ-မှ-စကား ပြောင်းရန် အလုပ်လုပ်သော ကွန်ရက်ချိတ်ဆက်မှု လိုအပ်သည်။"</string>
<string name="tts_default_sample_string" msgid="6388016028292967973">"ဤသည်မှာ အသံတုလုပ်ခြင်း ၏ နမူနာတစ်ခုဖြစ်သည်။"</string>
<string name="tts_status_title" msgid="8190784181389278640">"လက်ရှိဘာသာစကားအခြေအနေ"</string>
<string name="tts_status_ok" msgid="8583076006537547379">"<xliff:g id="LOCALE">%1$s</xliff:g> သည်အပြည့်အ၀ အထောက်အကူပြုသည်။"</string>
diff --git a/packages/SettingsProvider/res/values-nb/strings.xml b/packages/SettingsProvider/res/values-nb/strings.xml
index 3bdaf83a4230..8da90c0f32cb 100644
--- a/packages/SettingsProvider/res/values-nb/strings.xml
+++ b/packages/SettingsProvider/res/values-nb/strings.xml
@@ -20,6 +20,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4567566098528588863">"Lagring av innstillinger"</string>
- <string name="wifi_softap_config_change" msgid="5688373762357941645">"Innstillingene for Wi-Fi-sone er endret"</string>
+ <string name="wifi_softap_config_change" msgid="5688373762357941645">"Innstillingene for wifi-sone er endret"</string>
<string name="wifi_softap_config_change_summary" msgid="8946397286141531087">"Trykk for å se detaljer"</string>
</resources>
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 1c13b1660e31..6edf13addbca 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -618,6 +618,17 @@
android:excludeFromRecents="true"
android:visibleToInstantApps="true"/>
+ <activity
+ android:name=".media.MediaProjectionAppSelectorActivity"
+ android:theme="@style/Theme.SystemUI.MediaProjectionAppSelector"
+ android:finishOnCloseSystemDialogs="true"
+ android:excludeFromRecents="true"
+ android:documentLaunchMode="never"
+ android:relinquishTaskIdentity="true"
+ android:configChanges=
+ "screenSize|smallestScreenSize|screenLayout|orientation|keyboard|keyboardHidden"
+ android:visibleToInstantApps="true"/>
+
<!-- started from TvNotificationPanel -->
<activity
android:name=".statusbar.tv.notifications.TvNotificationPanelActivity"
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt
index cb16d7c3471f..dbdbdf6ee2ba 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt
@@ -150,15 +150,16 @@ constructor(
fun showFromDialog(
dialog: Dialog,
animateFrom: Dialog,
+ cuj: DialogCuj? = null,
animateBackgroundBoundsChange: Boolean = false
) {
val view =
openedDialogs.firstOrNull { it.dialog == animateFrom }?.dialogContentWithBackground
?: throw IllegalStateException(
"The animateFrom dialog was not animated using " +
- "DialogLaunchAnimator.showFrom(View|Dialog)"
- )
- showFromView(dialog, view, animateBackgroundBoundsChange = animateBackgroundBoundsChange)
+ "DialogLaunchAnimator.showFrom(View|Dialog)")
+ showFromView(
+ dialog, view, animateBackgroundBoundsChange = animateBackgroundBoundsChange, cuj = cuj)
}
/**
diff --git a/packages/SystemUI/docs/camera.md b/packages/SystemUI/docs/camera.md
index cabc65c53caa..a1c845832049 100644
--- a/packages/SystemUI/docs/camera.md
+++ b/packages/SystemUI/docs/camera.md
@@ -1,34 +1,23 @@
# How double-click power launches the camera
-
-_as of august 2020_
-
+_Last update: July 2022_
## Sequence of events
-
-
-
-1. [PhoneWindowManager.java](/services/core/java/com/android/server/policy/PhoneWindowManager.java) is responsible for all power button presses (see `interceptPowerKeyDown`).
-2. Even though PWMgr has a lot of logic to detect all manner of power button multipresses and gestures, it also checks with GestureLauncherService, which is also [offered the chance](/services/core/java/com/android/server/policy/PhoneWindowManager.java#943) to [intercept](/services/core/java/com/android/server/GestureLauncherService.java#358) the power key.
-3. GLS is responsible for the camera timeout, and if it detects one, it [forwards it to the StatusBarManagerService](/services/core/java/com/android/server/GestureLauncherService.java#475) (which hands it off to SystemUI).
-4. Inside SystemUI, [onCameraLaunchDetected](/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java#3927) looks at the keyguard state and determines
+1. [PhoneWindowManager.java](/services/core/java/com/android/server/policy/PhoneWindowManager.java) is responsible for all power button presses (see `interceptPowerKeyDown`)
+2. Even though `PhoneWindowManager` has a lot of logic to detect all manner of power button multi-presses and gestures, it also checks with `GestureLauncherService`, which is also [offered the chance](/services/core/java/com/android/server/policy/PhoneWindowManager.java#943) to [intercept](/services/core/java/com/android/server/GestureLauncherService.java) the power key
+3. `GestureLauncherService` is responsible for the camera timeout, and if it detects one, it [forwards it to the StatusBarManagerService](/services/core/java/com/android/server/GestureLauncherService.java) (which hands it off to SystemUI)
+4. Inside SystemUI, `onCameraLaunchDetected` in [CentralSurfacesCommandQueueCallbacks.java](/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java) looks at the keyguard state and determines
1. whether the camera is even allowed
2. whether the screen is on; if not, we need to delay until that happens
3. whether the device is locked (defined as "keyguard is showing").
-5. If the device is unlocked (no keyguard), the camera is launched immediately. [Callsite in onCameraLaunchGestureDetected](/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java#4047).
-6. If the keyguard is up, however, [KeyguardBottomAreaView.launchCamera](/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java#477) takes over to handle the "secure camera" (a different intent, usually directing to the same app, but giving that app the cue to not allow access to the photo roll, etc).
-7. If the intent [would have to launch a resolver](/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java#480) (the user has multiple cameras installed and hasn’t chosen one to always launch for the `SECURE_CAMERA_INTENT`),
- 1. In order to show the resolver, the lockscreen "bouncer" (authentication method) [is first presented](/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java#523).
-8. Otherwise (just one secure camera), [it is launched](/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java#501) (with some window animation gymnastics).
-
-
-## Which intent launches?
-
-
-
-* If the keyguard is not showing (device is unlocked)
- * `CameraIntents.getInsecureCameraIntent()`, defined to be `MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA`.
- * [Callsite](/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java#3950) in StatusBar.java.
-* If the keyguard is showing (device locked)
- * [KeyguardBottomAreaView.getCameraIntent()](/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java#366) is consulted, which allows the "keyguard right button" (which we don’t actually show) to control the camera intent. The [default implementation](/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java#831) returns one of `CameraIntents.getInsecureCameraIntent()` or `CameraIntents.getSecureCameraIntent()`, which are `MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA` and `MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE`, respectively.
- * [Callsite](/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java#523) in KeyguardBottomAreaView.java.
-* Note that starting in Android 12, as required by some OEMs, if the special string resource `config_cameraGesturePackage` is nonempty, this will be treated as a package name to be added to the insecure camera intent, constraining the invocation to that single app and typically preventing implicit intent resolution. This package must be on the device or the camera gesture will no longer work properly. \ No newline at end of file
+5. If the device is unlocked (no keyguard), the camera is launched immediately
+6. If the keyguard is up, however, [NotificationPanelViewController.launchCamera](/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java) takes over to handle the "secure camera" (a different intent, usually directing to the same app, but giving that app the cue to not allow access to the photo roll, etc).
+7. If the intent would have to launch a resolver (because the user has multiple camera apps installed and has not chosen one to always launch for the `SECURE_CAMERA_INTENT`, then - in order to show the resolver, the lockscreen "bouncer" (authentication method) is first presented
+8. Otherwise (just one secure camera), it is launched
+
+## Which intent launches the camera app?
+[CameraGestureHelper](/packages/SystemUI/src/com/android/systemui/camera/CameraGestureHelper.kt) encapsulate this logic. Roughly:
+* If the keyguard is not showing (device is unlocked)
+ * `CameraIntents.getInsecureCameraIntent()`, defined to be `MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA`.
+* If the keyguard is showing (device is locked)
+ * one of `CameraIntents.getInsecureCameraIntent()` or `CameraIntents.getSecureCameraIntent()`, which are `MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA` and `MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE`, respectively
+* Note that starting in Android 12, as required by some OEMs, if the special string resource `config_cameraGesturePackage` is nonempty, this will be treated as a package name to be added to the insecure camera intent, constraining the invocation to that single app and typically preventing implicit intent resolution. This package must be on the device or the camera gesture will no longer work properly
diff --git a/packages/SystemUI/proguard.flags b/packages/SystemUI/proguard.flags
index 6ffd66163653..ed01494a911b 100644
--- a/packages/SystemUI/proguard.flags
+++ b/packages/SystemUI/proguard.flags
@@ -9,8 +9,8 @@
-keep class com.android.systemui.statusbar.phone.CentralSurfaces
-keep class com.android.systemui.statusbar.tv.TvStatusBar
-keep class com.android.systemui.car.CarSystemUIFactory
--keep class com.android.systemui.SystemUIFactory
--keep class com.android.systemui.tv.TvSystemUIFactory
+-keep class com.android.systemui.SystemUIInitializer
+-keep class com.android.systemui.tv.TvSystemUIInitializer
-keep class * extends com.android.systemui.CoreStartable
-keep class * implements com.android.systemui.CoreStartable$Injector
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_bouncer_user_switcher.xml b/packages/SystemUI/res-keyguard/layout/keyguard_bouncer_user_switcher.xml
index 36035fc87e40..01e3de2315af 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_bouncer_user_switcher.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_bouncer_user_switcher.xml
@@ -45,6 +45,7 @@
style="@style/Bouncer.UserSwitcher.Spinner.Header"
android:clickable="false"
android:id="@+id/user_switcher_header"
+ android:textDirection="locale"
android:layout_width="@dimen/bouncer_user_switcher_width"
android:layout_height="wrap_content" />
</LinearLayout>>
diff --git a/packages/SystemUI/res/values-television/config.xml b/packages/SystemUI/res/values-television/config.xml
index 94f6c3952e06..375bd394bb4c 100644
--- a/packages/SystemUI/res/values-television/config.xml
+++ b/packages/SystemUI/res/values-television/config.xml
@@ -22,7 +22,7 @@
<resources>
<!-- SystemUIFactory component -->
<string name="config_systemUIFactoryComponent" translatable="false">
- com.android.systemui.tv.TvSystemUIFactory
+ com.android.systemui.tv.TvSystemUIInitializer
</string>
<!-- Svelte specific logic, see RecentsConfiguration.SVELTE_* constants. -->
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 771973c36053..82a3b58a5155 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -286,7 +286,7 @@
<bool name="config_enableFullscreenUserSwitcher">false</bool>
<!-- SystemUIFactory component -->
- <string name="config_systemUIFactoryComponent" translatable="false">com.android.systemui.SystemUIFactory</string>
+ <string name="config_systemUIFactoryComponent" translatable="false">com.android.systemui.SystemUIInitializerImpl</string>
<!-- QS tile shape store width. negative implies fill configuration instead of stroke-->
<dimen name="config_qsTileStrokeWidthActive">-1dp</dimen>
diff --git a/packages/SystemUI/res/values/ids.xml b/packages/SystemUI/res/values/ids.xml
index f013f9b49955..dca5ea836fa4 100644
--- a/packages/SystemUI/res/values/ids.xml
+++ b/packages/SystemUI/res/values/ids.xml
@@ -132,9 +132,6 @@
<item type="id" name="status_bar_view_state_tag" />
<item type="id" name="display_cutout" />
- <item type="id" name="display_cutout_left" />
- <item type="id" name="display_cutout_right" />
- <item type="id" name="display_cutout_bottom" />
<item type="id" name="row_tag_for_content_view" />
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 758c16d15bcf..22279785a773 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -265,6 +265,10 @@
<style name="Animation.ShutdownUi" parent="@android:style/Animation.Toast">
</style>
+ <style name="Theme.SystemUI.MediaProjectionAppSelector"
+ parent="@*android:style/Theme.DeviceDefault.Chooser">
+ </style>
+
<!-- Standard animations for hiding and showing the status bar. -->
<style name="Theme.SystemUI" parent="@*android:style/Theme.DeviceDefault.SystemUI">
diff --git a/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/ScreenshotTestRule.kt b/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/ScreenshotTestRule.kt
index 363ce10fa36c..564901c2a773 100644
--- a/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/ScreenshotTestRule.kt
+++ b/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/ScreenshotTestRule.kt
@@ -20,6 +20,7 @@ import android.app.UiModeManager
import android.content.Context
import android.graphics.Bitmap
import android.graphics.Canvas
+import android.os.Build
import android.os.UserHandle
import android.view.Display
import android.view.View
@@ -32,6 +33,7 @@ import platform.test.screenshot.GoldenImagePathManager
import platform.test.screenshot.PathConfig
import platform.test.screenshot.PathElementNoContext
import platform.test.screenshot.ScreenshotTestRule
+import platform.test.screenshot.matchers.MSSIMMatcher
import platform.test.screenshot.matchers.PixelPerfectMatcher
/**
@@ -55,7 +57,11 @@ class ScreenshotTestRule(private val testSpec: ScreenshotTestSpec) : TestRule {
currentDisplay?.name ?: error("currentDisplay is null")
},
)
- private val defaultMatcher = PixelPerfectMatcher()
+ private val matcher = if (shouldUsePerfectMatching()) {
+ PixelPerfectMatcher()
+ } else {
+ MSSIMMatcher()
+ }
private val screenshotRule =
ScreenshotTestRule(
@@ -67,6 +73,17 @@ class ScreenshotTestRule(private val testSpec: ScreenshotTestSpec) : TestRule {
)
)
+ private fun shouldUsePerfectMatching(): Boolean {
+ // Different CPU architectures can sometimes end up rendering differently, so we can't do
+ // pixel-perfect matching on different architectures using the same golden. Given that our
+ // presubmits are run on cf_x86_64_phone, our goldens should be perfectly matched on the
+ // x86_64 architecture and use the Structural Similarity Index on others.
+ // TODO(b/237511747): Run our screenshot presubmit tests on arm64 instead so that we can
+ // do pixel perfect matching both at presubmit time and at development time with actual
+ // devices.
+ return Build.CPU_ABI == "x86_64"
+ }
+
override fun apply(base: Statement, description: Description): Statement {
// The statement which call beforeTest() before running the test and afterTest() afterwards.
val statement =
@@ -147,7 +164,7 @@ class ScreenshotTestRule(private val testSpec: ScreenshotTestSpec) : TestRule {
// device to assertBitmapAgainstGolden instead?
currentDisplay = testSpec.display
currentGoldenIdentifier = goldenIdentifier
- screenshotRule.assertBitmapAgainstGolden(bitmap, identifierWithSpec, defaultMatcher)
+ screenshotRule.assertBitmapAgainstGolden(bitmap, identifierWithSpec, matcher)
currentDisplay = null
currentGoldenIdentifier = goldenIdentifier
}
diff --git a/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/ViewScreenshotTestRule.kt b/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/ViewScreenshotTestRule.kt
index 35812e39677d..6a80c486d515 100644
--- a/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/ViewScreenshotTestRule.kt
+++ b/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/ViewScreenshotTestRule.kt
@@ -60,11 +60,17 @@ class ViewScreenshotTestRule(testSpec: ScreenshotTestSpec) : TestRule {
) {
var dialog: Dialog? = null
activityRule.scenario.onActivity { activity ->
- // Make sure that the dialog draws full screen and fits the whole display instead of the
- // system bars.
dialog =
dialogProvider(activity).apply {
+ // Make sure that the dialog draws full screen and fits the whole display
+ // instead of the system bars.
window.setDecorFitsSystemWindows(false)
+
+ // Disable enter/exit animations.
+ create()
+ window.setWindowAnimations(0)
+
+ // Show the dialog.
show()
}
}
@@ -74,7 +80,11 @@ class ViewScreenshotTestRule(testSpec: ScreenshotTestSpec) : TestRule {
activityRule.scenario.onActivity {
// Check that the content is what we expected.
val dialog = dialog ?: error("dialog is null")
- screenshotRule.screenshotTest(goldenIdentifier, dialog.window.decorView)
+ try {
+ screenshotRule.screenshotTest(goldenIdentifier, dialog.window.decorView)
+ } finally {
+ dialog.dismiss()
+ }
}
}
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java
index db416013c453..a66dc7743792 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java
@@ -427,18 +427,14 @@ public class RemoteTransitionCompat implements Parcelable {
mPipTransaction = null;
}
}
- // Release surface references now. This is apparently to free GPU
- // memory while doing quick operations (eg. during CTS).
- for (int i = 0; i < mLeashMap.size(); ++i) {
- if (mLeashMap.keyAt(i) == mLeashMap.valueAt(i)) continue;
- t.remove(mLeashMap.valueAt(i));
- }
try {
mFinishCB.onTransitionFinished(wct.isEmpty() ? null : wct, t);
} catch (RemoteException e) {
Log.e("RemoteTransitionCompat", "Failed to call animation finish callback", e);
t.apply();
}
+ // Only release the non-local created surface references. The animator is responsible
+ // for releasing the leashes created by local.
for (int i = 0; i < mInfo.getChanges().size(); ++i) {
mInfo.getChanges().get(i).getLeash().release();
}
diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
index c1b2aba22b57..43e737823692 100644
--- a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
@@ -23,7 +23,6 @@ import static com.android.keyguard.LockIconView.ICON_LOCK;
import static com.android.keyguard.LockIconView.ICON_UNLOCK;
import static com.android.systemui.classifier.Classifier.LOCK_ICON;
import static com.android.systemui.doze.util.BurnInHelperKt.getBurnInOffset;
-import static com.android.systemui.doze.util.BurnInHelperKt.getBurnInProgressOffset;
import android.content.res.Configuration;
import android.content.res.Resources;
@@ -403,7 +402,6 @@ public class LockIconViewController extends ViewController<LockIconView> impleme
float offsetY = MathUtils.lerp(0f,
getBurnInOffset(mMaxBurnInOffsetY * 2, false /* xAxis */)
- mMaxBurnInOffsetY, mInterpolatedDarkAmount);
- float progress = MathUtils.lerp(0f, getBurnInProgressOffset(), mInterpolatedDarkAmount);
mView.setTranslationX(offsetX);
mView.setTranslationY(offsetY);
diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
index 9fab2ea34193..aaaa3f77924a 100644
--- a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
+++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
@@ -43,7 +43,6 @@ import android.graphics.drawable.Drawable;
import android.hardware.display.DisplayManager;
import android.hardware.graphics.common.AlphaInterpretation;
import android.hardware.graphics.common.DisplayDecorationSupport;
-import android.os.Build;
import android.os.Handler;
import android.os.SystemProperties;
import android.os.Trace;
@@ -73,7 +72,6 @@ import com.android.settingslib.Utils;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
-import com.android.systemui.decor.CutoutDecorProviderFactory;
import com.android.systemui.decor.DecorProvider;
import com.android.systemui.decor.DecorProviderFactory;
import com.android.systemui.decor.DecorProviderKt;
@@ -141,11 +139,13 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab
protected RoundedCornerResDelegate mRoundedCornerResDelegate;
@VisibleForTesting
protected DecorProviderFactory mRoundedCornerFactory;
- private CutoutDecorProviderFactory mCutoutFactory;
private int mProviderRefreshToken = 0;
@VisibleForTesting
protected OverlayWindow[] mOverlays = null;
@VisibleForTesting
+ @Nullable
+ DisplayCutoutView[] mCutoutViews;
+ @VisibleForTesting
ViewGroup mScreenDecorHwcWindow;
@VisibleForTesting
ScreenDecorHwcLayer mScreenDecorHwcLayer;
@@ -187,28 +187,17 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab
return;
}
- final int[] ids = {
- R.id.display_cutout,
- R.id.display_cutout_left,
- R.id.display_cutout_right,
- R.id.display_cutout_bottom
- };
- int setProtectionCnt = 0;
- for (int id: ids) {
- final View view = getOverlayView(id);
- if (!(view instanceof DisplayCutoutView)) {
- continue;
- }
- ++setProtectionCnt;
- final DisplayCutoutView dcv = (DisplayCutoutView) view;
- dcv.setProtection(protectionPath, bounds);
- dcv.enableShowProtection(true);
- }
- if (setProtectionCnt == 0) {
- if (Build.isDebuggable()) {
- throw new RuntimeException("CutoutView not initialized showCameraProtection");
- } else {
- Log.e(TAG, "CutoutView not initialized showCameraProtection");
+ if (mCutoutViews == null) {
+ Log.w(TAG, "DisplayCutoutView not initialized onApplyCameraProtection");
+ return;
+ }
+
+ // Show the extra protection around the front facing camera if necessary
+ for (DisplayCutoutView dcv : mCutoutViews) {
+ // Check Null since not all mCutoutViews[pos] be inflated at the meanwhile
+ if (dcv != null) {
+ dcv.setProtection(protectionPath, bounds);
+ dcv.enableShowProtection(true);
}
}
}
@@ -230,26 +219,15 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab
return;
}
- final int[] ids = {
- R.id.display_cutout,
- R.id.display_cutout_left,
- R.id.display_cutout_right,
- R.id.display_cutout_bottom
- };
- int setProtectionCnt = 0;
- for (int id: ids) {
- final View view = getOverlayView(id);
- if (!(view instanceof DisplayCutoutView)) {
- continue;
- }
- ++setProtectionCnt;
- ((DisplayCutoutView) view).enableShowProtection(false);
+ if (mCutoutViews == null) {
+ Log.w(TAG, "DisplayCutoutView not initialized onHideCameraProtection");
+ return;
}
- if (setProtectionCnt == 0) {
- if (Build.isDebuggable()) {
- throw new RuntimeException("CutoutView not initialized hideCameraProtection");
- } else {
- Log.e(TAG, "CutoutView not initialized hideCameraProtection");
+ // Go back to the regular anti-aliasing
+ for (DisplayCutoutView dcv : mCutoutViews) {
+ // Check Null since not all mCutoutViews[pos] be inflated at the meanwhile
+ if (dcv != null) {
+ dcv.enableShowProtection(false);
}
}
}
@@ -357,7 +335,6 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab
decorProviders.addAll(mFaceScanningFactory.getProviders());
if (!hasHwLayer) {
decorProviders.addAll(mRoundedCornerFactory.getProviders());
- decorProviders.addAll(mCutoutFactory.getProviders());
}
return decorProviders;
}
@@ -402,7 +379,6 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab
mRoundedCornerResDelegate.setPhysicalPixelDisplaySizeRatio(
getPhysicalPixelDisplaySizeRatio());
mRoundedCornerFactory = new RoundedCornerDecorProviderFactory(mRoundedCornerResDelegate);
- mCutoutFactory = getCutoutFactory();
mHwcScreenDecorationSupport = mContext.getDisplay().getDisplayDecorationSupport();
updateHwLayerRoundedCornerDrawable();
setupDecorations();
@@ -507,13 +483,18 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab
if (needToUpdateProviderViews) {
updateOverlayProviderViews(null);
} else {
- updateOverlayProviderViews(new Integer[] {
- mFaceScanningViewId,
- R.id.display_cutout,
- R.id.display_cutout_left,
- R.id.display_cutout_right,
- R.id.display_cutout_bottom,
- });
+ updateOverlayProviderViews(new Integer[] { mFaceScanningViewId });
+ }
+
+ if (mCutoutViews != null) {
+ final int size = mCutoutViews.length;
+ for (int i = 0; i < size; i++) {
+ final DisplayCutoutView cutoutView = mCutoutViews[i];
+ if (cutoutView == null) {
+ continue;
+ }
+ cutoutView.onDisplayChanged(newUniqueId);
+ }
}
if (mScreenDecorHwcLayer != null) {
@@ -526,9 +507,8 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab
updateConfiguration();
}
- @VisibleForTesting
@Nullable
- View getOverlayView(@IdRes int id) {
+ private View getOverlayView(@IdRes int id) {
if (mOverlays == null) {
return null;
}
@@ -585,18 +565,18 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab
removeHwcOverlay();
}
- boolean[] hasCreatedOverlay = new boolean[BOUNDS_POSITION_LENGTH];
+ final DisplayCutout cutout = getCutout();
final boolean shouldOptimizeVisibility = shouldOptimizeVisibility();
- Integer bound;
- while ((bound = DecorProviderKt.getProperBound(decorProviders)) != null) {
- hasCreatedOverlay[bound] = true;
- Pair<List<DecorProvider>, List<DecorProvider>> pair =
- DecorProviderKt.partitionAlignedBound(decorProviders, bound);
- decorProviders = pair.getSecond();
- createOverlay(bound, pair.getFirst(), shouldOptimizeVisibility);
- }
for (int i = 0; i < BOUNDS_POSITION_LENGTH; i++) {
- if (!hasCreatedOverlay[i]) {
+ if (shouldShowSwLayerCutout(i, cutout)
+ || shouldShowSwLayerFaceScan(i, cutout)
+ || shouldShowSwLayerRoundedCorner(i, cutout)
+ || shouldShowSwLayerPrivacyDot(i, cutout)) {
+ Pair<List<DecorProvider>, List<DecorProvider>> pair =
+ DecorProviderKt.partitionAlignedBound(decorProviders, i);
+ decorProviders = pair.getSecond();
+ createOverlay(i, pair.getFirst(), shouldOptimizeVisibility);
+ } else {
removeOverlay(i);
}
}
@@ -659,10 +639,9 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab
}
}
- // For unit test to override
- protected CutoutDecorProviderFactory getCutoutFactory() {
- return new CutoutDecorProviderFactory(mContext.getResources(),
- mContext.getDisplay());
+ @VisibleForTesting
+ DisplayCutout getCutout() {
+ return mContext.getDisplay().getCutout();
}
@VisibleForTesting
@@ -752,6 +731,16 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab
overlayView.setAlpha(0);
overlayView.setForceDarkAllowed(false);
+ // Only show cutout in mOverlays when hwc doesn't support screen decoration
+ if (mHwcScreenDecorationSupport == null) {
+ if (mCutoutViews == null) {
+ mCutoutViews = new DisplayCutoutView[BOUNDS_POSITION_LENGTH];
+ }
+ mCutoutViews[pos] = new DisplayCutoutView(mContext, pos);
+ overlayView.addView(mCutoutViews[pos]);
+ mCutoutViews[pos].updateRotation(mRotation);
+ }
+
mWindowManager.addView(overlayView, getWindowLayoutParams(pos));
overlayView.addOnLayoutChangeListener(new OnLayoutChangeListener() {
@@ -958,12 +947,27 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab
mTintColor = Color.RED;
}
+ if (mOverlays == null) {
+ return;
+ }
+
+ for (int i = 0; i < BOUNDS_POSITION_LENGTH; i++) {
+ if (mOverlays[i] == null) {
+ continue;
+ }
+ final ViewGroup overlayView = mOverlays[i].getRootView();
+ final int size = overlayView.getChildCount();
+ View child;
+ for (int j = 0; j < size; j++) {
+ child = overlayView.getChildAt(j);
+ if (child instanceof DisplayCutoutView && child.getId() == R.id.display_cutout) {
+ ((DisplayCutoutView) child).setColor(mTintColor);
+ }
+ }
+ }
+
updateOverlayProviderViews(new Integer[] {
mFaceScanningViewId,
- R.id.display_cutout,
- R.id.display_cutout_left,
- R.id.display_cutout_right,
- R.id.display_cutout_bottom,
R.id.rounded_corner_top_left,
R.id.rounded_corner_top_right,
R.id.rounded_corner_bottom_left,
@@ -1088,6 +1092,15 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab
updateHwLayerRoundedCornerDrawable();
}
updateLayoutParams();
+ // update cutout view rotation
+ if (mCutoutViews != null) {
+ for (final DisplayCutoutView cutoutView: mCutoutViews) {
+ if (cutoutView == null) {
+ continue;
+ }
+ cutoutView.updateRotation(mRotation);
+ }
+ }
// update all provider views inside overlay
updateOverlayProviderViews(null);
@@ -1106,6 +1119,46 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab
return mRoundedCornerFactory.getHasProviders();
}
+ private boolean isDefaultShownOverlayPos(@BoundsPosition int pos,
+ @Nullable DisplayCutout cutout) {
+ // for cutout is null or cutout with only waterfall.
+ final boolean emptyBoundsOrWaterfall = cutout == null || cutout.isBoundsEmpty();
+ // Shows rounded corner on left and right overlays only when there is no top or bottom
+ // cutout.
+ final int rotatedTop = getBoundPositionFromRotation(BOUNDS_POSITION_TOP, mRotation);
+ final int rotatedBottom = getBoundPositionFromRotation(BOUNDS_POSITION_BOTTOM, mRotation);
+ if (emptyBoundsOrWaterfall || !cutout.getBoundingRectsAll()[rotatedTop].isEmpty()
+ || !cutout.getBoundingRectsAll()[rotatedBottom].isEmpty()) {
+ return pos == BOUNDS_POSITION_TOP || pos == BOUNDS_POSITION_BOTTOM;
+ } else {
+ return pos == BOUNDS_POSITION_LEFT || pos == BOUNDS_POSITION_RIGHT;
+ }
+ }
+
+ private boolean shouldShowSwLayerRoundedCorner(@BoundsPosition int pos,
+ @Nullable DisplayCutout cutout) {
+ return hasRoundedCorners() && isDefaultShownOverlayPos(pos, cutout)
+ && mHwcScreenDecorationSupport == null;
+ }
+
+ private boolean shouldShowSwLayerPrivacyDot(@BoundsPosition int pos,
+ @Nullable DisplayCutout cutout) {
+ return isPrivacyDotEnabled() && isDefaultShownOverlayPos(pos, cutout);
+ }
+
+ private boolean shouldShowSwLayerFaceScan(@BoundsPosition int pos,
+ @Nullable DisplayCutout cutout) {
+ return mFaceScanningFactory.getHasProviders() && isDefaultShownOverlayPos(pos, cutout);
+ }
+
+ private boolean shouldShowSwLayerCutout(@BoundsPosition int pos,
+ @Nullable DisplayCutout cutout) {
+ final Rect[] bounds = cutout == null ? null : cutout.getBoundingRectsAll();
+ final int rotatedPos = getBoundPositionFromRotation(pos, mRotation);
+ return (bounds != null && !bounds[rotatedPos].isEmpty()
+ && mHwcScreenDecorationSupport == null);
+ }
+
private boolean shouldOptimizeVisibility() {
return (isPrivacyDotEnabled() || mFaceScanningFactory.getHasProviders())
&& (mHwcScreenDecorationSupport != null
@@ -1114,7 +1167,7 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab
}
private boolean shouldDrawCutout() {
- return mCutoutFactory.getHasProviders();
+ return shouldDrawCutout(mContext);
}
static boolean shouldDrawCutout(Context context) {
@@ -1230,6 +1283,7 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab
paint.setColor(mColor);
paint.setStyle(Paint.Style.FILL);
+ setId(R.id.display_cutout);
if (DEBUG) {
getViewTreeObserver().addOnDrawListener(() -> Log.i(TAG,
getWindowTitleByPos(pos) + " drawn in rot " + mRotation));
@@ -1237,9 +1291,6 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab
}
public void setColor(int color) {
- if (color == mColor) {
- return;
- }
mColor = color;
paint.setColor(mColor);
invalidate();
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIAppComponentFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIAppComponentFactory.java
index 714d267bb07d..527ce127820e 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIAppComponentFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIAppComponentFactory.java
@@ -16,160 +16,22 @@
package com.android.systemui;
-import android.app.Activity;
-import android.app.Application;
-import android.app.Service;
-import android.content.BroadcastReceiver;
-import android.content.ContentProvider;
import android.content.Context;
-import android.content.Intent;
-import android.util.Log;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.core.app.AppComponentFactory;
-
-import com.android.systemui.dagger.ContextComponentHelper;
-import com.android.systemui.dagger.SysUIComponent;
-
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-
-import javax.inject.Inject;
/**
- * Implementation of AppComponentFactory that injects into constructors.
+ * Starts up SystemUI using the AOSP {@link SystemUIInitializerImpl}.
*
- * This class sets up dependency injection when creating our application.
+ * This initializer relies on reflection to start everything up and should be considered deprecated.
+ * Instead, create your own {@link SystemUIAppComponentFactoryBase}, specify it in your
+ * AndroidManifest.xml and construct your own {@link SystemUIInitializer} directly.
*
- * Services support dependency injection into their constructors.
- *
- * ContentProviders support injection into member variables - _not_ constructors.
+ * @deprecated Define your own SystemUIAppComponentFactoryBase implementation and use that. This
+ * implementation may be changed or removed in future releases.
*/
-public class SystemUIAppComponentFactory extends AppComponentFactory {
-
- private static final String TAG = "AppComponentFactory";
- @Inject
- public ContextComponentHelper mComponentHelper;
-
- public SystemUIAppComponentFactory() {
- super();
- }
-
- @NonNull
+@Deprecated
+public class SystemUIAppComponentFactory extends SystemUIAppComponentFactoryBase {
@Override
- public Application instantiateApplicationCompat(
- @NonNull ClassLoader cl, @NonNull String className)
- throws InstantiationException, IllegalAccessException, ClassNotFoundException {
- Application app = super.instantiateApplicationCompat(cl, className);
- if (app instanceof ContextInitializer) {
- ((ContextInitializer) app).setContextAvailableCallback(
- context -> {
- SystemUIFactory.createFromConfig(context);
- SystemUIFactory.getInstance().getSysUIComponent().inject(
- SystemUIAppComponentFactory.this);
- }
- );
- }
-
- return app;
- }
-
- @NonNull
- @Override
- public ContentProvider instantiateProviderCompat(
- @NonNull ClassLoader cl, @NonNull String className)
- throws InstantiationException, IllegalAccessException, ClassNotFoundException {
-
- ContentProvider contentProvider = super.instantiateProviderCompat(cl, className);
- if (contentProvider instanceof ContextInitializer) {
- ((ContextInitializer) contentProvider).setContextAvailableCallback(
- context -> {
- SystemUIFactory.createFromConfig(context);
- SysUIComponent rootComponent =
- SystemUIFactory.getInstance().getSysUIComponent();
- try {
- Method injectMethod = rootComponent.getClass()
- .getMethod("inject", contentProvider.getClass());
- injectMethod.invoke(rootComponent, contentProvider);
- } catch (NoSuchMethodException
- | IllegalAccessException
- | InvocationTargetException e) {
- Log.w(TAG, "No injector for class: " + contentProvider.getClass(), e);
- }
- }
- );
- }
-
- return contentProvider;
- }
-
- @NonNull
- @Override
- public Activity instantiateActivityCompat(@NonNull ClassLoader cl, @NonNull String className,
- @Nullable Intent intent)
- throws InstantiationException, IllegalAccessException, ClassNotFoundException {
- if (mComponentHelper == null) {
- // This shouldn't happen, but is seen on occasion.
- // Bug filed against framework to take a look: http://b/141008541
- SystemUIFactory.getInstance().getSysUIComponent().inject(
- SystemUIAppComponentFactory.this);
- }
- Activity activity = mComponentHelper.resolveActivity(className);
- if (activity != null) {
- return activity;
- }
- return super.instantiateActivityCompat(cl, className, intent);
- }
-
- @NonNull
- @Override
- public Service instantiateServiceCompat(
- @NonNull ClassLoader cl, @NonNull String className, Intent intent)
- throws InstantiationException, IllegalAccessException, ClassNotFoundException {
- if (mComponentHelper == null) {
- // This shouldn't happen, but does when a device is freshly formatted.
- // Bug filed against framework to take a look: http://b/141008541
- SystemUIFactory.getInstance().getSysUIComponent().inject(
- SystemUIAppComponentFactory.this);
- }
- Service service = mComponentHelper.resolveService(className);
- if (service != null) {
- return service;
- }
- return super.instantiateServiceCompat(cl, className, intent);
- }
-
- @NonNull
- @Override
- public BroadcastReceiver instantiateReceiverCompat(@NonNull ClassLoader cl,
- @NonNull String className, @Nullable Intent intent)
- throws InstantiationException, IllegalAccessException, ClassNotFoundException {
- if (mComponentHelper == null) {
- // This shouldn't happen, but does when a device is freshly formatted.
- // Bug filed against framework to take a look: http://b/141008541
- SystemUIFactory.getInstance().getSysUIComponent().inject(
- SystemUIAppComponentFactory.this);
- }
- BroadcastReceiver receiver = mComponentHelper.resolveBroadcastReceiver(className);
- if (receiver != null) {
- return receiver;
- }
-
- return super.instantiateReceiverCompat(cl, className, intent);
- }
-
- /**
- * A callback that receives a Context when one is ready.
- */
- public interface ContextAvailableCallback {
- void onContextAvailable(Context context);
- }
-
- /**
- * Implemented in classes that get started by the system before a context is available.
- */
- public interface ContextInitializer {
- void setContextAvailableCallback(ContextAvailableCallback callback);
+ protected SystemUIInitializer createSystemUIInitializer(Context context) {
+ return SystemUIInitializerFactory.createWithContext(context);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIAppComponentFactoryBase.kt b/packages/SystemUI/src/com/android/systemui/SystemUIAppComponentFactoryBase.kt
new file mode 100644
index 000000000000..12108b01ab28
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIAppComponentFactoryBase.kt
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui
+
+import android.app.Activity
+import android.app.Application
+import android.app.Service
+import android.content.BroadcastReceiver
+import android.content.ContentProvider
+import android.content.Context
+import android.content.Intent
+import android.util.Log
+import androidx.core.app.AppComponentFactory
+import com.android.systemui.dagger.ContextComponentHelper
+import java.lang.reflect.InvocationTargetException
+import java.util.concurrent.ExecutionException
+import javax.inject.Inject
+
+/**
+ * Implementation of AppComponentFactory that injects into constructors.
+ *
+ * This class sets up dependency injection when creating our application.
+ *
+ * Activities, Services, and BroadcastReceivers support dependency injection into
+ * their constructors.
+ *
+ * ContentProviders support injection into member variables - _not_ constructors.
+ */
+abstract class SystemUIAppComponentFactoryBase : AppComponentFactory() {
+ companion object {
+ private const val TAG = "AppComponentFactory"
+ // Must be static due to http://b/141008541.
+ var systemUIInitializer: SystemUIInitializer? = null
+ }
+
+ @set:Inject
+ lateinit var componentHelper: ContextComponentHelper
+
+ /**
+ * Returns a new [SystemUIInitializer].
+ *
+ * The returned implementation should be specific to your build.
+ */
+ protected abstract fun createSystemUIInitializer(context: Context): SystemUIInitializer
+
+ private fun createSystemUIInitializerInternal(context: Context): SystemUIInitializer {
+ return systemUIInitializer ?: run {
+ val initializer = createSystemUIInitializer(context.applicationContext)
+ try {
+ initializer.init(false)
+ } catch (exception: ExecutionException) {
+ throw RuntimeException("Failed to initialize SysUI", exception)
+ } catch (exception: InterruptedException) {
+ throw RuntimeException("Failed to initialize SysUI", exception)
+ }
+ initializer.sysUIComponent.inject(
+ this@SystemUIAppComponentFactoryBase
+ )
+
+ systemUIInitializer = initializer
+ return initializer
+ }
+ }
+
+ override fun instantiateApplicationCompat(cl: ClassLoader, className: String): Application {
+ val app = super.instantiateApplicationCompat(cl, className)
+ if (app !is ContextInitializer) {
+ throw RuntimeException("App must implement ContextInitializer")
+ } else {
+ app.setContextAvailableCallback { context ->
+ createSystemUIInitializerInternal(context)
+ }
+ }
+
+ return app
+ }
+
+ override fun instantiateProviderCompat(cl: ClassLoader, className: String): ContentProvider {
+ val contentProvider = super.instantiateProviderCompat(cl, className)
+ if (contentProvider is ContextInitializer) {
+ contentProvider.setContextAvailableCallback { context ->
+ val initializer = createSystemUIInitializerInternal(context)
+ val rootComponent = initializer.sysUIComponent
+ try {
+ val injectMethod = rootComponent.javaClass
+ .getMethod("inject", contentProvider.javaClass)
+ injectMethod.invoke(rootComponent, contentProvider)
+ } catch (e: NoSuchMethodException) {
+ Log.w(TAG, "No injector for class: " + contentProvider.javaClass, e)
+ } catch (e: IllegalAccessException) {
+ Log.w(TAG, "No injector for class: " + contentProvider.javaClass, e)
+ } catch (e: InvocationTargetException) {
+ Log.w(TAG, "No injector for class: " + contentProvider.javaClass, e)
+ }
+ initializer
+ }
+ }
+ return contentProvider
+ }
+
+ override fun instantiateActivityCompat(
+ cl: ClassLoader,
+ className: String,
+ intent: Intent?
+ ): Activity {
+ if (!this::componentHelper.isInitialized) {
+ // This shouldn't happen, but is seen on occasion.
+ // Bug filed against framework to take a look: http://b/141008541
+ systemUIInitializer?.sysUIComponent?.inject(this@SystemUIAppComponentFactoryBase)
+ }
+ return componentHelper.resolveActivity(className)
+ ?: super.instantiateActivityCompat(cl, className, intent)
+ }
+
+ override fun instantiateServiceCompat(
+ cl: ClassLoader,
+ className: String,
+ intent: Intent?
+ ): Service {
+ if (!this::componentHelper.isInitialized) {
+ // This shouldn't happen, but does when a device is freshly formatted.
+ // Bug filed against framework to take a look: http://b/141008541
+ systemUIInitializer?.sysUIComponent?.inject(this@SystemUIAppComponentFactoryBase)
+ }
+ return componentHelper.resolveService(className)
+ ?: super.instantiateServiceCompat(cl, className, intent)
+ }
+
+ override fun instantiateReceiverCompat(
+ cl: ClassLoader,
+ className: String,
+ intent: Intent?
+ ): BroadcastReceiver {
+ if (!this::componentHelper.isInitialized) {
+ // This shouldn't happen, but does when a device is freshly formatted.
+ // Bug filed against framework to take a look: http://b/141008541
+ systemUIInitializer?.sysUIComponent?.inject(this@SystemUIAppComponentFactoryBase)
+ }
+ return componentHelper.resolveBroadcastReceiver(className)
+ ?: super.instantiateReceiverCompat(cl, className, intent)
+ }
+
+ /**
+ * An Interface for classes that can be notified when an Application Context becomes available.
+ *
+ * An instance of this will be passed to implementers of [ContextInitializer].
+ */
+ fun interface ContextAvailableCallback {
+ /** Notifies when the Application Context is available. */
+ fun onContextAvailable(context: Context): SystemUIInitializer
+ }
+
+ /**
+ * Interface for classes that can be constructed by the system before a context is available.
+ *
+ * This is intended for [Application] and [ContentProvider] implementations that
+ * either may not have a Context until some point after construction or are themselves
+ * a [Context].
+ *
+ * Implementers will be passed a [ContextAvailableCallback] that they should call as soon
+ * as an Application Context is ready.
+ */
+ interface ContextInitializer {
+ /**
+ * Called to supply the [ContextAvailableCallback] that should be called when an
+ * Application [Context] is available.
+ */
+ fun setContextAvailableCallback(callback: ContextAvailableCallback)
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
index 6d3fd503dff6..9138b2346ab8 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
@@ -42,7 +42,6 @@ import android.view.SurfaceControl;
import android.view.ThreadedRenderer;
import com.android.internal.protolog.common.ProtoLog;
-import com.android.systemui.dagger.ContextComponentHelper;
import com.android.systemui.dagger.GlobalRootComponent;
import com.android.systemui.dagger.SysUIComponent;
import com.android.systemui.dump.DumpManager;
@@ -65,7 +64,6 @@ public class SystemUIApplication extends Application implements
public static final String TAG = "SystemUIService";
private static final boolean DEBUG = false;
- private ContextComponentHelper mComponentHelper;
private BootCompleteCacheImpl mBootCompleteCache;
private DumpManager mDumpManager;
@@ -80,8 +78,8 @@ public class SystemUIApplication extends Application implements
private CoreStartable[] mServices;
private boolean mServicesStarted;
private SystemUIAppComponentFactory.ContextAvailableCallback mContextAvailableCallback;
- private GlobalRootComponent mRootComponent;
private SysUIComponent mSysUIComponent;
+ private SystemUIInitializer mInitializer;
public SystemUIApplication() {
super();
@@ -90,6 +88,10 @@ public class SystemUIApplication extends Application implements
ProtoLog.REQUIRE_PROTOLOGTOOL = false;
}
+ protected GlobalRootComponent getRootComponent() {
+ return mInitializer.getRootComponent();
+ }
+
@Override
public void onCreate() {
super.onCreate();
@@ -99,10 +101,8 @@ public class SystemUIApplication extends Application implements
TimingsTraceLog log = new TimingsTraceLog("SystemUIBootTiming",
Trace.TRACE_TAG_APP);
log.traceBegin("DependencyInjection");
- mContextAvailableCallback.onContextAvailable(this);
- mRootComponent = SystemUIFactory.getInstance().getRootComponent();
- mSysUIComponent = SystemUIFactory.getInstance().getSysUIComponent();
- mComponentHelper = mSysUIComponent.getContextComponentHelper();
+ mInitializer = mContextAvailableCallback.onContextAvailable(this);
+ mSysUIComponent = mInitializer.getSysUIComponent();
mBootCompleteCache = mSysUIComponent.provideBootCacheImpl();
log.traceEnd();
@@ -189,15 +189,14 @@ public class SystemUIApplication extends Application implements
*/
public void startServicesIfNeeded() {
- final String vendorComponent = SystemUIFactory.getInstance()
- .getVendorComponent(getResources());
+ final String vendorComponent = mInitializer.getVendorComponent(getResources());
// Sort the startables so that we get a deterministic ordering.
// TODO: make #start idempotent and require users of CoreStartable to call it.
Map<Class<?>, Provider<CoreStartable>> sortedStartables = new TreeMap<>(
Comparator.comparing(Class::getName));
- sortedStartables.putAll(SystemUIFactory.getInstance().getStartableComponents());
- sortedStartables.putAll(SystemUIFactory.getInstance().getStartableComponentsPerUser());
+ sortedStartables.putAll(mSysUIComponent.getStartables());
+ sortedStartables.putAll(mSysUIComponent.getPerUserStartables());
startServicesIfNeeded(
sortedStartables, "StartServices", vendorComponent);
}
@@ -212,7 +211,7 @@ public class SystemUIApplication extends Application implements
// Sort the startables so that we get a deterministic ordering.
Map<Class<?>, Provider<CoreStartable>> sortedStartables = new TreeMap<>(
Comparator.comparing(Class::getName));
- sortedStartables.putAll(SystemUIFactory.getInstance().getStartableComponentsPerUser());
+ sortedStartables.putAll(mSysUIComponent.getPerUserStartables());
startServicesIfNeeded(
sortedStartables, "StartSecondaryServices", null);
}
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIInitializer.java
index ca94b8cd05b7..5100c09912c8 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIInitializer.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -11,7 +11,7 @@
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
- * limitations under the License
+ * limitations under the License.
*/
package com.android.systemui;
@@ -22,8 +22,6 @@ import android.os.Handler;
import android.os.HandlerThread;
import android.util.Log;
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.systemui.dagger.DaggerGlobalRootComponent;
import com.android.systemui.dagger.GlobalRootComponent;
import com.android.systemui.dagger.SysUIComponent;
import com.android.systemui.dagger.WMComponent;
@@ -31,66 +29,47 @@ import com.android.systemui.util.InitializationChecker;
import com.android.wm.shell.dagger.WMShellConcurrencyModule;
import com.android.wm.shell.transition.ShellTransitions;
-import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ExecutionException;
-import javax.inject.Provider;
-
/**
- * Class factory to provide customizable SystemUI components.
+ * Initializer that stands up SystemUI.
+ *
+ * Implementations should override {@link #getGlobalRootComponentBuilder()} to fill in their own
+ * Dagger root component.
*/
-public class SystemUIFactory {
+public abstract class SystemUIInitializer {
private static final String TAG = "SystemUIFactory";
- static SystemUIFactory mFactory;
+ private final Context mContext;
+
private GlobalRootComponent mRootComponent;
private WMComponent mWMComponent;
private SysUIComponent mSysUIComponent;
private InitializationChecker mInitializationChecker;
- public static <T extends SystemUIFactory> T getInstance() {
- return (T) mFactory;
+ public SystemUIInitializer(Context context) {
+ mContext = context;
}
- public static void createFromConfig(Context context) {
- createFromConfig(context, false);
- }
-
- @VisibleForTesting
- public static void createFromConfig(Context context, boolean fromTest) {
- if (mFactory != null) {
- return;
- }
-
- final String clsName = context.getString(R.string.config_systemUIFactoryComponent);
- if (clsName == null || clsName.length() == 0) {
- throw new RuntimeException("No SystemUIFactory component configured");
- }
-
- try {
- Class<?> cls = null;
- cls = context.getClassLoader().loadClass(clsName);
- mFactory = (SystemUIFactory) cls.newInstance();
- mFactory.init(context, fromTest);
- } catch (Throwable t) {
- Log.w(TAG, "Error creating SystemUIFactory component: " + clsName, t);
- throw new RuntimeException(t);
- }
- }
+ protected abstract GlobalRootComponent.Builder getGlobalRootComponentBuilder();
- @VisibleForTesting
- static void cleanup() {
- mFactory = null;
+ /**
+ * Prepares the SysUIComponent builder before it is built.
+ * @param sysUIBuilder the builder provided by the root component's getSysUIComponent() method
+ * @param wm the built WMComponent from the root component's getWMComponent() method
+ */
+ protected SysUIComponent.Builder prepareSysUIComponentBuilder(
+ SysUIComponent.Builder sysUIBuilder, WMComponent wm) {
+ return sysUIBuilder;
}
- public SystemUIFactory() {}
-
- @VisibleForTesting
- public void init(Context context, boolean fromTest)
- throws ExecutionException, InterruptedException {
+ /**
+ * Starts the initialization process. This stands up the Dagger graph.
+ */
+ public void init(boolean fromTest) throws ExecutionException, InterruptedException {
mRootComponent = getGlobalRootComponentBuilder()
- .context(context)
+ .context(mContext)
.instrumentationTest(fromTest)
.build();
@@ -98,7 +77,7 @@ public class SystemUIFactory {
boolean initializeComponents = mInitializationChecker.initializeComponents();
// Stand up WMComponent
- setupWmComponent(context);
+ setupWmComponent(mContext);
if (initializeComponents) {
// Only initialize when not starting from tests since this currently initializes some
// components that shouldn't be run in the test environment
@@ -188,20 +167,6 @@ public class SystemUIFactory {
}
}
- /**
- * Prepares the SysUIComponent builder before it is built.
- * @param sysUIBuilder the builder provided by the root component's getSysUIComponent() method
- * @param wm the built WMComponent from the root component's getWMComponent() method
- */
- protected SysUIComponent.Builder prepareSysUIComponentBuilder(
- SysUIComponent.Builder sysUIBuilder, WMComponent wm) {
- return sysUIBuilder;
- }
-
- protected GlobalRootComponent.Builder getGlobalRootComponentBuilder() {
- return DaggerGlobalRootComponent.builder();
- }
-
public GlobalRootComponent getRootComponent() {
return mRootComponent;
}
@@ -215,23 +180,9 @@ public class SystemUIFactory {
}
/**
- * Returns the list of {@link CoreStartable} components that should be started at startup.
- */
- public Map<Class<?>, Provider<CoreStartable>> getStartableComponents() {
- return mSysUIComponent.getStartables();
- }
-
- /**
* Returns the list of additional system UI components that should be started.
*/
public String getVendorComponent(Resources resources) {
return resources.getString(R.string.config_systemUIVendorServiceComponent);
}
-
- /**
- * Returns the list of {@link CoreStartable} components that should be started per user.
- */
- public Map<Class<?>, Provider<CoreStartable>> getStartableComponentsPerUser() {
- return mSysUIComponent.getPerUserStartables();
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIInitializerFactory.kt b/packages/SystemUI/src/com/android/systemui/SystemUIInitializerFactory.kt
new file mode 100644
index 000000000000..b9454e8c3be8
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIInitializerFactory.kt
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui
+
+import android.annotation.SuppressLint
+import android.content.Context
+import android.util.Log
+import com.android.internal.annotations.VisibleForTesting
+import com.android.systemui.util.Assert
+
+/**
+ * Factory to reflectively lookup a [SystemUIInitializer] to start SystemUI with.
+ */
+@Deprecated("Provide your own {@link SystemUIAppComponentFactoryBase} that doesn't need this.")
+object SystemUIInitializerFactory {
+ private const val TAG = "SysUIInitializerFactory"
+ @SuppressLint("StaticFieldLeak")
+ private var initializer: SystemUIInitializer? = null
+
+ /**
+ * Instantiate a [SystemUIInitializer] reflectively.
+ */
+ @JvmStatic
+ fun createWithContext(context: Context): SystemUIInitializer {
+ return createFromConfig(context)
+ }
+
+ /**
+ * Instantiate a [SystemUIInitializer] reflectively.
+ */
+ @JvmStatic
+ private fun createFromConfig(context: Context): SystemUIInitializer {
+ Assert.isMainThread()
+
+ return createFromConfigNoAssert(context)
+ }
+
+ @JvmStatic
+ @VisibleForTesting
+ fun createFromConfigNoAssert(context: Context): SystemUIInitializer {
+
+ return initializer ?: run {
+ val className = context.getString(R.string.config_systemUIFactoryComponent)
+ if (className.isEmpty()) {
+ throw RuntimeException("No SystemUIFactory component configured")
+ }
+ try {
+ val cls = context.classLoader.loadClass(className)
+ val constructor = cls.getConstructor(Context::class.java)
+ (constructor.newInstance(context) as SystemUIInitializer).apply {
+ initializer = this
+ }
+ } catch (t: Throwable) {
+ Log.w(TAG, "Error creating SystemUIInitializer component: $className", t)
+ throw t
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIInitializerImpl.kt b/packages/SystemUI/src/com/android/systemui/SystemUIInitializerImpl.kt
new file mode 100644
index 000000000000..8920c928da09
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIInitializerImpl.kt
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui
+
+import android.content.Context
+import com.android.systemui.dagger.DaggerGlobalRootComponent
+import com.android.systemui.dagger.GlobalRootComponent
+
+/**
+ * {@link SystemUIInitializer} that stands up AOSP SystemUI.
+ */
+class SystemUIInitializerImpl(context: Context) : SystemUIInitializer(context) {
+ override fun getGlobalRootComponentBuilder(): GlobalRootComponent.Builder {
+ return DaggerGlobalRootComponent.builder()
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/camera/CameraGestureHelper.kt b/packages/SystemUI/src/com/android/systemui/camera/CameraGestureHelper.kt
index 4986fe85af19..99267e8ee1c9 100644
--- a/packages/SystemUI/src/com/android/systemui/camera/CameraGestureHelper.kt
+++ b/packages/SystemUI/src/com/android/systemui/camera/CameraGestureHelper.kt
@@ -125,6 +125,13 @@ class CameraGestureHelper @Inject constructor(
// launched from behind the lock-screen.
activityStarter.startActivity(intent, false /* dismissShade */)
}
+
+ // Call this to make sure that the keyguard returns if the app that is being launched
+ // crashes after a timeout.
+ centralSurfaces.startLaunchTransitionTimeout()
+ // Call this to make sure the keyguard is ready to be dismissed once the next intent is
+ // handled by the OS (in our case it is the activity we started right above)
+ centralSurfaces.readyForKeyguardDone()
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
index 3a1b12955647..550af7cafc75 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
@@ -21,7 +21,7 @@ import com.android.systemui.BootCompleteCacheImpl;
import com.android.systemui.CoreStartable;
import com.android.systemui.Dependency;
import com.android.systemui.InitController;
-import com.android.systemui.SystemUIAppComponentFactory;
+import com.android.systemui.SystemUIAppComponentFactoryBase;
import com.android.systemui.dagger.qualifiers.PerUser;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.keyguard.KeyguardSliceProvider;
@@ -241,7 +241,7 @@ public interface SysUIComponent {
/**
* Member injection into the supplied argument.
*/
- void inject(SystemUIAppComponentFactory factory);
+ void inject(SystemUIAppComponentFactoryBase factory);
/**
* Member injection into the supplied argument.
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
index ba1e057716f8..8cc952df47ed 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
@@ -26,7 +26,6 @@ import com.android.keyguard.clock.ClockModule;
import com.android.keyguard.dagger.KeyguardBouncerComponent;
import com.android.systemui.BootCompleteCache;
import com.android.systemui.BootCompleteCacheImpl;
-import com.android.systemui.SystemUIFactory;
import com.android.systemui.appops.dagger.AppOpsModule;
import com.android.systemui.assist.AssistModule;
import com.android.systemui.biometrics.AlternateUdfpsTouchProvider;
@@ -43,6 +42,7 @@ import com.android.systemui.flags.FlagsModule;
import com.android.systemui.fragments.FragmentService;
import com.android.systemui.log.dagger.LogModule;
import com.android.systemui.lowlightclock.LowLightClockController;
+import com.android.systemui.media.dagger.MediaProjectionModule;
import com.android.systemui.model.SysUiState;
import com.android.systemui.navigationbar.NavigationBarComponent;
import com.android.systemui.plugins.BcSmartspaceDataPlugin;
@@ -119,6 +119,7 @@ import dagger.Provides;
FalsingModule.class,
FlagsModule.class,
LogModule.class,
+ MediaProjectionModule.class,
PeopleHubModule.class,
PluginModule.class,
PrivacyModule.class,
@@ -196,11 +197,6 @@ public abstract class SystemUIModule {
@Binds
abstract SystemClock bindSystemClock(SystemClockImpl systemClock);
- @Provides
- static SystemUIFactory getSystemUIFactory() {
- return SystemUIFactory.getInstance();
- }
-
// TODO: This should provided by the WM component
/** Provides Optional of BubbleManager */
@SysUISingleton
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java
index 1570a7ebc0c4..f2f1798c94f6 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java
@@ -21,7 +21,7 @@ import android.os.HandlerThread;
import androidx.annotation.Nullable;
-import com.android.systemui.SystemUIFactory;
+import com.android.systemui.SystemUIInitializerFactory;
import com.android.systemui.tv.TvWMComponent;
import com.android.wm.shell.ShellCommandHandler;
import com.android.wm.shell.ShellInit;
@@ -52,7 +52,7 @@ import dagger.Subcomponent;
/**
* Dagger Subcomponent for WindowManager. This class explicitly describes the interfaces exported
* from the WM component into the SysUI component (in
- * {@link SystemUIFactory#init(Context, boolean)}), and references the specific dependencies
+ * {@link SystemUIInitializerFactory#init(Context, boolean)}), and references the specific dependencies
* provided by its particular device/form-factor SystemUI implementation.
*
* ie. {@link WMComponent} includes {@link WMShellModule}
diff --git a/packages/SystemUI/src/com/android/systemui/decor/CutoutDecorProviderFactory.kt b/packages/SystemUI/src/com/android/systemui/decor/CutoutDecorProviderFactory.kt
deleted file mode 100644
index cbed21cf65d6..000000000000
--- a/packages/SystemUI/src/com/android/systemui/decor/CutoutDecorProviderFactory.kt
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.decor
-
-import android.content.res.Resources
-import android.util.Log
-import android.view.Display
-import android.view.DisplayCutout
-import android.view.DisplayInfo
-
-class CutoutDecorProviderFactory constructor(
- private val res: Resources,
- private val display: Display?,
-) : DecorProviderFactory() {
-
- val displayInfo = DisplayInfo()
-
- override val hasProviders: Boolean
- get() {
- display?.getDisplayInfo(displayInfo) ?: run {
- Log.w(TAG, "display is null, can't update displayInfo")
- }
- return DisplayCutout.getFillBuiltInDisplayCutout(res, displayInfo.uniqueId)
- }
-
- override val providers: List<DecorProvider>
- get() {
- if (!hasProviders) {
- return emptyList()
- }
-
- return ArrayList<DecorProvider>().also { list ->
- // We need to update displayInfo before using it, but it has already updated during
- // accessing hasProviders field
- displayInfo.displayCutout?.getBoundBaseOnCurrentRotation()?.let { bounds ->
- for (bound in bounds) {
- list.add(
- CutoutDecorProviderImpl(bound.baseOnRotation0(displayInfo.rotation))
- )
- }
- }
- }
- }
-}
-
-private const val TAG = "CutoutDecorProviderFactory"
diff --git a/packages/SystemUI/src/com/android/systemui/decor/CutoutDecorProviderImpl.kt b/packages/SystemUI/src/com/android/systemui/decor/CutoutDecorProviderImpl.kt
deleted file mode 100644
index 991b54e8035e..000000000000
--- a/packages/SystemUI/src/com/android/systemui/decor/CutoutDecorProviderImpl.kt
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.decor
-
-import android.content.Context
-import android.view.DisplayCutout
-import android.view.Surface
-import android.view.View
-import android.view.ViewGroup
-import com.android.systemui.R
-import com.android.systemui.ScreenDecorations.DisplayCutoutView
-
-class CutoutDecorProviderImpl(
- @DisplayCutout.BoundsPosition override val alignedBound: Int
-) : BoundDecorProvider() {
-
- override val viewId: Int = when (alignedBound) {
- DisplayCutout.BOUNDS_POSITION_TOP -> R.id.display_cutout
- DisplayCutout.BOUNDS_POSITION_LEFT -> R.id.display_cutout_left
- DisplayCutout.BOUNDS_POSITION_RIGHT -> R.id.display_cutout_right
- else -> R.id.display_cutout_bottom
- }
-
- override fun inflateView(
- context: Context,
- parent: ViewGroup,
- @Surface.Rotation rotation: Int,
- tintColor: Int
- ): View {
- return DisplayCutoutView(context, alignedBound).also { view ->
- view.id = viewId
- view.setColor(tintColor)
- parent.addView(view)
- view.updateRotation(rotation)
- }
- }
-
- override fun onReloadResAndMeasure(
- view: View,
- reloadToken: Int,
- @Surface.Rotation rotation: Int,
- tintColor: Int,
- displayUniqueId: String?
- ) {
- (view as? DisplayCutoutView)?.let { cutoutView ->
- cutoutView.setColor(tintColor)
- cutoutView.updateRotation(rotation)
- cutoutView.onDisplayChanged(displayUniqueId)
- }
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/decor/DecorProvider.kt b/packages/SystemUI/src/com/android/systemui/decor/DecorProvider.kt
index 260c4b5a7830..de6d7278971c 100644
--- a/packages/SystemUI/src/com/android/systemui/decor/DecorProvider.kt
+++ b/packages/SystemUI/src/com/android/systemui/decor/DecorProvider.kt
@@ -32,7 +32,7 @@ abstract class DecorProvider {
abstract val viewId: Int
/** The number of total aligned bounds */
- val numOfAlignedBound: Int
+ val numOfAlignedEdge: Int
get() = alignedBounds.size
/** The aligned bounds for the view which is created through inflateView() */
@@ -57,8 +57,16 @@ abstract class DecorProvider {
@Surface.Rotation rotation: Int,
tintColor: Int
): View
+}
- override fun toString() = "${javaClass.simpleName}{alignedBounds=$alignedBounds}"
+/**
+ * Split list to 2 list, and return it back as Pair<>. The providers on the first list contains this
+ * alignedBound element. The providers on the second list do not contain this alignedBound element
+ */
+fun List<DecorProvider>.partitionAlignedBound(
+ @DisplayCutout.BoundsPosition alignedBound: Int
+): Pair<List<DecorProvider>, List<DecorProvider>> {
+ return partition { it.alignedBounds.contains(alignedBound) }
}
/**
@@ -86,60 +94,3 @@ abstract class BoundDecorProvider : DecorProvider() {
listOf(alignedBound)
}
}
-
-/**
- * Split list to 2 list, and return it back as Pair<>. The providers on the first list contains this
- * alignedBound element. The providers on the second list do not contain this alignedBound element
- */
-fun List<DecorProvider>.partitionAlignedBound(
- @DisplayCutout.BoundsPosition alignedBound: Int
-): Pair<List<DecorProvider>, List<DecorProvider>> {
- return partition { it.alignedBounds.contains(alignedBound) }
-}
-
-/**
- * Get the proper bound from DecorProvider list
- * Time complexity: O(N), N is the number of providers
- *
- * Choose order
- * 1. Return null if list is empty
- * 2. If list contains BoundDecorProvider, return its alignedBound[0] because it is a must-have
- * bound
- * 3. Return the bound with most DecorProviders
- */
-fun List<DecorProvider>.getProperBound(): Int? {
- // Return null if list is empty
- if (isEmpty()) {
- return null
- }
-
- // Choose alignedBounds[0] of BoundDecorProvider if any
- val singleBoundProvider = firstOrNull { it.numOfAlignedBound == 1 }
- if (singleBoundProvider != null) {
- return singleBoundProvider.alignedBounds[0]
- }
-
- // Return the bound with most DecorProviders
- val boundCount = intArrayOf(0, 0, 0, 0)
- for (provider in this) {
- for (bound in provider.alignedBounds) {
- boundCount[bound]++
- }
- }
- var maxCount = 0
- var maxCountBound: Int? = null
- val bounds = arrayOf(
- // Put top and bottom at first to get the highest priority to be chosen
- DisplayCutout.BOUNDS_POSITION_TOP,
- DisplayCutout.BOUNDS_POSITION_BOTTOM,
- DisplayCutout.BOUNDS_POSITION_LEFT,
- DisplayCutout.BOUNDS_POSITION_RIGHT
- )
- for (bound in bounds) {
- if (boundCount[bound] > maxCount) {
- maxCountBound = bound
- maxCount = boundCount[bound]
- }
- }
- return maxCountBound
-}
diff --git a/packages/SystemUI/src/com/android/systemui/decor/OverlayWindow.kt b/packages/SystemUI/src/com/android/systemui/decor/OverlayWindow.kt
index 45b8a08a9b45..dfb0b5aad912 100644
--- a/packages/SystemUI/src/com/android/systemui/decor/OverlayWindow.kt
+++ b/packages/SystemUI/src/com/android/systemui/decor/OverlayWindow.kt
@@ -114,8 +114,7 @@ class OverlayWindow(private val context: Context) {
pw.println(" rootView=$rootView")
for (i in 0 until rootView.childCount) {
val child = rootView.getChildAt(i)
- val provider = viewProviderMap[child.id]?.second
- pw.println(" child[$i]=$child $provider")
+ pw.println(" child[$i]=$child")
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index c6da7d9ccbcb..7abf2a8241bb 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -2701,7 +2701,7 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable,
/** Hides the surface behind the keyguard by re-showing the keyguard/activity lock screen. */
public void hideSurfaceBehindKeyguard() {
mSurfaceBehindRemoteAnimationRequested = false;
-
+ mKeyguardStateController.notifyKeyguardGoingAway(false);
if (mShowing) {
setShowingLocked(true, true);
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt
index 2f732de50ea1..458ed4059b3b 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt
@@ -144,8 +144,7 @@ class MediaHierarchyManager @Inject constructor(
animatedFraction)
// When crossfading, let's keep the bounds at the right location during fading
boundsProgress = if (animationCrossFadeProgress < 0.5f) 0.0f else 1.0f
- currentAlpha = calculateAlphaFromCrossFade(animationCrossFadeProgress,
- instantlyShowAtEnd = false)
+ currentAlpha = calculateAlphaFromCrossFade(animationCrossFadeProgress)
} else {
// If we're not crossfading, let's interpolate from the start alpha to 1.0f
currentAlpha = MathUtils.lerp(animationStartAlpha, 1.0f, animatedFraction)
@@ -276,7 +275,7 @@ class MediaHierarchyManager @Inject constructor(
if (value >= 0) {
updateTargetState()
// Setting the alpha directly, as the below call will use it to update the alpha
- carouselAlpha = calculateAlphaFromCrossFade(field, instantlyShowAtEnd = true)
+ carouselAlpha = calculateAlphaFromCrossFade(field)
applyTargetStateIfNotAnimating()
}
}
@@ -414,18 +413,10 @@ class MediaHierarchyManager @Inject constructor(
* @param crossFadeProgress The current cross fade progress. 0.5f means it's just switching
* between the start and the end location and the content is fully faded, while 0.75f means
* that we're halfway faded in again in the target state.
- *
- * @param instantlyShowAtEnd should the view be instantly shown at the end. This is needed
- * to avoid fadinging in when the target was hidden anyway.
*/
- private fun calculateAlphaFromCrossFade(
- crossFadeProgress: Float,
- instantlyShowAtEnd: Boolean
- ): Float {
+ private fun calculateAlphaFromCrossFade(crossFadeProgress: Float): Float {
if (crossFadeProgress <= 0.5f) {
return 1.0f - crossFadeProgress / 0.5f
- } else if (instantlyShowAtEnd) {
- return 1.0f
} else {
return (crossFadeProgress - 0.5f) / 0.5f
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaProjectionAppSelectorActivity.kt b/packages/SystemUI/src/com/android/systemui/media/MediaProjectionAppSelectorActivity.kt
new file mode 100644
index 000000000000..6802da347c93
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaProjectionAppSelectorActivity.kt
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.media
+
+import android.app.ActivityOptions
+import android.content.Intent
+import android.media.projection.IMediaProjection
+import android.media.projection.MediaProjectionManager.EXTRA_MEDIA_PROJECTION
+import android.os.Binder
+import android.os.Bundle
+import android.os.IBinder
+import android.view.View
+import com.android.internal.app.ChooserActivity
+import com.android.internal.app.chooser.NotSelectableTargetInfo
+import com.android.internal.app.chooser.TargetInfo
+import com.android.systemui.util.AsyncActivityLauncher
+import com.android.systemui.R;
+import javax.inject.Inject
+
+class MediaProjectionAppSelectorActivity @Inject constructor(
+ private val activityLauncher: AsyncActivityLauncher
+) : ChooserActivity() {
+
+ public override fun onCreate(bundle: Bundle?) {
+ val queryIntent = Intent(Intent.ACTION_MAIN)
+ .addCategory(Intent.CATEGORY_LAUNCHER)
+ intent.putExtra(Intent.EXTRA_INTENT, queryIntent)
+
+ // TODO(b/235465652) Use resource lexeme
+ intent.putExtra(Intent.EXTRA_TITLE, "Record or cast an app")
+
+ super.onCreate(bundle)
+
+ // TODO(b/235465652) we should update VisD of the title and add an icon
+ findViewById<View>(R.id.title)?.visibility = View.VISIBLE
+ }
+
+ override fun appliedThemeResId(): Int =
+ R.style.Theme_SystemUI_MediaProjectionAppSelector
+
+ override fun startSelected(which: Int, always: Boolean, filtered: Boolean) {
+ val currentListAdapter = mChooserMultiProfilePagerAdapter.activeListAdapter
+ val targetInfo = currentListAdapter.targetInfoForPosition(which, filtered) ?: return
+ if (targetInfo is NotSelectableTargetInfo) return
+
+ val intent = createIntent(targetInfo)
+
+ val launchToken: IBinder = Binder("media_projection_launch_token")
+ val activityOptions = ActivityOptions.makeBasic()
+ activityOptions.launchCookie = launchToken
+
+ val userHandle = mMultiProfilePagerAdapter.activeListAdapter.userHandle
+
+ // Launch activity asynchronously and wait for the result, launching of an activity
+ // is typically very fast, so we don't show any loaders.
+ // We wait for the activity to be launched to make sure that the window of the activity
+ // is created and ready to be captured.
+ val activityStarted = activityLauncher
+ .startActivityAsUser(intent, userHandle, activityOptions.toBundle()) {
+ onTargetActivityLaunched(launchToken)
+ }
+
+ // Rely on the ActivityManager to pop up a dialog regarding app suspension
+ // and return false if suspended
+ if (!targetInfo.isSuspended && activityStarted) {
+ // TODO(b/222078415) track activity launch
+ }
+ }
+
+ private fun createIntent(target: TargetInfo): Intent {
+ val intent = Intent(target.resolvedIntent)
+
+ // Launch the app in a new task, so it won't be in the host's app task
+ intent.flags = intent.flags or Intent.FLAG_ACTIVITY_NEW_TASK
+
+ // Remove activity forward result flag as this activity will
+ // return the media projection session
+ intent.flags = intent.flags and Intent.FLAG_ACTIVITY_FORWARD_RESULT.inv()
+
+ return intent
+ }
+
+ override fun onDestroy() {
+ activityLauncher.destroy()
+ super.onDestroy()
+ }
+
+ override fun onActivityStarted(cti: TargetInfo) {
+ // do nothing
+ }
+
+ private fun onTargetActivityLaunched(launchToken: IBinder) {
+ val mediaProjectionBinder = intent.getIBinderExtra(EXTRA_MEDIA_PROJECTION)
+ val projection = IMediaProjection.Stub.asInterface(mediaProjectionBinder)
+
+ projection.launchCookie = launchToken
+
+ val intent = Intent()
+ intent.putExtra(EXTRA_MEDIA_PROJECTION, projection.asBinder())
+ setResult(RESULT_OK, intent)
+ setForceSendResultForMediaProjection()
+ finish()
+ }
+
+ override fun shouldGetOnlyDefaultActivities() = false
+}
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java b/packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java
index 38604091c409..397bffcaa64c 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java
@@ -40,7 +40,10 @@ import android.text.style.StyleSpan;
import android.util.Log;
import android.view.Window;
+import com.android.systemui.Dependency;
import com.android.systemui.R;
+import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.flags.Flags;
import com.android.systemui.statusbar.phone.SystemUIDialog;
import com.android.systemui.util.Utils;
@@ -53,6 +56,7 @@ public class MediaProjectionPermissionActivity extends Activity
private String mPackageName;
private int mUid;
private IMediaProjectionManager mService;
+ private FeatureFlags mFeatureFlags;
private AlertDialog mDialog;
@@ -60,6 +64,7 @@ public class MediaProjectionPermissionActivity extends Activity
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
+ mFeatureFlags = Dependency.get(FeatureFlags.class);
mPackageName = getCallingPackage();
IBinder b = ServiceManager.getService(MEDIA_PROJECTION_SERVICE);
mService = IMediaProjectionManager.Stub.asInterface(b);
@@ -141,14 +146,22 @@ public class MediaProjectionPermissionActivity extends Activity
dialogTitle = getString(R.string.media_projection_dialog_title, appName);
}
- mDialog = new AlertDialog.Builder(this, R.style.Theme_SystemUI_Dialog)
+ AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(this,
+ R.style.Theme_SystemUI_Dialog)
.setTitle(dialogTitle)
.setIcon(R.drawable.ic_media_projection_permission)
.setMessage(dialogText)
.setPositiveButton(R.string.media_projection_action_text, this)
.setNeutralButton(android.R.string.cancel, this)
- .setOnCancelListener(this)
- .create();
+ .setOnCancelListener(this);
+
+ if (isPartialScreenSharingEnabled()) {
+ // This is a temporary entry point before we have a new permission dialog
+ // TODO(b/233183090): this activity should be redesigned to have a dropdown selector
+ dialogBuilder.setNegativeButton("App", this);
+ }
+
+ mDialog = dialogBuilder.create();
SystemUIDialog.registerDismissListener(mDialog);
SystemUIDialog.applyFlags(mDialog);
@@ -177,6 +190,15 @@ public class MediaProjectionPermissionActivity extends Activity
if (which == AlertDialog.BUTTON_POSITIVE) {
setResult(RESULT_OK, getMediaProjectionIntent(mUid, mPackageName));
}
+
+ if (isPartialScreenSharingEnabled() && which == AlertDialog.BUTTON_NEGATIVE) {
+ IMediaProjection projection = createProjection(mUid, mPackageName);
+ final Intent intent = new Intent(this, MediaProjectionAppSelectorActivity.class);
+ intent.putExtra(MediaProjectionManager.EXTRA_MEDIA_PROJECTION,
+ projection.asBinder());
+ intent.setFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
+ startActivity(intent);
+ }
} catch (RemoteException e) {
Log.e(TAG, "Error granting projection permission", e);
setResult(RESULT_CANCELED);
@@ -188,10 +210,14 @@ public class MediaProjectionPermissionActivity extends Activity
}
}
+ private IMediaProjection createProjection(int uid, String packageName) throws RemoteException {
+ return mService.createProjection(uid, packageName,
+ MediaProjectionManager.TYPE_SCREEN_CAPTURE, false /* permanentGrant */);
+ }
+
private Intent getMediaProjectionIntent(int uid, String packageName)
throws RemoteException {
- IMediaProjection projection = mService.createProjection(uid, packageName,
- MediaProjectionManager.TYPE_SCREEN_CAPTURE, false /* permanentGrant */);
+ IMediaProjection projection = createProjection(uid, packageName);
Intent intent = new Intent();
intent.putExtra(MediaProjectionManager.EXTRA_MEDIA_PROJECTION, projection.asBinder());
return intent;
@@ -201,4 +227,8 @@ public class MediaProjectionPermissionActivity extends Activity
public void onCancel(DialogInterface dialog) {
finish();
}
+
+ private boolean isPartialScreenSharingEnabled() {
+ return mFeatureFlags.isEnabled(Flags.WM_ENABLE_PARTIAL_SCREEN_SHARING);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/dagger/MediaProjectionModule.kt b/packages/SystemUI/src/com/android/systemui/media/dagger/MediaProjectionModule.kt
new file mode 100644
index 000000000000..e33a1b909d48
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/media/dagger/MediaProjectionModule.kt
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.media.dagger
+
+import android.app.Activity
+import com.android.systemui.media.MediaProjectionAppSelectorActivity
+import dagger.Binds
+import dagger.Module
+import dagger.multibindings.ClassKey
+import dagger.multibindings.IntoMap
+
+@Module
+abstract class MediaProjectionModule {
+
+ @Binds
+ @IntoMap
+ @ClassKey(MediaProjectionAppSelectorActivity::class)
+ abstract fun provideMediaProjectionAppSelectorActivity(
+ activity: MediaProjectionAppSelectorActivity): Activity
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/people/PeopleProvider.java b/packages/SystemUI/src/com/android/systemui/people/PeopleProvider.java
index b55d86e8fb1c..0ba077eb0912 100644
--- a/packages/SystemUI/src/com/android/systemui/people/PeopleProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/people/PeopleProvider.java
@@ -29,7 +29,8 @@ import android.os.UserHandle;
import android.util.Log;
import android.widget.RemoteViews;
-import com.android.systemui.SystemUIAppComponentFactory;
+import com.android.systemui.SystemUIAppComponentFactoryBase.ContextAvailableCallback;
+import com.android.systemui.SystemUIAppComponentFactoryBase.ContextInitializer;
import com.android.systemui.people.widget.PeopleSpaceWidgetManager;
import com.android.systemui.shared.system.PeopleProviderUtils;
@@ -37,11 +38,11 @@ import javax.inject.Inject;
/** API that returns a People Tile preview. */
public class PeopleProvider extends ContentProvider implements
- SystemUIAppComponentFactory.ContextInitializer {
+ ContextInitializer {
private static final String TAG = "PeopleProvider";
private static final boolean DEBUG = PeopleSpaceUtils.DEBUG;
private static final String EMPTY_STRING = "";
- private SystemUIAppComponentFactory.ContextAvailableCallback mCallback;
+ private ContextAvailableCallback mCallback;
@Inject
PeopleSpaceWidgetManager mPeopleSpaceWidgetManager;
@@ -144,7 +145,7 @@ public class PeopleProvider extends ContentProvider implements
@Override
public void setContextAvailableCallback(
- SystemUIAppComponentFactory.ContextAvailableCallback callback) {
+ ContextAvailableCallback callback) {
mCallback = callback;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/user/UserSwitchDialogController.kt b/packages/SystemUI/src/com/android/systemui/qs/user/UserSwitchDialogController.kt
index 260a3714a368..bdcc6b0b2a57 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/user/UserSwitchDialogController.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/user/UserSwitchDialogController.kt
@@ -128,15 +128,16 @@ class UserSwitchDialogController @VisibleForTesting constructor(
private val animateFrom: Dialog,
private val dialogLaunchAnimator: DialogLaunchAnimator
) : DialogInterface by animateFrom, DialogShower {
- override fun showDialog(dialog: Dialog) {
+ override fun showDialog(dialog: Dialog, cuj: DialogCuj) {
dialogLaunchAnimator.showFromDialog(
dialog,
- animateFrom = animateFrom
+ animateFrom = animateFrom,
+ cuj
)
}
}
interface DialogShower : DialogInterface {
- fun showDialog(dialog: Dialog)
+ fun showDialog(dialog: Dialog, cuj: DialogCuj)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotifications.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotifications.kt
index 5aeab84b677c..d24896148095 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotifications.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotifications.kt
@@ -31,7 +31,6 @@ import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.collection.inflation.BindEventManager
-import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy
import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
@@ -129,11 +128,9 @@ class AnimatedImageNotificationManager @Inject constructor(
*/
@SysUISingleton
class ConversationNotificationManager @Inject constructor(
- private val bindEventManager: BindEventManager,
- private val notificationGroupManager: NotificationGroupManagerLegacy,
+ bindEventManager: BindEventManager,
private val context: Context,
private val notifCollection: CommonNotifCollection,
- private val featureFlags: NotifPipelineFlags,
@Main private val mainHandler: Handler
) {
// Need this state to be thread safe, since it's accessed from the ui thread
@@ -172,12 +169,10 @@ class ConversationNotificationManager @Inject constructor(
layout.setIsImportantConversation(important, false)
}
}
- if (changed && !featureFlags.isNewPipelineEnabled()) {
- notificationGroupManager.updateIsolation(entry)
- }
}
}
}
+
fun onEntryViewBound(entry: NotificationEntry) {
if (!entry.ranking.isConversation) {
return
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
index c9c7fe9e0ab6..27a7cd779405 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
@@ -226,10 +226,8 @@ public interface NotificationsModule {
static NotificationLogger provideNotificationLogger(
NotificationListener notificationListener,
@UiBackground Executor uiBgExecutor,
- NotifPipelineFlags notifPipelineFlags,
NotifLiveDataStore notifLiveDataStore,
NotificationVisibilityProvider visibilityProvider,
- NotificationEntryManager entryManager,
NotifPipeline notifPipeline,
StatusBarStateController statusBarStateController,
NotificationLogger.ExpansionStateLogger expansionStateLogger,
@@ -237,10 +235,8 @@ public interface NotificationsModule {
return new NotificationLogger(
notificationListener,
uiBgExecutor,
- notifPipelineFlags,
notifLiveDataStore,
visibilityProvider,
- entryManager,
notifPipeline,
statusBarStateController,
expansionStateLogger,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java
index 8378b69bee9a..2dd95a3cbab8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java
@@ -294,11 +294,6 @@ public class NotificationInterruptStateProviderImpl implements NotificationInter
* @return true if these checks pass, false if the notification should not alert
*/
private boolean canAlertCommon(NotificationEntry entry) {
- if (!mFlags.isNewPipelineEnabled() && mNotificationFilter.shouldFilterOut(entry)) {
- mLogger.logNoAlertingFilteredOut(entry);
- return false;
- }
-
for (int i = 0; i < mSuppressors.size(); i++) {
if (mSuppressors.get(i).suppressInterruptions(entry)) {
mLogger.logNoAlertingSuppressedBy(entry, mSuppressors.get(i), /* awake */ false);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java
index 9fbd5c39dedd..639187790ae0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java
@@ -22,7 +22,6 @@ import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.Trace;
import android.service.notification.NotificationListenerService;
-import android.service.notification.StatusBarNotification;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Log;
@@ -39,9 +38,6 @@ import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener;
import com.android.systemui.statusbar.NotificationListener;
import com.android.systemui.statusbar.StatusBarState;
-import com.android.systemui.statusbar.notification.NotifPipelineFlags;
-import com.android.systemui.statusbar.notification.NotificationEntryListener;
-import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.collection.NotifLiveDataStore;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
@@ -80,7 +76,6 @@ public class NotificationLogger implements StateListener {
private final Executor mUiBgExecutor;
private final NotifLiveDataStore mNotifLiveDataStore;
private final NotificationVisibilityProvider mVisibilityProvider;
- private final NotificationEntryManager mEntryManager;
private final NotifPipeline mNotifPipeline;
private final NotificationPanelLogger mNotificationPanelLogger;
private final ExpansionStateLogger mExpansionStateLogger;
@@ -220,10 +215,8 @@ public class NotificationLogger implements StateListener {
*/
public NotificationLogger(NotificationListener notificationListener,
@UiBackground Executor uiBgExecutor,
- NotifPipelineFlags notifPipelineFlags,
NotifLiveDataStore notifLiveDataStore,
NotificationVisibilityProvider visibilityProvider,
- NotificationEntryManager entryManager,
NotifPipeline notifPipeline,
StatusBarStateController statusBarStateController,
ExpansionStateLogger expansionStateLogger,
@@ -232,7 +225,6 @@ public class NotificationLogger implements StateListener {
mUiBgExecutor = uiBgExecutor;
mNotifLiveDataStore = notifLiveDataStore;
mVisibilityProvider = visibilityProvider;
- mEntryManager = entryManager;
mNotifPipeline = notifPipeline;
mBarService = IStatusBarService.Stub.asInterface(
ServiceManager.getService(Context.STATUS_BAR_SERVICE));
@@ -241,36 +233,7 @@ public class NotificationLogger implements StateListener {
// Not expected to be destroyed, don't need to unsubscribe
statusBarStateController.addCallback(this);
- if (notifPipelineFlags.isNewPipelineEnabled()) {
- registerNewPipelineListener();
- } else {
- registerLegacyListener();
- }
- }
-
- private void registerLegacyListener() {
- mEntryManager.addNotificationEntryListener(new NotificationEntryListener() {
- @Override
- public void onEntryRemoved(
- NotificationEntry entry,
- NotificationVisibility visibility,
- boolean removedByUser,
- int reason) {
- mExpansionStateLogger.onEntryRemoved(entry.getKey());
- }
-
- @Override
- public void onPreEntryUpdated(NotificationEntry entry) {
- mExpansionStateLogger.onEntryUpdated(entry.getKey());
- }
-
- @Override
- public void onInflationError(
- StatusBarNotification notification,
- Exception exception) {
- logNotificationError(notification, exception);
- }
- });
+ registerNewPipelineListener();
}
private void registerNewPipelineListener() {
@@ -333,26 +296,6 @@ public class NotificationLogger implements StateListener {
}
}
- /**
- * Logs Notification inflation error
- */
- private void logNotificationError(
- StatusBarNotification notification,
- Exception exception) {
- try {
- mBarService.onNotificationError(
- notification.getPackageName(),
- notification.getTag(),
- notification.getId(),
- notification.getUid(),
- notification.getInitialPid(),
- exception.getMessage(),
- notification.getUserId());
- } catch (RemoteException ex) {
- // The end is nigh.
- }
- }
-
private void logNotificationVisibilityChanges(
Collection<NotificationVisibility> newlyVisible,
Collection<NotificationVisibility> noLongerVisible) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
index 52c04b9de29a..a8913bfbefa6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -89,7 +89,6 @@ public class KeyguardBottomAreaView extends FrameLayout {
private ActivityStarter mActivityStarter;
private KeyguardStateController mKeyguardStateController;
- private CentralSurfaces mCentralSurfaces;
private FalsingManager mFalsingManager;
private boolean mDozing;
@@ -139,9 +138,38 @@ public class KeyguardBottomAreaView extends FrameLayout {
super(context, attrs, defStyleAttr, defStyleRes);
}
- public void initFrom(KeyguardBottomAreaView oldBottomArea) {
- setCentralSurfaces(oldBottomArea.mCentralSurfaces);
+ /** Initializes the {@link KeyguardBottomAreaView} with the given dependencies */
+ public void init(
+ FalsingManager falsingManager,
+ QuickAccessWalletController controller,
+ ControlsComponent controlsComponent,
+ QRCodeScannerController qrCodeScannerController) {
+ mFalsingManager = falsingManager;
+ mQuickAccessWalletController = controller;
+ mQuickAccessWalletController.setupWalletChangeObservers(
+ mCardRetriever, WALLET_PREFERENCE_CHANGE, DEFAULT_PAYMENT_APP_CHANGE);
+ mQuickAccessWalletController.updateWalletPreference();
+ mQuickAccessWalletController.queryWalletCards(mCardRetriever);
+ updateWalletVisibility();
+
+ mControlsComponent = controlsComponent;
+ mControlsComponent.getControlsListingController().ifPresent(
+ c -> c.addCallback(mListingCallback));
+
+ mQRCodeScannerController = qrCodeScannerController;
+ mQRCodeScannerController.registerQRCodeScannerChangeObservers(
+ QRCodeScannerController.DEFAULT_QR_CODE_SCANNER_CHANGE,
+ QRCodeScannerController.QR_CODE_SCANNER_PREFERENCE_CHANGE);
+ updateQRCodeButtonVisibility();
+
+ updateAffordanceColors();
+ }
+ /**
+ * Initializes this instance of {@link KeyguardBottomAreaView} based on the given instance of
+ * another {@link KeyguardBottomAreaView}
+ */
+ public void initFrom(KeyguardBottomAreaView oldBottomArea) {
// if it exists, continue to use the original ambient indication container
// instead of the newly inflated one
if (mAmbientIndicationArea != null) {
@@ -268,10 +296,6 @@ public class KeyguardBottomAreaView extends FrameLayout {
updateAffordanceColors();
}
- public void setCentralSurfaces(CentralSurfaces centralSurfaces) {
- mCentralSurfaces = centralSurfaces;
- }
-
private void updateWalletVisibility() {
if (mDozing
|| mQuickAccessWalletController == null
@@ -332,7 +356,7 @@ public class KeyguardBottomAreaView extends FrameLayout {
return false;
}
- public void startFinishDozeAnimation() {
+ private void startFinishDozeAnimation() {
long delay = 0;
if (mWalletButton.getVisibility() == View.VISIBLE) {
startFinishDozeAnimationElement(mWalletButton, delay);
@@ -415,38 +439,6 @@ public class KeyguardBottomAreaView extends FrameLayout {
return insets;
}
- /** Set the falsing manager */
- public void setFalsingManager(FalsingManager falsingManager) {
- mFalsingManager = falsingManager;
- }
-
- /**
- * Initialize the wallet feature, only enabling if the feature is enabled within the platform.
- */
- public void initWallet(
- QuickAccessWalletController controller) {
- mQuickAccessWalletController = controller;
- mQuickAccessWalletController.setupWalletChangeObservers(
- mCardRetriever, WALLET_PREFERENCE_CHANGE, DEFAULT_PAYMENT_APP_CHANGE);
- mQuickAccessWalletController.updateWalletPreference();
- mQuickAccessWalletController.queryWalletCards(mCardRetriever);
-
- updateWalletVisibility();
- updateAffordanceColors();
- }
-
- /**
- * Initialize the qr code scanner feature, controlled by QRCodeScannerController.
- */
- public void initQRCodeScanner(QRCodeScannerController qrCodeScannerController) {
- mQRCodeScannerController = qrCodeScannerController;
- mQRCodeScannerController.registerQRCodeScannerChangeObservers(
- QRCodeScannerController.DEFAULT_QR_CODE_SCANNER_CHANGE,
- QRCodeScannerController.QR_CODE_SCANNER_PREFERENCE_CHANGE);
- updateQRCodeButtonVisibility();
- updateAffordanceColors();
- }
-
private void updateQRCodeButtonVisibility() {
if (mQuickAccessWalletController != null
&& mQuickAccessWalletController.isWalletEnabled()) {
@@ -502,17 +494,6 @@ public class KeyguardBottomAreaView extends FrameLayout {
mQRCodeScannerButton.setBackgroundTintList(bgColor);
}
- /**
- * Initialize controls via the ControlsComponent
- */
- public void initControls(ControlsComponent controlsComponent) {
- mControlsComponent = controlsComponent;
- mControlsComponent.getControlsListingController().ifPresent(
- c -> c.addCallback(mListingCallback));
-
- updateAffordanceColors();
- }
-
private void onWalletClick(View v) {
// More coming here; need to inform the user about how to proceed
if (mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
index 5810d64a8bbc..dcc02b44806b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -40,8 +40,6 @@ import static com.android.systemui.statusbar.phone.panelstate.PanelExpansionStat
import static com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManagerKt.STATE_OPENING;
import static com.android.systemui.util.DumpUtilsKt.asIndenting;
-import static java.lang.Float.isNaN;
-
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
@@ -50,13 +48,13 @@ import android.app.ActivityManager;
import android.app.Fragment;
import android.app.StatusBarManager;
import android.content.ContentResolver;
-import android.content.res.Resources;
import android.database.ContentObserver;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorFilter;
import android.graphics.Insets;
import android.graphics.Paint;
+import android.graphics.PixelFormat;
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.Region;
@@ -79,6 +77,7 @@ import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
+import android.view.View.AccessibilityDelegate;
import android.view.ViewGroup;
import android.view.ViewPropertyAnimator;
import android.view.ViewStub;
@@ -195,7 +194,6 @@ import com.android.systemui.util.Compile;
import com.android.systemui.util.LargeScreenUtils;
import com.android.systemui.util.ListenerSet;
import com.android.systemui.util.Utils;
-import com.android.systemui.util.settings.SecureSettings;
import com.android.systemui.util.time.SystemClock;
import com.android.systemui.wallet.controller.QuickAccessWalletController;
import com.android.wm.shell.animation.FlingAnimationUtils;
@@ -207,14 +205,13 @@ import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
-import java.util.concurrent.Executor;
import java.util.function.Consumer;
import javax.inject.Inject;
import javax.inject.Provider;
@CentralSurfacesComponent.CentralSurfacesScope
-public class NotificationPanelViewController extends PanelViewController {
+public final class NotificationPanelViewController extends PanelViewController {
private static final boolean DEBUG_LOGCAT = Compile.IS_DEBUG && Log.isLoggable(TAG, Log.DEBUG);
private static final boolean SPEW_LOGCAT = Compile.IS_DEBUG && Log.isLoggable(TAG, Log.VERBOSE);
@@ -260,7 +257,8 @@ public class NotificationPanelViewController extends PanelViewController {
private final ConfigurationListener mConfigurationListener = new ConfigurationListener();
private final SettingsChangeObserver mSettingsChangeObserver;
- @VisibleForTesting final StatusBarStateListener mStatusBarStateListener =
+ @VisibleForTesting
+ final StatusBarStateListener mStatusBarStateListener =
new StatusBarStateListener();
private final NotificationPanelView mView;
private final VibratorHelper mVibratorHelper;
@@ -332,19 +330,20 @@ public class NotificationPanelViewController extends PanelViewController {
private KeyguardUserSwitcherController mKeyguardUserSwitcherController;
private KeyguardStatusBarView mKeyguardStatusBar;
private KeyguardStatusBarViewController mKeyguardStatusBarViewController;
- @VisibleForTesting QS mQs;
+ @VisibleForTesting
+ QS mQs;
private FrameLayout mQsFrame;
- private QsFrameTranslateController mQsFrameTranslateController;
+ private final QsFrameTranslateController mQsFrameTranslateController;
private KeyguardStatusViewController mKeyguardStatusViewController;
- private LockIconViewController mLockIconViewController;
+ private final LockIconViewController mLockIconViewController;
private NotificationsQuickSettingsContainer mNotificationContainerParent;
- private NotificationsQSContainerController mNotificationsQSContainerController;
+ private final NotificationsQSContainerController mNotificationsQSContainerController;
private final Provider<KeyguardBottomAreaViewController>
mKeyguardBottomAreaViewControllerProvider;
private boolean mAnimateNextPositionUpdate;
private float mQuickQsHeaderHeight;
- private ScreenOffAnimationController mScreenOffAnimationController;
- private UnlockedScreenOffAnimationController mUnlockedScreenOffAnimationController;
+ private final ScreenOffAnimationController mScreenOffAnimationController;
+ private final UnlockedScreenOffAnimationController mUnlockedScreenOffAnimationController;
private int mTrackingPointer;
private VelocityTracker mQsVelocityTracker;
@@ -397,12 +396,6 @@ public class NotificationPanelViewController extends PanelViewController {
private int mLargeScreenShadeHeaderHeight;
private int mSplitShadeNotificationsScrimMarginBottom;
- /**
- * Vertical overlap allowed between the bottom of the notification shelf and
- * the top of the lock icon or the under-display fingerprint sensor background.
- */
- private int mShelfAndLockIconOverlap;
-
private final KeyguardClockPositionAlgorithm
mClockPositionAlgorithm =
new KeyguardClockPositionAlgorithm();
@@ -417,7 +410,8 @@ public class NotificationPanelViewController extends PanelViewController {
* Determines if QS should be already expanded when expanding shade.
* Used for split shade, two finger gesture as well as accessibility shortcut to QS.
*/
- @VisibleForTesting boolean mQsExpandImmediate;
+ @VisibleForTesting
+ boolean mQsExpandImmediate;
private boolean mTwoFingerQsExpandPossible;
private String mHeaderDebugInfo;
@@ -439,14 +433,13 @@ public class NotificationPanelViewController extends PanelViewController {
private int mNavigationBarBottomHeight;
private boolean mExpandingFromHeadsUp;
private boolean mCollapsedOnDown;
- private int mPositionMinSideMargin;
private boolean mClosingWithAlphaFadeOut;
private boolean mHeadsUpAnimatingAway;
private boolean mLaunchingAffordance;
private final FalsingManager mFalsingManager;
private final FalsingCollector mFalsingCollector;
- private Runnable mHeadsUpExistenceChangedRunnable = () -> {
+ private final Runnable mHeadsUpExistenceChangedRunnable = () -> {
setHeadsUpAnimatingAway(false);
updatePanelExpansionAndVisibility();
};
@@ -456,9 +449,6 @@ public class NotificationPanelViewController extends PanelViewController {
private boolean mIsFullWidth;
private boolean mBlockingExpansionForCurrentTouch;
- // TODO (b/204204226): no longer needed once refactor is complete
- private final boolean mUseCombinedQSHeaders;
-
/**
* Following variables maintain state of events when input focus transfer may occur.
*/
@@ -502,10 +492,10 @@ public class NotificationPanelViewController extends PanelViewController {
mPanelAlphaAnimator.getProperty(), Interpolators.ALPHA_OUT);
private final AnimationProperties mPanelAlphaInPropertiesAnimator =
new AnimationProperties().setDuration(200).setAnimationEndAction((property) -> {
- if (mPanelAlphaEndAction != null) {
- mPanelAlphaEndAction.run();
- }
- }).setCustomInterpolator(
+ if (mPanelAlphaEndAction != null) {
+ mPanelAlphaEndAction.run();
+ }
+ }).setCustomInterpolator(
mPanelAlphaAnimator.getProperty(), Interpolators.ALPHA_IN);
private final NotificationEntryManager mEntryManager;
@@ -514,19 +504,10 @@ public class NotificationPanelViewController extends PanelViewController {
private final MediaDataManager mMediaDataManager;
private final SysUiState mSysUiState;
- private NotificationShadeDepthController mDepthController;
- private int mDisplayId;
+ private final NotificationShadeDepthController mDepthController;
+ private final int mDisplayId;
- /**
- * Cache the resource id of the theme to avoid unnecessary work in onThemeChanged.
- *
- * onThemeChanged is forced when the theme might not have changed. So, to avoid unncessary
- * work, check the current id with the cached id.
- */
- private int mThemeResId;
private KeyguardIndicationController mKeyguardIndicationController;
- private int mShelfHeight;
- private int mDarkIconSize;
private int mHeadsUpInset;
private boolean mHeadsUpPinnedMode;
private boolean mAllowExpandForSmallExpansion;
@@ -640,15 +621,12 @@ public class NotificationPanelViewController extends PanelViewController {
private final ContentResolver mContentResolver;
private float mMinFraction;
- private final Executor mUiExecutor;
- private final SecureSettings mSecureSettings;
-
- private KeyguardMediaController mKeyguardMediaController;
+ private final KeyguardMediaController mKeyguardMediaController;
private boolean mStatusViewCentered = true;
- private Optional<KeyguardUnfoldTransition> mKeyguardUnfoldTransition;
- private Optional<NotificationPanelUnfoldAnimationController>
+ private final Optional<KeyguardUnfoldTransition> mKeyguardUnfoldTransition;
+ private final Optional<NotificationPanelUnfoldAnimationController>
mNotificationPanelUnfoldAnimationController;
/** The drag distance required to fully expand the split shade. */
@@ -659,9 +637,13 @@ public class NotificationPanelViewController extends PanelViewController {
private final NPVCDownEventState.Buffer mLastDownEvents;
- private View.AccessibilityDelegate mAccessibilityDelegate = new View.AccessibilityDelegate() {
+ private final Runnable mAnimateKeyguardBottomAreaInvisibleEndRunnable =
+ () -> mKeyguardBottomArea.setVisibility(View.GONE);
+
+ private final AccessibilityDelegate mAccessibilityDelegate = new AccessibilityDelegate() {
@Override
- public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
+ public void onInitializeAccessibilityNodeInfo(View host,
+ AccessibilityNodeInfo info) {
super.onInitializeAccessibilityNodeInfo(host, info);
info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_FORWARD);
info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_UP);
@@ -669,7 +651,8 @@ public class NotificationPanelViewController extends PanelViewController {
@Override
public boolean performAccessibilityAction(View host, int action, Bundle args) {
- if (action == AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_FORWARD.getId()
+ if (action
+ == AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_FORWARD.getId()
|| action
== AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_UP.getId()) {
mStatusBarKeyguardViewManager.showBouncer(true);
@@ -696,7 +679,6 @@ public class NotificationPanelViewController extends PanelViewController {
@Inject
public NotificationPanelViewController(NotificationPanelView view,
- @Main Resources resources,
@Main Handler handler,
LayoutInflater layoutInflater,
FeatureFlags featureFlags,
@@ -746,8 +728,6 @@ public class NotificationPanelViewController extends PanelViewController {
QuickAccessWalletController quickAccessWalletController,
QRCodeScannerController qrCodeScannerController,
RecordingController recordingController,
- @Main Executor uiExecutor,
- SecureSettings secureSettings,
LargeScreenShadeHeaderController largeScreenShadeHeaderController,
ScreenOffAnimationController screenOffAnimationController,
LockscreenGestureLogger lockscreenGestureLogger,
@@ -834,8 +814,6 @@ public class NotificationPanelViewController extends PanelViewController {
mUserManager = userManager;
mMediaDataManager = mediaDataManager;
mTapAgainViewController = tapAgainViewController;
- mUiExecutor = uiExecutor;
- mSecureSettings = secureSettings;
mInteractionJankMonitor = interactionJankMonitor;
mSysUiState = sysUiState;
mPanelEventsEmitter = panelEventsEmitter;
@@ -845,7 +823,6 @@ public class NotificationPanelViewController extends PanelViewController {
}
});
statusBarWindowStateController.addListener(this::onStatusBarWindowStateChanged);
- mThemeResId = mView.getContext().getThemeResId();
mKeyguardBypassController = bypassController;
mUpdateMonitor = keyguardUpdateMonitor;
mLockscreenShadeTransitionController = lockscreenShadeTransitionController;
@@ -892,14 +869,14 @@ public class NotificationPanelViewController extends PanelViewController {
mView.getOverlay().add(new DebugDrawable());
}
- mKeyguardUnfoldTransition = unfoldComponent.map(c -> c.getKeyguardUnfoldTransition());
+ mKeyguardUnfoldTransition = unfoldComponent.map(
+ SysUIUnfoldComponent::getKeyguardUnfoldTransition);
mNotificationPanelUnfoldAnimationController = unfoldComponent.map(
SysUIUnfoldComponent::getNotificationPanelUnfoldAnimationController);
mQsFrameTranslateController = qsFrameTranslateController;
updateUserSwitcherFlags();
onFinishInflate();
- mUseCombinedQSHeaders = featureFlags.isEnabled(Flags.COMBINED_QS_HEADERS);
keyguardUnlockAnimationController.addKeyguardUnlockAnimationListener(
new KeyguardUnlockAnimationController.KeyguardUnlockAnimationListener() {
@Override
@@ -975,8 +952,8 @@ public class NotificationPanelViewController extends PanelViewController {
mKeyguardStatusBarViewController =
mKeyguardStatusBarViewComponentFactory.build(
- mKeyguardStatusBar,
- mNotificationPanelViewStateProvider)
+ mKeyguardStatusBar,
+ mNotificationPanelViewStateProvider)
.getKeyguardStatusBarViewController();
mKeyguardStatusBarViewController.init();
@@ -1047,12 +1024,8 @@ public class NotificationPanelViewController extends PanelViewController {
mQsPeekHeight = mResources.getDimensionPixelSize(R.dimen.qs_peek_height);
mClockPositionAlgorithm.loadDimens(mResources);
mQsFalsingThreshold = mResources.getDimensionPixelSize(R.dimen.qs_falsing_threshold);
- mPositionMinSideMargin = mResources.getDimensionPixelSize(
- R.dimen.notification_panel_min_side_margin);
mIndicationBottomPadding = mResources.getDimensionPixelSize(
R.dimen.keyguard_indication_bottom_padding);
- mShelfHeight = mResources.getDimensionPixelSize(R.dimen.notification_shelf_height);
- mDarkIconSize = mResources.getDimensionPixelSize(R.dimen.status_bar_icon_drawing_size_dark);
int statusbarHeight = SystemBarUtils.getStatusBarHeight(mView.getContext());
mHeadsUpInset = statusbarHeight + mResources.getDimensionPixelSize(
R.dimen.heads_up_status_bar_padding);
@@ -1110,16 +1083,12 @@ public class NotificationPanelViewController extends PanelViewController {
private void setCentralSurfaces(CentralSurfaces centralSurfaces) {
// TODO: this can be injected.
mCentralSurfaces = centralSurfaces;
- mKeyguardBottomArea.setCentralSurfaces(mCentralSurfaces);
}
public void updateResources() {
mSplitShadeNotificationsScrimMarginBottom =
mResources.getDimensionPixelSize(
R.dimen.split_shade_notifications_scrim_margin_bottom);
- mShelfAndLockIconOverlap =
- mResources.getDimensionPixelSize(R.dimen.shelf_and_lock_icon_overlap);
-
final boolean newSplitShadeEnabled =
LargeScreenUtils.shouldUseSplitNotificationShade(mResources);
final boolean splitShadeChanged = mSplitShadeEnabled != newSplitShadeEnabled;
@@ -1283,11 +1252,11 @@ public class NotificationPanelViewController extends PanelViewController {
}
private void initBottomArea() {
- mKeyguardBottomArea.setCentralSurfaces(mCentralSurfaces);
- mKeyguardBottomArea.setFalsingManager(mFalsingManager);
- mKeyguardBottomArea.initWallet(mQuickAccessWalletController);
- mKeyguardBottomArea.initControls(mControlsComponent);
- mKeyguardBottomArea.initQRCodeScanner(mQRCodeScannerController);
+ mKeyguardBottomArea.init(
+ mFalsingManager,
+ mQuickAccessWalletController,
+ mControlsComponent,
+ mQRCodeScannerController);
}
@VisibleForTesting
@@ -1297,7 +1266,7 @@ public class NotificationPanelViewController extends PanelViewController {
private void updateMaxDisplayedNotifications(boolean recompute) {
if (recompute) {
- mMaxAllowedKeyguardNotifications = Math.max(computeMaxKeyguardNotifications(), 1);
+ setMaxDisplayedNotifications(Math.max(computeMaxKeyguardNotifications(), 1));
} else {
if (SPEW_LOGCAT) Log.d(TAG, "Skipping computeMaxKeyguardNotifications() by request");
}
@@ -1325,7 +1294,7 @@ public class NotificationPanelViewController extends PanelViewController {
private void updateGestureExclusionRect() {
Rect exclusionRect = calculateGestureExclusionRect();
- mView.setSystemGestureExclusionRects(exclusionRect.isEmpty() ? Collections.EMPTY_LIST
+ mView.setSystemGestureExclusionRects(exclusionRect.isEmpty() ? Collections.emptyList()
: Collections.singletonList(exclusionRect));
}
@@ -1353,14 +1322,11 @@ public class NotificationPanelViewController extends PanelViewController {
mQsSizeChangeAnimator = ValueAnimator.ofInt(oldHeight, newHeight);
mQsSizeChangeAnimator.setDuration(300);
mQsSizeChangeAnimator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
- mQsSizeChangeAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- requestScrollerTopPaddingUpdate(false /* animate */);
- requestPanelHeightUpdate();
- int height = (int) mQsSizeChangeAnimator.getAnimatedValue();
- mQs.setHeightOverride(height);
- }
+ mQsSizeChangeAnimator.addUpdateListener(animation -> {
+ requestScrollerTopPaddingUpdate(false /* animate */);
+ requestPanelHeightUpdate();
+ int height = (int) mQsSizeChangeAnimator.getAnimatedValue();
+ mQs.setHeightOverride(height);
});
mQsSizeChangeAnimator.addListener(new AnimatorListenerAdapter() {
@Override
@@ -1905,12 +1871,8 @@ public class NotificationPanelViewController extends PanelViewController {
mListenForHeadsUp = mCollapsedOnDown && mHeadsUpManager.hasPinnedHeadsUp();
mAllowExpandForSmallExpansion = mExpectingSynthesizedDown;
mTouchSlopExceededBeforeDown = mExpectingSynthesizedDown;
- if (mExpectingSynthesizedDown) {
- mLastEventSynthesizedDown = true;
- } else {
- // down but not synthesized motion event.
- mLastEventSynthesizedDown = false;
- }
+ // When false, down but not synthesized motion event.
+ mLastEventSynthesizedDown = mExpectingSynthesizedDown;
mLastDownEvents.insert(
mSystemClock.currentTimeMillis(),
mDownX,
@@ -1935,7 +1897,6 @@ public class NotificationPanelViewController extends PanelViewController {
*
* @param downX the x location where the touch started
* @param downY the y location where the touch started
- *
* @return true if the panel could be collapsed because it stared on QQS
*/
private boolean canPanelCollapseOnQQS(float downX, float downY) {
@@ -1944,7 +1905,7 @@ public class NotificationPanelViewController extends PanelViewController {
}
View header = mQs == null ? mKeyguardStatusBar : mQs.getHeader();
return downX >= mQsFrame.getX() && downX <= mQsFrame.getX() + mQsFrame.getWidth()
- && downY <= header.getBottom();
+ && downY <= header.getBottom();
}
@@ -2089,7 +2050,7 @@ public class NotificationPanelViewController extends PanelViewController {
return false;
}
return y <= mNotificationStackScrollLayoutController.getBottomMostNotificationBottom()
- || y <= mQs.getView().getY() + mQs.getView().getHeight();
+ || y <= mQs.getView().getY() + mQs.getView().getHeight();
}
private boolean isOpenQsEvent(MotionEvent event) {
@@ -2268,15 +2229,11 @@ public class NotificationPanelViewController extends PanelViewController {
}
private void onQsExpansionStarted() {
- onQsExpansionStarted(0);
- }
-
- protected void onQsExpansionStarted(int overscrollAmount) {
cancelQsAnimation();
cancelHeightAnimator();
// Reset scroll position and apply that position to the expanded height.
- float height = mQsExpansionHeight - overscrollAmount;
+ float height = mQsExpansionHeight;
setQsExpansion(height);
requestPanelHeightUpdate();
mNotificationStackScrollLayoutController.checkSnoozeLeavebehind();
@@ -2288,7 +2245,8 @@ public class NotificationPanelViewController extends PanelViewController {
}
}
- @VisibleForTesting void setQsExpanded(boolean expanded) {
+ @VisibleForTesting
+ void setQsExpanded(boolean expanded) {
boolean changed = mQsExpanded != expanded;
if (changed) {
mQsExpanded = expanded;
@@ -2313,13 +2271,6 @@ public class NotificationPanelViewController extends PanelViewController {
}
}
- private final Runnable mAnimateKeyguardBottomAreaInvisibleEndRunnable = new Runnable() {
- @Override
- public void run() {
- mKeyguardBottomArea.setVisibility(View.GONE);
- }
- };
-
private void setKeyguardBottomAreaVisibility(int statusBarState, boolean goingToFullShade) {
mKeyguardBottomArea.animate().cancel();
if (goingToFullShade) {
@@ -2437,7 +2388,7 @@ public class NotificationPanelViewController extends PanelViewController {
}
setQSClippingBounds();
}
- };
+ }
private void onNotificationScrolled(int newScrollPosition) {
updateQSExpansionEnabledAmbient();
@@ -2602,7 +2553,7 @@ public class NotificationPanelViewController extends PanelViewController {
boolean pulseExpanding = mPulseExpansionHandler.isExpanding();
if (mTransitioningToFullShadeProgress > 0.0f || pulseExpanding
|| (mQsClippingAnimation != null
- && (mIsQsTranslationResetAnimator || mIsPulseExpansionResetAnimator))) {
+ && (mIsQsTranslationResetAnimator || mIsPulseExpansionResetAnimator))) {
if (pulseExpanding || mIsPulseExpansionResetAnimator) {
// qsTranslation should only be positive during pulse expansion because it's
// already translating in from the top
@@ -2621,8 +2572,8 @@ public class NotificationPanelViewController extends PanelViewController {
mQs.setFancyClipping(
mQsClipTop,
mQsClipBottom,
- radius, qsVisible
- && !mSplitShadeEnabled);
+ radius,
+ qsVisible && !mSplitShadeEnabled);
}
mKeyguardStatusViewController.setClipBounds(
clipStatusView ? mKeyguardStatusAreaClipBounds : null);
@@ -2746,8 +2697,7 @@ public class NotificationPanelViewController extends PanelViewController {
}
}
-
- protected void requestScrollerTopPaddingUpdate(boolean animate) {
+ private void requestScrollerTopPaddingUpdate(boolean animate) {
mNotificationStackScrollLayoutController.updateTopPadding(
calculateNotificationsTopPadding(), animate);
if (mKeyguardShowing && mKeyguardBypassController.getBypassEnabled()) {
@@ -2895,7 +2845,7 @@ public class NotificationPanelViewController extends PanelViewController {
* @param onFinishRunnable Runnable to be executed at the end of animation.
* @param isClick If originated by click (different interpolator and duration.)
*/
- protected void flingSettings(float vel, int type, final Runnable onFinishRunnable,
+ private void flingSettings(float vel, int type, final Runnable onFinishRunnable,
boolean isClick) {
float target;
switch (type) {
@@ -2937,11 +2887,11 @@ public class NotificationPanelViewController extends PanelViewController {
if (oppositeDirection) {
animator.setDuration(350);
}
- animator.addUpdateListener(animation -> {
- setQsExpansion((Float) animation.getAnimatedValue());
- });
+ animator.addUpdateListener(
+ animation -> setQsExpansion((Float) animation.getAnimatedValue()));
animator.addListener(new AnimatorListenerAdapter() {
private boolean mIsCanceled;
+
@Override
public void onAnimationStart(Animator animation) {
notifyExpandingStarted();
@@ -3039,7 +2989,7 @@ public class NotificationPanelViewController extends PanelViewController {
maxHeight = calculatePanelHeightShade();
}
maxHeight = Math.max(min, maxHeight);
- if (maxHeight == 0 || isNaN(maxHeight)) {
+ if (maxHeight == 0) {
Log.wtf(TAG, "maxPanelHeight is invalid. mOverExpansion: "
+ mOverExpansion + ", calculatePanelHeightQsExpanded: "
+ calculatePanelHeightQsExpanded() + ", calculatePanelHeightShade: "
@@ -3202,7 +3152,7 @@ public class NotificationPanelViewController extends PanelViewController {
updateQsExpansion();
}
- protected float getHeaderTranslation() {
+ private float getHeaderTranslation() {
if (mBarState == KEYGUARD && !mKeyguardBypassController.getBypassEnabled()) {
return -mQs.getQsMinExpansionHeight();
}
@@ -3272,22 +3222,13 @@ public class NotificationPanelViewController extends PanelViewController {
mMediaHierarchyManager.setCollapsingShadeFromQS(false);
mMediaHierarchyManager.setQsExpanded(mQsExpanded);
if (isFullyCollapsed()) {
- DejankUtils.postAfterTraversal(new Runnable() {
- @Override
- public void run() {
- setListening(false);
- }
- });
+ DejankUtils.postAfterTraversal(() -> setListening(false));
// Workaround b/22639032: Make sure we invalidate something because else RenderThread
// thinks we are actually drawing a frame put in reality we don't, so RT doesn't go
// ahead with rendering and we jank.
- mView.postOnAnimation(new Runnable() {
- @Override
- public void run() {
- mView.getParent().invalidateChild(mView, M_DUMMY_DIRTY_RECT);
- }
- });
+ mView.postOnAnimation(
+ () -> mView.getParent().invalidateChild(mView, M_DUMMY_DIRTY_RECT));
} else {
setListening(true);
}
@@ -3487,13 +3428,13 @@ public class NotificationPanelViewController extends PanelViewController {
if (mUpdateMonitor.isFaceEnrolled()
&& !mUpdateMonitor.isFaceDetectionRunning()
&& !mUpdateMonitor.getUserCanSkipBouncer(
- KeyguardUpdateMonitor.getCurrentUser())) {
+ KeyguardUpdateMonitor.getCurrentUser())) {
mUpdateMonitor.requestFaceAuth(true);
} else {
mLockscreenGestureLogger.write(MetricsEvent.ACTION_LS_HINT,
0 /* lengthDp - N/A */, 0 /* velocityDp - N/A */);
mLockscreenGestureLogger
- .log(LockscreenUiEvent.LOCKSCREEN_LOCK_SHOW_HINT);
+ .log(LockscreenUiEvent.LOCKSCREEN_LOCK_SHOW_HINT);
startUnlockHintAnimation();
}
if (mUpdateMonitor.isFaceEnrolled()) {
@@ -3572,7 +3513,7 @@ public class NotificationPanelViewController extends PanelViewController {
mNotificationStackScrollLayoutController.forceNoOverlappingRendering(closing);
}
- protected void updateExpandedHeight(float expandedHeight) {
+ private void updateExpandedHeight(float expandedHeight) {
if (mTracking) {
mNotificationStackScrollLayoutController
.setExpandingVelocity(getCurrentExpandVelocity());
@@ -3595,12 +3536,10 @@ public class NotificationPanelViewController extends PanelViewController {
}
private void updateStatusBarIcons() {
- boolean
- showIconsWhenExpanded =
+ boolean showIconsWhenExpanded =
(isPanelVisibleBecauseOfHeadsUp() || isFullWidth())
&& getExpandedHeight() < getOpeningHeight();
- boolean noVisibleNotifications = true;
- if (showIconsWhenExpanded && noVisibleNotifications && isOnKeyguard()) {
+ if (showIconsWhenExpanded && isOnKeyguard()) {
showIconsWhenExpanded = false;
}
if (showIconsWhenExpanded != mShowIconsWhenExpanded) {
@@ -3892,24 +3831,25 @@ public class NotificationPanelViewController extends PanelViewController {
*/
public void startFoldToAodAnimation(Runnable endAction) {
mView.animate()
- .translationX(0)
- .alpha(1f)
- .setDuration(ANIMATION_DURATION_FOLD_TO_AOD)
- .setInterpolator(EMPHASIZED_DECELERATE)
- .setListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationCancel(Animator animation) {
- endAction.run();
- }
- @Override
- public void onAnimationEnd(Animator animation) {
- endAction.run();
- }
- })
- .setUpdateListener(anim -> {
- mKeyguardStatusViewController.animateFoldToAod(anim.getAnimatedFraction());
- })
- .start();
+ .translationX(0)
+ .alpha(1f)
+ .setDuration(ANIMATION_DURATION_FOLD_TO_AOD)
+ .setInterpolator(EMPHASIZED_DECELERATE)
+ .setListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ endAction.run();
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ endAction.run();
+ }
+ })
+ .setUpdateListener(anim -> {
+ mKeyguardStatusViewController.animateFoldToAod(anim.getAnimatedFraction());
+ })
+ .start();
}
/**
@@ -3921,7 +3861,6 @@ public class NotificationPanelViewController extends PanelViewController {
resetTranslation();
}
- /** */
public void setImportantForAccessibility(int mode) {
mView.setImportantForAccessibility(mode);
}
@@ -4256,8 +4195,7 @@ public class NotificationPanelViewController extends PanelViewController {
};
@Override
- protected PanelViewController.OnConfigurationChangedListener
- createOnConfigurationChangedListener() {
+ protected OnConfigurationChangedListener createOnConfigurationChangedListener() {
return new OnConfigurationChangedListener();
}
@@ -4314,7 +4252,7 @@ public class NotificationPanelViewController extends PanelViewController {
+ isFullyExpanded() + " inQs=" + isInSettings());
}
mSysUiState.setFlag(SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED,
- isFullyExpanded() && !isInSettings())
+ isFullyExpanded() && !isInSettings())
.setFlag(SYSUI_STATE_QUICK_SETTINGS_EXPANDED, isInSettings())
.commitUpdate(mDisplayId);
}
@@ -4490,7 +4428,6 @@ public class NotificationPanelViewController extends PanelViewController {
@Override
public void onThemeChanged() {
if (DEBUG_LOGCAT) Log.d(TAG, "onThemeChanged");
- mThemeResId = mView.getContext().getThemeResId();
reInflateViews();
}
@@ -4639,6 +4576,7 @@ public class NotificationPanelViewController extends PanelViewController {
public interface NotificationPanelViewStateProvider {
/** Returns the expanded height of the panel view. */
float getPanelViewExpandedHeight();
+
/**
* Returns true if heads up should be visible.
*
@@ -4700,7 +4638,7 @@ public class NotificationPanelViewController extends PanelViewController {
@Override
public void onViewAttachedToWindow(View v) {
mFragmentService.getFragmentHostManager(mView)
- .addTagListener(QS.TAG, mFragmentListener);
+ .addTagListener(QS.TAG, mFragmentListener);
mStatusBarStateController.addCallback(mStatusBarStateListener);
mStatusBarStateListener.onStateChanged(mStatusBarStateController.getState());
mConfigurationController.addCallback(mConfigurationListener);
@@ -4717,7 +4655,7 @@ public class NotificationPanelViewController extends PanelViewController {
public void onViewDetachedFromWindow(View v) {
unregisterSettingsChangeListener();
mFragmentService.getFragmentHostManager(mView)
- .removeTagListener(QS.TAG, mFragmentListener);
+ .removeTagListener(QS.TAG, mFragmentListener);
mStatusBarStateController.removeCallback(mStatusBarStateListener);
mConfigurationController.removeCallback(mConfigurationListener);
mFalsingManager.removeTapListener(mFalsingTapListener);
@@ -4799,7 +4737,7 @@ public class NotificationPanelViewController extends PanelViewController {
private final Paint mDebugPaint = new Paint();
@Override
- public void draw(@NonNull Canvas canvas) {
+ public void draw(@androidx.annotation.NonNull @NonNull Canvas canvas) {
mDebugTextUsedYPositions.clear();
mDebugPaint.setColor(Color.RED);
@@ -4873,7 +4811,7 @@ public class NotificationPanelViewController extends PanelViewController {
@Override
public int getOpacity() {
- return 0;
+ return PixelFormat.UNKNOWN;
}
}
@@ -4943,15 +4881,16 @@ public class NotificationPanelViewController extends PanelViewController {
private final ListenerSet<Listener> mListeners = new ListenerSet<>();
@Inject
- PanelEventsEmitter() {}
+ PanelEventsEmitter() {
+ }
@Override
- public void registerListener(@NonNull Listener listener) {
+ public void registerListener(@androidx.annotation.NonNull @NonNull Listener listener) {
mListeners.addIfAbsent(listener);
}
@Override
- public void unregisterListener(@NonNull Listener listener) {
+ public void unregisterListener(@androidx.annotation.NonNull @NonNull Listener listener) {
mListeners.remove(listener);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
index 6af8e9e77d10..2e6664820fa7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
@@ -68,6 +68,7 @@ import com.android.systemui.GuestResetOrExitSessionReceiver;
import com.android.systemui.GuestResumeSessionReceiver;
import com.android.systemui.R;
import com.android.systemui.SystemUISecondaryUserService;
+import com.android.systemui.animation.DialogCuj;
import com.android.systemui.animation.DialogLaunchAnimator;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.broadcast.BroadcastSender;
@@ -116,6 +117,9 @@ public class UserSwitcherController implements Dumpable {
private static final String PERMISSION_SELF = "com.android.systemui.permission.SELF";
private static final long MULTI_USER_JOURNEY_TIMEOUT = 20000l;
+ private static final String INTERACTION_JANK_ADD_NEW_USER_TAG = "add_new_user";
+ private static final String INTERACTION_JANK_EXIT_GUEST_MODE_TAG = "exit_guest_mode";
+
protected final Context mContext;
protected final UserTracker mUserTracker;
protected final UserManager mUserManager;
@@ -597,7 +601,9 @@ public class UserSwitcherController implements Dumpable {
}
mExitGuestDialog = new ExitGuestDialog(mContext, id, isGuestEphemeral, targetId);
if (dialogShower != null) {
- dialogShower.showDialog(mExitGuestDialog);
+ dialogShower.showDialog(mExitGuestDialog, new DialogCuj(
+ InteractionJankMonitor.CUJ_USER_DIALOG_OPEN,
+ INTERACTION_JANK_EXIT_GUEST_MODE_TAG));
} else {
mExitGuestDialog.show();
}
@@ -609,7 +615,11 @@ public class UserSwitcherController implements Dumpable {
}
mAddUserDialog = new AddUserDialog(mContext);
if (dialogShower != null) {
- dialogShower.showDialog(mAddUserDialog);
+ dialogShower.showDialog(mAddUserDialog,
+ new DialogCuj(
+ InteractionJankMonitor.CUJ_USER_DIALOG_OPEN,
+ INTERACTION_JANK_ADD_NEW_USER_TAG
+ ));
} else {
mAddUserDialog.show();
}
diff --git a/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIInitializer.java
index 0b5594b14d0e..fabbb2c1f44d 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIInitializer.java
@@ -16,14 +16,20 @@
package com.android.systemui.tv;
-import com.android.systemui.SystemUIFactory;
+import android.content.Context;
+
+import com.android.systemui.SystemUIInitializer;
import com.android.systemui.dagger.GlobalRootComponent;
/**
- * TV variant {@link SystemUIFactory}, that substitutes default {@link GlobalRootComponent} for
+ * TV variant {@link SystemUIInitializer}, that substitutes default {@link GlobalRootComponent} for
* {@link TvGlobalRootComponent}
*/
-public class TvSystemUIFactory extends SystemUIFactory {
+public class TvSystemUIInitializer extends SystemUIInitializer {
+ public TvSystemUIInitializer(Context context) {
+ super(context);
+ }
+
@Override
protected GlobalRootComponent.Builder getGlobalRootComponentBuilder() {
return DaggerTvGlobalRootComponent.builder();
diff --git a/packages/SystemUI/src/com/android/systemui/util/AsyncActivityLauncher.kt b/packages/SystemUI/src/com/android/systemui/util/AsyncActivityLauncher.kt
new file mode 100644
index 000000000000..80d0e4b90359
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/AsyncActivityLauncher.kt
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.util
+
+import android.app.IActivityTaskManager
+import android.app.WaitResult
+import android.content.Context
+import android.content.Intent
+import android.os.Bundle
+import android.os.UserHandle
+import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.dagger.qualifiers.UiBackground
+import java.util.concurrent.Executor
+import javax.inject.Inject
+
+/**
+ * Helper class that allows to launch an activity and asynchronously wait
+ * for it to be launched. This class uses application context, so the intent
+ * will be launched with FLAG_ACTIVITY_NEW_TASK.
+ */
+class AsyncActivityLauncher @Inject constructor(
+ private val context: Context,
+ private val activityTaskManager: IActivityTaskManager,
+ @UiBackground private val backgroundExecutor: Executor,
+ @Main private val mainExecutor: Executor
+) {
+
+ private var pendingCallback: ((WaitResult) -> Unit)? = null
+
+ /**
+ * Starts activity and notifies about the result using the provided [callback].
+ * If there is already pending activity launch the call will be ignored.
+ *
+ * @return true if launch has started, false otherwise
+ */
+ fun startActivityAsUser(intent: Intent, userHandle: UserHandle,
+ activityOptions: Bundle? = null,
+ callback: (WaitResult) -> Unit): Boolean {
+ if (pendingCallback != null) return false
+
+ pendingCallback = callback
+
+ intent.flags = intent.flags or Intent.FLAG_ACTIVITY_NEW_TASK
+
+ backgroundExecutor.execute {
+ val waitResult = activityTaskManager.startActivityAndWait(
+ /* caller = */ null,
+ /* callingPackage = */ context.packageName,
+ /* callingFeatureId = */ context.attributionTag,
+ /* intent = */ intent,
+ /* resolvedType = */ null,
+ /* resultTo = */ null,
+ /* resultWho = */ null,
+ /* requestCode = */ 0,
+ /* flags = */ 0,
+ /* profilerInfo = */ null,
+ /* options = */ activityOptions,
+ /* userId = */ userHandle.identifier
+ )
+ mainExecutor.execute {
+ pendingCallback?.invoke(waitResult)
+ }
+ }
+
+ return true
+ }
+
+ /**
+ * Cancels pending activity launches. It guarantees that the callback won't be fired
+ * but the activity will be launched anyway.
+ */
+ fun destroy() {
+ pendingCallback = null
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/util/service/ObservableServiceConnection.java b/packages/SystemUI/src/com/android/systemui/util/service/ObservableServiceConnection.java
index c57dbe37ca5f..064c224b0568 100644
--- a/packages/SystemUI/src/com/android/systemui/util/service/ObservableServiceConnection.java
+++ b/packages/SystemUI/src/com/android/systemui/util/service/ObservableServiceConnection.java
@@ -155,11 +155,6 @@ public class ObservableServiceConnection<T> implements ServiceConnection {
* Disconnect from the service if bound.
*/
public void unbind() {
- if (!mBoundCalled) {
- return;
- }
- mBoundCalled = false;
- mContext.unbindService(this);
onDisconnected(DISCONNECT_REASON_UNBIND);
}
@@ -210,12 +205,15 @@ public class ObservableServiceConnection<T> implements ServiceConnection {
Log.d(TAG, "onDisconnected:" + reason);
}
+ // If not bound or already unbound, do not proceed setting reason, unbinding, and
+ // notifying
if (!mBoundCalled) {
return;
}
+ mBoundCalled = false;
mLastDisconnectReason = Optional.of(reason);
- unbind();
+ mContext.unbindService(this);
mProxy = null;
applyToCallbacksLocked(callback-> callback.onDisconnected(this,
diff --git a/packages/SystemUI/src/com/android/systemui/util/service/PersistentConnectionManager.java b/packages/SystemUI/src/com/android/systemui/util/service/PersistentConnectionManager.java
index 292c062369c1..6e19bed49626 100644
--- a/packages/SystemUI/src/com/android/systemui/util/service/PersistentConnectionManager.java
+++ b/packages/SystemUI/src/com/android/systemui/util/service/PersistentConnectionManager.java
@@ -72,6 +72,11 @@ public class PersistentConnectionManager<T> {
@Override
public void onDisconnected(ObservableServiceConnection connection, int reason) {
+ // Do not attempt to reconnect if we were manually unbound
+ if (reason == ObservableServiceConnection.DISCONNECT_REASON_UNBIND) {
+ return;
+ }
+
if (mSystemClock.currentTimeMillis() - mStartTime > mMinConnectionDuration) {
initiateConnectionAttempt();
} else {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/DependencyTest.java b/packages/SystemUI/tests/src/com/android/systemui/DependencyTest.java
index 5d8e4351cfd9..a0fdc8f1555e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/DependencyTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/DependencyTest.java
@@ -26,6 +26,8 @@ import com.android.systemui.statusbar.policy.FlashlightController;
import org.junit.Assert;
import org.junit.Test;
+import java.util.concurrent.ExecutionException;
+
@SmallTest
public class DependencyTest extends SysuiTestCase {
@@ -44,10 +46,12 @@ public class DependencyTest extends SysuiTestCase {
}
@Test
- public void testInitDependency() {
+ public void testInitDependency() throws ExecutionException, InterruptedException {
Dependency.clearDependencies();
- Dependency dependency =
- SystemUIFactory.getInstance().getSysUIComponent().createDependency();
+ SystemUIInitializer initializer =
+ SystemUIInitializerFactory.createFromConfigNoAssert(mContext);
+ initializer.init(true);
+ Dependency dependency = initializer.getSysUIComponent().createDependency();
dependency.start();
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java b/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java
index df10dfe9f160..64a7986d05b1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java
@@ -16,6 +16,7 @@ package com.android.systemui;
import static android.view.DisplayCutout.BOUNDS_POSITION_BOTTOM;
import static android.view.DisplayCutout.BOUNDS_POSITION_LEFT;
+import static android.view.DisplayCutout.BOUNDS_POSITION_LENGTH;
import static android.view.DisplayCutout.BOUNDS_POSITION_RIGHT;
import static android.view.DisplayCutout.BOUNDS_POSITION_TOP;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY;
@@ -35,7 +36,6 @@ import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isA;
-import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
@@ -49,6 +49,7 @@ import android.annotation.IdRes;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.content.res.TypedArray;
+import android.graphics.Insets;
import android.graphics.Path;
import android.graphics.PixelFormat;
import android.graphics.Rect;
@@ -59,6 +60,7 @@ import android.os.Handler;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.testing.TestableLooper.RunWithLooper;
+import android.util.RotationUtils;
import android.util.Size;
import android.view.Display;
import android.view.DisplayCutout;
@@ -78,8 +80,6 @@ import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.biometrics.AuthController;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.decor.CornerDecorProvider;
-import com.android.systemui.decor.CutoutDecorProviderFactory;
-import com.android.systemui.decor.CutoutDecorProviderImpl;
import com.android.systemui.decor.DecorProvider;
import com.android.systemui.decor.DecorProviderFactory;
import com.android.systemui.decor.FaceScanningOverlayProviderImpl;
@@ -157,9 +157,6 @@ public class ScreenDecorationsTest extends SysuiTestCase {
@Mock
private DisplayInfo mDisplayInfo;
private PrivacyDotViewController.ShowingListener mPrivacyDotShowingListener;
- @Mock
- private CutoutDecorProviderFactory mCutoutFactory;
- private List<DecorProvider> mMockCutoutList;
@Before
public void setup() {
@@ -209,11 +206,6 @@ public class ScreenDecorationsTest extends SysuiTestCase {
DisplayCutout.BOUNDS_POSITION_RIGHT,
R.layout.privacy_dot_bottom_right));
- // Default no cutout
- mMockCutoutList = new ArrayList<>();
- doAnswer(it -> !(mMockCutoutList.isEmpty())).when(mCutoutFactory).getHasProviders();
- doReturn(mMockCutoutList).when(mCutoutFactory).getProviders();
-
mFaceScanningDecorProvider = spy(new FaceScanningOverlayProviderImpl(
BOUNDS_POSITION_TOP,
mAuthController,
@@ -247,11 +239,6 @@ public class ScreenDecorationsTest extends SysuiTestCase {
super.updateOverlayWindowVisibilityIfViewExists(view);
mExecutor.runAllReady();
}
-
- @Override
- protected CutoutDecorProviderFactory getCutoutFactory() {
- return ScreenDecorationsTest.this.mCutoutFactory;
- }
});
mScreenDecorations.mDisplayInfo = mDisplayInfo;
doReturn(1f).when(mScreenDecorations).getPhysicalPixelDisplaySizeRatio();
@@ -442,9 +429,11 @@ public class ScreenDecorationsTest extends SysuiTestCase {
public void testNoRounding_NoCutout_NoPrivacyDot_NoFaceScanning() {
setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
- 0 /* roundedPadding */, false /* privacyDot */, false /* faceScanning */);
+ 0 /* roundedPadding */, false /* fillCutout */, false /* privacyDot */,
+ false /* faceScanning */);
- // no cutout (default)
+ // no cutout
+ doReturn(null).when(mScreenDecorations).getCutout();
mScreenDecorations.start();
// No views added.
@@ -459,9 +448,11 @@ public class ScreenDecorationsTest extends SysuiTestCase {
public void testNoRounding_NoCutout_PrivacyDot_NoFaceScanning() {
setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
- 0 /* roundedPadding */, true /* privacyDot */, false /* faceScanning */);
+ 0 /* roundedPadding */, false /* fillCutout */, true /* privacyDot */,
+ false /* faceScanning */);
- // no cutout (default)
+ // no cutout
+ doReturn(null).when(mScreenDecorations).getCutout();
mScreenDecorations.start();
@@ -493,9 +484,11 @@ public class ScreenDecorationsTest extends SysuiTestCase {
public void testRounding_NoCutout_NoPrivacyDot_NoFaceScanning() {
setupResources(20 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
- 20 /* roundedPadding */, false /* privacyDot */, false /* faceScanning */);
+ 20 /* roundedPadding */, false /* fillCutout */, false /* privacyDot */,
+ false /* faceScanning */);
- // no cutout (default)
+ // no cutout
+ doReturn(null).when(mScreenDecorations).getCutout();
mScreenDecorations.start();
@@ -523,9 +516,11 @@ public class ScreenDecorationsTest extends SysuiTestCase {
public void testRounding_NoCutout_PrivacyDot_NoFaceScanning() {
setupResources(20 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
- 20 /* roundedPadding */, true /* privacyDot */, false /* faceScanning */);
+ 20 /* roundedPadding */, false /* fillCutout */, true /* privacyDot */,
+ false /* faceScanning */);
- // no cutout (default)
+ // no cutout
+ doReturn(null).when(mScreenDecorations).getCutout();
mScreenDecorations.start();
@@ -560,9 +555,10 @@ public class ScreenDecorationsTest extends SysuiTestCase {
/* roundedTopDrawable */,
getTestsDrawable(com.android.systemui.tests.R.drawable.rounded3px)
/* roundedBottomDrawable */,
- 0 /* roundedPadding */, true /* privacyDot */, false /* faceScanning */);
-
- // no cutout (default)
+ 0 /* roundedPadding */, false /* fillCutout */, true /* privacyDot */,
+ false /* faceScanning */);
+ // no cutout
+ doReturn(null).when(mScreenDecorations).getCutout();
mScreenDecorations.start();
// Size of corner view should same as rounded_corner_radius{_top|_bottom}
@@ -578,9 +574,11 @@ public class ScreenDecorationsTest extends SysuiTestCase {
/* roundedTopDrawable */,
getTestsDrawable(com.android.systemui.tests.R.drawable.rounded3px)
/* roundedBottomDrawable */,
- 0 /* roundedPadding */, true /* privacyDot */, false /* faceScanning */);
+ 0 /* roundedPadding */, false /* fillCutout */, true /* privacyDot */,
+ false /* faceScanning */);
- // no cutout (default)
+ // no cutout
+ doReturn(null).when(mScreenDecorations).getCutout();
mScreenDecorations.start();
View leftRoundedCorner = mScreenDecorations.mOverlays[BOUNDS_POSITION_TOP].getRootView()
@@ -613,10 +611,13 @@ public class ScreenDecorationsTest extends SysuiTestCase {
/* roundedTopDrawable */,
getTestsDrawable(com.android.systemui.tests.R.drawable.rounded5px)
/* roundedBottomDrawable */,
- 0 /* roundedPadding */, true /* privacyDot */, false /* faceScanning */);
+ 0 /* roundedPadding */, false /* fillCutout */, true /* privacyDot */,
+ false /* faceScanning */);
// left cutout
- mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_LEFT));
+ final Rect[] bounds = {new Rect(0, 50, 1, 60), null, null, null};
+ doReturn(getDisplayCutoutForRotation(Insets.of(1, 0, 0, 0), bounds))
+ .when(mScreenDecorations).getCutout();
mScreenDecorations.start();
View topRoundedCorner = mScreenDecorations.mOverlays[BOUNDS_POSITION_LEFT].getRootView()
@@ -646,10 +647,13 @@ public class ScreenDecorationsTest extends SysuiTestCase {
public void testNoRounding_CutoutShortEdge_NoPrivacyDot() {
setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
- 0 /* roundedPadding */, false /* privacyDot */, false /* faceScanning */);
+ 0 /* roundedPadding */, true /* fillCutout */, false /* privacyDot */,
+ false /* faceScanning */);
// top cutout
- mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_TOP));
+ final Rect[] bounds = {null, new Rect(9, 0, 10, 1), null, null};
+ doReturn(getDisplayCutoutForRotation(Insets.of(0, 1, 0, 0), bounds))
+ .when(mScreenDecorations).getCutout();
mScreenDecorations.start();
// Top window is created for top cutout.
@@ -667,10 +671,13 @@ public class ScreenDecorationsTest extends SysuiTestCase {
public void testNoRounding_CutoutShortEdge_PrivacyDot() {
setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
- 0 /* roundedPadding */, true /* privacyDot */, false /* faceScanning */);
+ 0 /* roundedPadding */, true /* fillCutout */, true /* privacyDot */,
+ false /* faceScanning */);
// top cutout
- mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_TOP));
+ final Rect[] bounds = {null, new Rect(9, 0, 10, 1), null, null};
+ doReturn(getDisplayCutoutForRotation(Insets.of(0, 1, 0, 0), bounds))
+ .when(mScreenDecorations).getCutout();
mScreenDecorations.start();
// Top window is created for top cutout.
@@ -699,10 +706,13 @@ public class ScreenDecorationsTest extends SysuiTestCase {
public void testNoRounding_CutoutLongEdge_NoPrivacyDot() {
setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
- 0 /* roundedPadding */, false /* privacyDot */, false /* faceScanning */);
+ 0 /* roundedPadding */, true /* fillCutout */, false /* privacyDot */,
+ false /* faceScanning */);
// left cutout
- mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_LEFT));
+ final Rect[] bounds = {new Rect(0, 50, 1, 60), null, null, null};
+ doReturn(getDisplayCutoutForRotation(Insets.of(1, 0, 0, 0), bounds))
+ .when(mScreenDecorations).getCutout();
mScreenDecorations.start();
// Left window is created for left cutout.
@@ -724,10 +734,13 @@ public class ScreenDecorationsTest extends SysuiTestCase {
public void testNoRounding_CutoutLongEdge_PrivacyDot() {
setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
- 0 /* roundedPadding */, true /* privacyDot */, false /* faceScanning */);
+ 0 /* roundedPadding */, true /* fillCutout */, true /* privacyDot */,
+ false /* faceScanning */);
// left cutout
- mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_LEFT));
+ final Rect[] bounds = {new Rect(0, 50, 1, 60), null, null, null};
+ doReturn(getDisplayCutoutForRotation(Insets.of(1, 0, 0, 0), bounds))
+ .when(mScreenDecorations).getCutout();
mScreenDecorations.start();
// Left window is created for left cutout.
@@ -749,10 +762,13 @@ public class ScreenDecorationsTest extends SysuiTestCase {
public void testRounding_CutoutShortEdge_NoPrivacyDot() {
setupResources(20 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
- 20 /* roundedPadding */, false /* privacyDot */, false /* faceScanning */);
+ 20 /* roundedPadding */, true /* fillCutout */, false /* privacyDot */,
+ false /* faceScanning */);
// top cutout
- mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_TOP));
+ final Rect[] bounds = {null, new Rect(9, 0, 10, 1), null, null};
+ doReturn(getDisplayCutoutForRotation(Insets.of(0, 1, 0, 0), bounds))
+ .when(mScreenDecorations).getCutout();
mScreenDecorations.start();
// Top window is created for rounded corner and top cutout.
@@ -775,10 +791,13 @@ public class ScreenDecorationsTest extends SysuiTestCase {
public void testRounding_CutoutShortEdge_PrivacyDot() {
setupResources(20 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
- 20 /* roundedPadding */, true /* privacyDot */, false /* faceScanning */);
+ 20 /* roundedPadding */, true /* fillCutout */, true /* privacyDot */,
+ false /* faceScanning */);
// top cutout
- mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_TOP));
+ final Rect[] bounds = {null, new Rect(9, 0, 10, 1), null, null};
+ doReturn(getDisplayCutoutForRotation(Insets.of(0, 1, 0, 0), bounds))
+ .when(mScreenDecorations).getCutout();
mScreenDecorations.start();
// Top window is created for rounded corner and top cutout.
@@ -804,10 +823,13 @@ public class ScreenDecorationsTest extends SysuiTestCase {
public void testRounding_CutoutLongEdge_NoPrivacyDot() {
setupResources(20 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
- 20 /* roundedPadding */, false /* privacyDot */, false /* faceScanning */);
+ 20 /* roundedPadding */, true /* fillCutout */, false /* privacyDot */,
+ false /* faceScanning */);
// left cutout
- mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_LEFT));
+ final Rect[] bounds = {new Rect(0, 50, 1, 60), null, null, null};
+ doReturn(getDisplayCutoutForRotation(Insets.of(1, 0, 0, 0), bounds))
+ .when(mScreenDecorations).getCutout();
mScreenDecorations.start();
// Left window is created for rounded corner and left cutout.
@@ -820,10 +842,13 @@ public class ScreenDecorationsTest extends SysuiTestCase {
public void testRounding_CutoutLongEdge_PrivacyDot() {
setupResources(20 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
- 20 /* roundedPadding */, true /* privacyDot */, false /* faceScanning */);
+ 20 /* roundedPadding */, true /* fillCutout */, true /* privacyDot */,
+ false /* faceScanning */);
// left cutout
- mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_LEFT));
+ final Rect[] bounds = {new Rect(0, 50, 1, 60), null, null, null};
+ doReturn(getDisplayCutoutForRotation(Insets.of(1, 0, 0, 0), bounds))
+ .when(mScreenDecorations).getCutout();
mScreenDecorations.start();
// Left window is created for rounded corner, left cutout, and privacy.
@@ -838,11 +863,13 @@ public class ScreenDecorationsTest extends SysuiTestCase {
public void testRounding_CutoutShortAndLongEdge_NoPrivacyDot() {
setupResources(20 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
- 20 /* roundedPadding */, false /* privacyDot */, false /* faceScanning */);
+ 20 /* roundedPadding */, true /* fillCutout */, false /* privacyDot */,
+ false /* faceScanning */);
// top and left cutout
- mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_LEFT));
- mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_TOP));
+ final Rect[] bounds = {new Rect(0, 50, 1, 60), new Rect(9, 0, 10, 1), null, null};
+ doReturn(getDisplayCutoutForRotation(Insets.of(1, 1, 0, 0), bounds))
+ .when(mScreenDecorations).getCutout();
mScreenDecorations.start();
// Top window is created for rounded corner and top cutout.
@@ -856,11 +883,13 @@ public class ScreenDecorationsTest extends SysuiTestCase {
public void testRounding_CutoutShortAndLongEdge_PrivacyDot() {
setupResources(20 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
- 20 /* roundedPadding */, true /* privacyDot */, false /* faceScanning */);
+ 20 /* roundedPadding */, true /* fillCutout */, true /* privacyDot */,
+ false /* faceScanning */);
// top and left cutout
- mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_LEFT));
- mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_TOP));
+ final Rect[] bounds = {new Rect(0, 50, 1, 60), new Rect(9, 0, 10, 1), null, null};
+ doReturn(getDisplayCutoutForRotation(Insets.of(1, 1, 0, 0), bounds))
+ .when(mScreenDecorations).getCutout();
mScreenDecorations.start();
// Top window is created for rounded corner and top cutout.
@@ -876,16 +905,21 @@ public class ScreenDecorationsTest extends SysuiTestCase {
public void testNoRounding_SwitchFrom_ShortEdgeCutout_To_LongCutout_NoPrivacyDot() {
setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
- 0 /* roundedPadding */, false /* privacyDot */, false /* faceScanning */);
+ 0 /* roundedPadding */, true /* fillCutout */, false /* privacyDot */,
+ false /* faceScanning */);
// Set to short edge cutout(top).
- mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_TOP));
+ final Rect[] bounds = {null, new Rect(9, 0, 10, 1), null, null};
+ doReturn(getDisplayCutoutForRotation(Insets.of(0, 1, 0, 0), bounds))
+ .when(mScreenDecorations).getCutout();
mScreenDecorations.start();
verifyOverlaysExistAndAdded(false, true, false, false, View.VISIBLE);
// Switch to long edge cutout(left).
- mMockCutoutList.set(0, new CutoutDecorProviderImpl(BOUNDS_POSITION_LEFT));
+ final Rect[] newBounds = {new Rect(0, 50, 1, 60), null, null, null};
+ doReturn(getDisplayCutoutForRotation(Insets.of(1, 0, 0, 0), newBounds))
+ .when(mScreenDecorations).getCutout();
mScreenDecorations.onConfigurationChanged(new Configuration());
verifyOverlaysExistAndAdded(true, false, false, false, View.VISIBLE);
@@ -895,10 +929,13 @@ public class ScreenDecorationsTest extends SysuiTestCase {
public void testNoRounding_SwitchFrom_ShortEdgeCutout_To_LongCutout_PrivacyDot() {
setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
- 0 /* roundedPadding */, true /* privacyDot */, false /* faceScanning */);
+ 0 /* roundedPadding */, true /* fillCutout */, true /* privacyDot */,
+ false /* faceScanning */);
// Set to short edge cutout(top).
- mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_TOP));
+ final Rect[] bounds = {null, new Rect(9, 0, 10, 1), null, null};
+ doReturn(getDisplayCutoutForRotation(Insets.of(0, 1, 0, 0), bounds))
+ .when(mScreenDecorations).getCutout();
mScreenDecorations.start();
verifyOverlaysExistAndAdded(false, true, false, true, View.VISIBLE);
@@ -906,7 +943,9 @@ public class ScreenDecorationsTest extends SysuiTestCase {
verify(mDotViewController, times(1)).setShowingListener(null);
// Switch to long edge cutout(left).
- mMockCutoutList.set(0, new CutoutDecorProviderImpl(BOUNDS_POSITION_LEFT));
+ final Rect[] newBounds = {new Rect(0, 50, 1, 60), null, null, null};
+ doReturn(getDisplayCutoutForRotation(Insets.of(1, 0, 0, 0), newBounds))
+ .when(mScreenDecorations).getCutout();
mScreenDecorations.onConfigurationChanged(new Configuration());
verifyOverlaysExistAndAdded(true, false, true, false, View.VISIBLE);
@@ -934,16 +973,20 @@ public class ScreenDecorationsTest extends SysuiTestCase {
public void testDelayedCutout_NoPrivacyDot() {
setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
- 0 /* roundedPadding */, false /* privacyDot */, false /* faceScanning */);
+ 0 /* roundedPadding */, false /* fillCutout */, false /* privacyDot */,
+ false /* faceScanning */);
- // No cutout (default)
+ // top cutout
+ final Rect[] bounds = {null, new Rect(9, 0, 10, 1), null, null};
+ doReturn(getDisplayCutoutForRotation(Insets.of(0, 1, 0, 0), bounds))
+ .when(mScreenDecorations).getCutout();
mScreenDecorations.start();
verifyOverlaysExistAndAdded(false, false, false, false, null);
- // top cutout
- mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_TOP));
-
+ when(mContext.getResources().getBoolean(
+ com.android.internal.R.bool.config_fillMainBuiltInDisplayCutout))
+ .thenReturn(true);
mScreenDecorations.onConfigurationChanged(new Configuration());
// Only top windows should be added.
@@ -954,9 +997,13 @@ public class ScreenDecorationsTest extends SysuiTestCase {
public void testDelayedCutout_PrivacyDot() {
setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
- 0 /* roundedPadding */, true /* privacyDot */, false /* faceScanning */);
+ 0 /* roundedPadding */, false /* fillCutout */, true /* privacyDot */,
+ false /* faceScanning */);
- // no cutout (default)
+ // top cutout
+ final Rect[] bounds = {null, new Rect(9, 0, 10, 1), null, null};
+ doReturn(getDisplayCutoutForRotation(Insets.of(0, 1, 0, 0), bounds))
+ .when(mScreenDecorations).getCutout();
mScreenDecorations.start();
// Both top and bottom windows should be added with INVISIBLE because of only privacy dot,
@@ -968,9 +1015,9 @@ public class ScreenDecorationsTest extends SysuiTestCase {
verify(mDotViewController, times(1)).setShowingListener(
mScreenDecorations.mPrivacyDotShowingListener);
- // top cutout
- mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_TOP));
-
+ when(mContext.getResources().getBoolean(
+ com.android.internal.R.bool.config_fillMainBuiltInDisplayCutout))
+ .thenReturn(true);
mScreenDecorations.onConfigurationChanged(new Configuration());
// Both top and bottom windows should be added with VISIBLE because of privacy dot and
@@ -996,7 +1043,8 @@ public class ScreenDecorationsTest extends SysuiTestCase {
/* roundedTopDrawable */,
getTestsDrawable(com.android.systemui.tests.R.drawable.rounded4px)
/* roundedBottomDrawable */,
- 0 /* roundedPadding */, true /* privacyDot */, false /* faceScanning*/);
+ 0 /* roundedPadding */, false /* fillCutout */, true /* privacyDot */,
+ false /* faceScanning*/);
mDisplayInfo.rotation = Surface.ROTATION_0;
mScreenDecorations.start();
@@ -1010,7 +1058,8 @@ public class ScreenDecorationsTest extends SysuiTestCase {
/* roundedTopDrawable */,
getTestsDrawable(com.android.systemui.tests.R.drawable.rounded5px)
/* roundedBottomDrawable */,
- 0 /* roundedPadding */, true /* privacyDot */, false /* faceScanning*/);
+ 0 /* roundedPadding */, false /* fillCutout */, true /* privacyDot */,
+ false /* faceScanning*/);
mDisplayInfo.rotation = Surface.ROTATION_270;
mScreenDecorations.onConfigurationChanged(null);
@@ -1023,7 +1072,8 @@ public class ScreenDecorationsTest extends SysuiTestCase {
public void testOnlyRoundedCornerRadiusTop() {
setupResources(0 /* radius */, 10 /* radiusTop */, 0 /* radiusBottom */,
null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
- 0 /* roundedPadding */, true /* privacyDot */, false /* faceScanning */);
+ 0 /* roundedPadding */, false /* fillCutout */, true /* privacyDot */,
+ false /* faceScanning */);
mScreenDecorations.start();
@@ -1044,7 +1094,8 @@ public class ScreenDecorationsTest extends SysuiTestCase {
public void testOnlyRoundedCornerRadiusBottom() {
setupResources(0 /* radius */, 0 /* radiusTop */, 20 /* radiusBottom */,
null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
- 0 /* roundedPadding */, true /* privacyDot */, false /* faceScanning */);
+ 0 /* roundedPadding */, false /* fillCutout */, true /* privacyDot */,
+ false /* faceScanning */);
mScreenDecorations.start();
@@ -1115,10 +1166,13 @@ public class ScreenDecorationsTest extends SysuiTestCase {
public void testSupportHwcLayer_SwitchFrom_NotSupport() {
setupResources(0 /* radius */, 10 /* radiusTop */, 20 /* radiusBottom */,
null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
- 0 /* roundedPadding */, false /* privacyDot */, false /* faceScanning */);
+ 0 /* roundedPadding */, true /* fillCutout */, false /* privacyDot */,
+ false /* faceScanning */);
// top cutout
- mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_TOP));
+ final Rect[] bounds = {null, new Rect(9, 0, 10, 1), null, null};
+ doReturn(getDisplayCutoutForRotation(Insets.of(0, 1, 0, 0), bounds))
+ .when(mScreenDecorations).getCutout();
mScreenDecorations.start();
// should only inflate mOverlays when the hwc doesn't support screen decoration
@@ -1141,13 +1195,16 @@ public class ScreenDecorationsTest extends SysuiTestCase {
public void testNotSupportHwcLayer_SwitchFrom_Support() {
setupResources(0 /* radius */, 10 /* radiusTop */, 20 /* radiusBottom */,
null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
- 0 /* roundedPadding */, false /* privacyDot */, false /* faceScanning */);
+ 0 /* roundedPadding */, true /* fillCutout */, false /* privacyDot */,
+ false /* faceScanning */);
final DisplayDecorationSupport decorationSupport = new DisplayDecorationSupport();
decorationSupport.format = PixelFormat.R_8;
doReturn(decorationSupport).when(mDisplay).getDisplayDecorationSupport();
// top cutout
- mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_TOP));
+ final Rect[] bounds = {null, new Rect(9, 0, 10, 1), null, null};
+ doReturn(getDisplayCutoutForRotation(Insets.of(0, 1, 0, 0), bounds))
+ .when(mScreenDecorations).getCutout();
mScreenDecorations.start();
// should only inflate hwc layer when the hwc supports screen decoration
@@ -1177,13 +1234,16 @@ public class ScreenDecorationsTest extends SysuiTestCase {
/* roundedTopDrawable */,
getTestsDrawable(com.android.systemui.tests.R.drawable.rounded4px)
/* roundedBottomDrawable */,
- 0 /* roundedPadding */, true /* privacyDot */, true /* faceScanning */);
+ 0 /* roundedPadding */, true /* fillCutout */, true /* privacyDot */,
+ true /* faceScanning */);
final DisplayDecorationSupport decorationSupport = new DisplayDecorationSupport();
decorationSupport.format = PixelFormat.R_8;
doReturn(decorationSupport).when(mDisplay).getDisplayDecorationSupport();
// top cutout
- mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_TOP));
+ final Rect[] bounds = {null, new Rect(9, 0, 10, 1), null, null};
+ doReturn(getDisplayCutoutForRotation(Insets.of(0, 1, 0, 0), bounds))
+ .when(mScreenDecorations).getCutout();
mScreenDecorations.start();
// Inflate top and bottom overlay with INVISIBLE because of only privacy dots on sw layer
@@ -1217,9 +1277,11 @@ public class ScreenDecorationsTest extends SysuiTestCase {
public void testAutoShowHideOverlayWindowWhenNoRoundedAndNoCutout() {
setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
- 0 /* roundedPadding */, true /* privacyDot */, true /* faceScanning */);
+ 0 /* roundedPadding */, false /* fillCutout */, true /* privacyDot */,
+ true /* faceScanning */);
- // no cutout (default)
+ // no cutout
+ doReturn(null).when(mScreenDecorations).getCutout();
mScreenDecorations.start();
// Inflate top and bottom overlay with INVISIBLE because of only privacy dots on sw layer
@@ -1253,13 +1315,16 @@ public class ScreenDecorationsTest extends SysuiTestCase {
public void testHwcLayer_noPrivacyDot_noFaceScanning() {
setupResources(0 /* radius */, 10 /* radiusTop */, 20 /* radiusBottom */,
null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
- 0 /* roundedPadding */, false /* privacyDot */, false /* faceScanning */);
+ 0 /* roundedPadding */, true /* fillCutout */, false /* privacyDot */,
+ false /* faceScanning */);
final DisplayDecorationSupport decorationSupport = new DisplayDecorationSupport();
decorationSupport.format = PixelFormat.R_8;
doReturn(decorationSupport).when(mDisplay).getDisplayDecorationSupport();
// top cutout
- mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_TOP));
+ final Rect[] bounds = {null, new Rect(9, 0, 10, 1), null, null};
+ doReturn(getDisplayCutoutForRotation(Insets.of(0, 1, 0, 0), bounds))
+ .when(mScreenDecorations).getCutout();
mScreenDecorations.start();
@@ -1272,13 +1337,16 @@ public class ScreenDecorationsTest extends SysuiTestCase {
public void testHwcLayer_PrivacyDot_FaceScanning() {
setupResources(0 /* radius */, 10 /* radiusTop */, 20 /* radiusBottom */,
null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
- 0 /* roundedPadding */, true /* privacyDot */, true /* faceScanning */);
+ 0 /* roundedPadding */, true /* fillCutout */, true /* privacyDot */,
+ true /* faceScanning */);
final DisplayDecorationSupport decorationSupport = new DisplayDecorationSupport();
decorationSupport.format = PixelFormat.R_8;
doReturn(decorationSupport).when(mDisplay).getDisplayDecorationSupport();
// top cutout
- mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_TOP));
+ final Rect[] bounds = {null, new Rect(9, 0, 10, 1), null, null};
+ doReturn(getDisplayCutoutForRotation(Insets.of(0, 1, 0, 0), bounds))
+ .when(mScreenDecorations).getCutout();
mScreenDecorations.start();
@@ -1296,13 +1364,16 @@ public class ScreenDecorationsTest extends SysuiTestCase {
public void testOnDisplayChanged_hwcLayer() {
setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
- 0 /* roundedPadding */, false /* privacyDot */, false /* faceScanning */);
+ 0 /* roundedPadding */, true /* fillCutout */, false /* privacyDot */,
+ false /* faceScanning */);
final DisplayDecorationSupport decorationSupport = new DisplayDecorationSupport();
decorationSupport.format = PixelFormat.R_8;
doReturn(decorationSupport).when(mDisplay).getDisplayDecorationSupport();
// top cutout
- mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_TOP));
+ final Rect[] bounds = {null, new Rect(9, 0, 10, 1), null, null};
+ doReturn(getDisplayCutoutForRotation(Insets.of(0, 1, 0, 0), bounds))
+ .when(mScreenDecorations).getCutout();
mScreenDecorations.start();
@@ -1319,16 +1390,18 @@ public class ScreenDecorationsTest extends SysuiTestCase {
public void testOnDisplayChanged_nonHwcLayer() {
setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
- 0 /* roundedPadding */, false /* privacyDot */, false /* faceScanning */);
+ 0 /* roundedPadding */, true /* fillCutout */, false /* privacyDot */,
+ false /* faceScanning */);
// top cutout
- mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_TOP));
+ final Rect[] bounds = {null, new Rect(9, 0, 10, 1), null, null};
+ doReturn(getDisplayCutoutForRotation(Insets.of(0, 1, 0, 0), bounds))
+ .when(mScreenDecorations).getCutout();
mScreenDecorations.start();
- final ScreenDecorations.DisplayCutoutView cutoutView = (ScreenDecorations.DisplayCutoutView)
- mScreenDecorations.getOverlayView(R.id.display_cutout);
- assertNotNull(cutoutView);
+ final ScreenDecorations.DisplayCutoutView cutoutView =
+ mScreenDecorations.mCutoutViews[BOUNDS_POSITION_TOP];
spyOn(cutoutView);
doReturn(mDisplay).when(cutoutView).getDisplay();
@@ -1341,7 +1414,8 @@ public class ScreenDecorationsTest extends SysuiTestCase {
public void testHasSameProvidersWithNullOverlays() {
setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
- 0 /* roundedPadding */, false /* privacyDot */, false /* faceScanning */);
+ 0 /* roundedPadding */, false /* fillCutout */, false /* privacyDot */,
+ false /* faceScanning */);
mScreenDecorations.start();
@@ -1359,7 +1433,8 @@ public class ScreenDecorationsTest extends SysuiTestCase {
public void testHasSameProvidersWithPrivacyDots() {
setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
- 0 /* roundedPadding */, true /* privacyDot */, false /* faceScanning */);
+ 0 /* roundedPadding */, true /* fillCutout */, true /* privacyDot */,
+ false /* faceScanning */);
mScreenDecorations.start();
@@ -1396,7 +1471,7 @@ public class ScreenDecorationsTest extends SysuiTestCase {
private void setupResources(int radius, int radiusTop, int radiusBottom,
@Nullable Drawable roundedTopDrawable, @Nullable Drawable roundedBottomDrawable,
- int roundedPadding, boolean privacyDot, boolean faceScanning) {
+ int roundedPadding, boolean fillCutout, boolean privacyDot, boolean faceScanning) {
mContext.getOrCreateTestableResources().addOverride(
com.android.internal.R.array.config_displayUniqueIdArray,
new String[]{});
@@ -1436,6 +1511,8 @@ public class ScreenDecorationsTest extends SysuiTestCase {
}
mContext.getOrCreateTestableResources().addOverride(
R.dimen.rounded_corner_content_padding, roundedPadding);
+ mContext.getOrCreateTestableResources().addOverride(
+ com.android.internal.R.bool.config_fillMainBuiltInDisplayCutout, fillCutout);
mPrivacyDecorProviders = new ArrayList<>();
if (privacyDot) {
@@ -1454,4 +1531,19 @@ public class ScreenDecorationsTest extends SysuiTestCase {
when(mFaceScanningProviderFactory.getProviders()).thenReturn(mFaceScanningProviders);
when(mFaceScanningProviderFactory.getHasProviders()).thenReturn(faceScanning);
}
+
+ private DisplayCutout getDisplayCutoutForRotation(Insets safeInsets, Rect[] cutoutBounds) {
+ final int rotation = mContext.getDisplay().getRotation();
+ final Insets insets = RotationUtils.rotateInsets(safeInsets, rotation);
+ final Rect[] sorted = new Rect[BOUNDS_POSITION_LENGTH];
+ for (int i = 0; i < BOUNDS_POSITION_LENGTH; i++) {
+ final int rotatedPos = ScreenDecorations.getBoundPositionFromRotation(i, rotation);
+ if (cutoutBounds[i] != null) {
+ RotationUtils.rotateBounds(cutoutBounds[i], new Rect(0, 0, 100, 200), rotation);
+ }
+ sorted[rotatedPos] = cutoutBounds[i];
+ }
+ return new DisplayCutout(insets, sorted[BOUNDS_POSITION_LEFT], sorted[BOUNDS_POSITION_TOP],
+ sorted[BOUNDS_POSITION_RIGHT], sorted[BOUNDS_POSITION_BOTTOM]);
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/SysuiBaseFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/SysuiBaseFragmentTest.java
index 8c20b248d02c..9179efc9f39f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/SysuiBaseFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/SysuiBaseFragmentTest.java
@@ -34,6 +34,8 @@ import org.junit.Before;
import org.junit.Rule;
import org.mockito.Mockito;
+import java.util.concurrent.ExecutionException;
+
public abstract class SysuiBaseFragmentTest extends BaseFragmentTest {
public static final Class<?>[] ALL_SUPPORTED_CLASSES = LeakCheckedTest.ALL_SUPPORTED_CLASSES;
@@ -54,10 +56,11 @@ public abstract class SysuiBaseFragmentTest extends BaseFragmentTest {
}
@Before
- public void SysuiSetup() {
- SystemUIFactory.createFromConfig(mContext, true);
- mDependency = new TestableDependency(
- SystemUIFactory.getInstance().getSysUIComponent().createDependency());
+ public void sysuiSetup() throws ExecutionException, InterruptedException {
+ SystemUIInitializer initializer =
+ SystemUIInitializerFactory.createFromConfigNoAssert(mContext);
+ initializer.init(true);
+ mDependency = new TestableDependency(initializer.getSysUIComponent().createDependency());
Dependency.setInstance(mDependency);
// TODO: Figure out another way to give reference to a SysuiTestableContext.
@@ -77,7 +80,6 @@ public abstract class SysuiBaseFragmentTest extends BaseFragmentTest {
public void SysuiTeardown() {
InstrumentationRegistry.registerInstance(mRealInstrumentation,
InstrumentationRegistry.getArguments());
- SystemUIFactory.cleanup();
}
@AfterClass
diff --git a/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java b/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java
index 8c7927782d2d..c52ea60f0bfc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java
@@ -76,9 +76,10 @@ public abstract class SysuiTestCase {
@Before
public void SysuiSetup() throws Exception {
- SystemUIFactory.createFromConfig(mContext, true);
- mDependency = new TestableDependency(
- SystemUIFactory.getInstance().getSysUIComponent().createDependency());
+ SystemUIInitializer initializer =
+ SystemUIInitializerFactory.createFromConfigNoAssert(mContext);
+ initializer.init(true);
+ mDependency = new TestableDependency(initializer.getSysUIComponent().createDependency());
Dependency.setInstance(mDependency);
mFakeBroadcastDispatcher = new FakeBroadcastDispatcher(mContext, mock(Looper.class),
mock(Executor.class), mock(DumpManager.class),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/DialogLaunchAnimatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/DialogLaunchAnimatorTest.kt
index 1e2074bfab98..4218e0904c43 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/animation/DialogLaunchAnimatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/animation/DialogLaunchAnimatorTest.kt
@@ -170,19 +170,27 @@ class DialogLaunchAnimatorTest : SysuiTestCase() {
@Test
fun testCujSpecificationLogsInteraction() {
val touchSurface = createTouchSurface()
- return runOnMainThreadAndWaitForIdleSync {
+ runOnMainThreadAndWaitForIdleSync {
val dialog = TestDialog(context)
dialogLaunchAnimator.showFromView(
- dialog, touchSurface,
- cuj = DialogCuj(InteractionJankMonitor.CUJ_SHADE_DIALOG_OPEN)
- )
+ dialog, touchSurface, cuj = DialogCuj(InteractionJankMonitor.CUJ_SHADE_DIALOG_OPEN))
}
- verify(interactionJankMonitor).begin(
- any()
- )
- verify(interactionJankMonitor)
- .end(InteractionJankMonitor.CUJ_SHADE_DIALOG_OPEN)
+ verify(interactionJankMonitor).begin(any())
+ verify(interactionJankMonitor).end(InteractionJankMonitor.CUJ_SHADE_DIALOG_OPEN)
+ }
+
+ @Test
+ fun testShowFromDialogCujSpecificationLogsInteraction() {
+ val firstDialog = createAndShowDialog()
+ runOnMainThreadAndWaitForIdleSync {
+ val dialog = TestDialog(context)
+ dialogLaunchAnimator.showFromDialog(
+ dialog, firstDialog, cuj = DialogCuj(InteractionJankMonitor.CUJ_USER_DIALOG_OPEN))
+ dialog
+ }
+ verify(interactionJankMonitor).begin(any())
+ verify(interactionJankMonitor).end(InteractionJankMonitor.CUJ_USER_DIALOG_OPEN)
}
private fun createAndShowDialog(): TestDialog {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/decor/CutoutDecorProviderFactoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/decor/CutoutDecorProviderFactoryTest.kt
deleted file mode 100644
index 1040ec453a7c..000000000000
--- a/packages/SystemUI/tests/src/com/android/systemui/decor/CutoutDecorProviderFactoryTest.kt
+++ /dev/null
@@ -1,200 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.decor
-
-import android.graphics.Insets
-import android.graphics.Rect
-import android.testing.AndroidTestingRunner
-import android.testing.TestableResources
-import android.util.RotationUtils
-import android.util.Size
-import android.view.Display
-import android.view.DisplayCutout
-import android.view.DisplayCutout.BOUNDS_POSITION_LENGTH
-import android.view.DisplayInfo
-import android.view.Surface
-import androidx.test.filters.SmallTest
-import com.android.systemui.SysuiTestCase
-import com.android.systemui.util.mockito.any
-import org.junit.Assert
-import org.junit.Before
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.mockito.Mock
-import org.mockito.Mockito.doAnswer
-import org.mockito.MockitoAnnotations
-
-@RunWith(AndroidTestingRunner::class)
-@SmallTest
-class CutoutDecorProviderFactoryTest : SysuiTestCase() {
-
- @Mock private lateinit var display: Display
- private var testableRes: TestableResources? = null
- private lateinit var factory: CutoutDecorProviderFactory
-
- @Before
- fun setUp() {
- MockitoAnnotations.initMocks(this)
- testableRes = mContext.orCreateTestableResources
- factory = CutoutDecorProviderFactory(testableRes!!.resources, display)
- }
-
- private fun setupFillCutout(fillCutout: Boolean) {
- testableRes!!.addOverride(
- com.android.internal.R.bool.config_fillMainBuiltInDisplayCutout, fillCutout
- )
- }
-
- private fun setupDisplayInfo(
- displayCutout: DisplayCutout? = null,
- @Surface.Rotation rotation: Int = Surface.ROTATION_0,
- displayId: Int = -1
- ) {
- doAnswer {
- it.getArgument<DisplayInfo>(0).let { info ->
- info.displayCutout = displayCutout
- info.rotation = rotation
- info.displayId = displayId
- }
- true
- }.`when`(display).getDisplayInfo(any<DisplayInfo>())
- }
-
- private fun getCutout(
- safeInsets: Insets,
- cutoutBounds: Array<Rect?>,
- @Surface.Rotation rotation: Int = Surface.ROTATION_0,
- cutoutParentSizeForRotate: Size = Size(100, 200)
- ): DisplayCutout {
- val insets = RotationUtils.rotateInsets(safeInsets, rotation)
- val sorted = arrayOfNulls<Rect>(BOUNDS_POSITION_LENGTH)
- for (pos in 0 until BOUNDS_POSITION_LENGTH) {
- val rotatedPos = (pos - rotation + BOUNDS_POSITION_LENGTH) % BOUNDS_POSITION_LENGTH
- if (cutoutBounds[pos] != null) {
- RotationUtils.rotateBounds(
- cutoutBounds[pos],
- cutoutParentSizeForRotate.width,
- cutoutParentSizeForRotate.height,
- rotation
- )
- }
- sorted[rotatedPos] = cutoutBounds[pos]
- }
- return DisplayCutout(
- insets,
- sorted[DisplayCutout.BOUNDS_POSITION_LEFT],
- sorted[DisplayCutout.BOUNDS_POSITION_TOP],
- sorted[DisplayCutout.BOUNDS_POSITION_RIGHT],
- sorted[DisplayCutout.BOUNDS_POSITION_BOTTOM]
- )
- }
-
- @Test
- fun testGetNothingIfNoCutout() {
- setupFillCutout(false)
-
- Assert.assertFalse(factory.hasProviders)
- Assert.assertEquals(0, factory.providers.size)
- }
-
- @Test
- fun testGetTopCutoutProvider() {
- setupFillCutout(true)
- setupDisplayInfo(
- getCutout(
- safeInsets = Insets.of(0, 1, 0, 0),
- cutoutBounds = arrayOf(null, Rect(9, 0, 10, 1), null, null)
- )
- )
-
- Assert.assertTrue(factory.hasProviders)
-
- val providers = factory.providers
- Assert.assertEquals(1, providers.size)
- Assert.assertEquals(1, providers[0].numOfAlignedBound)
- Assert.assertEquals(DisplayCutout.BOUNDS_POSITION_TOP, providers[0].alignedBounds[0])
- }
-
- @Test
- fun testGetBottomCutoutProviderOnLandscape() {
- setupFillCutout(true)
- setupDisplayInfo(
- getCutout(
- safeInsets = Insets.of(0, 0, 0, 1),
- cutoutBounds = arrayOf(null, null, null, Rect(45, 199, 55, 200)),
- rotation = Surface.ROTATION_90
- ),
- Surface.ROTATION_90
- )
-
- Assert.assertTrue(factory.hasProviders)
-
- val providers = factory.providers
- Assert.assertEquals(1, providers.size)
- Assert.assertEquals(1, providers[0].numOfAlignedBound)
- Assert.assertEquals(DisplayCutout.BOUNDS_POSITION_BOTTOM, providers[0].alignedBounds[0])
- }
-
- @Test
- fun testGetLeftCutoutProviderOnSeascape() {
- setupFillCutout(true)
- setupDisplayInfo(
- getCutout(
- safeInsets = Insets.of(1, 0, 0, 0),
- cutoutBounds = arrayOf(Rect(0, 20, 1, 40), null, null, null),
- rotation = Surface.ROTATION_270
- ),
- Surface.ROTATION_270
- )
-
- Assert.assertTrue(factory.hasProviders)
-
- val providers = factory.providers
- Assert.assertEquals(1, providers.size)
- Assert.assertEquals(1, providers[0].numOfAlignedBound)
- Assert.assertEquals(DisplayCutout.BOUNDS_POSITION_LEFT, providers[0].alignedBounds[0])
- }
-
- @Test
- fun testGetTopRightCutoutProviderOnReverse() {
- setupFillCutout(true)
- setupDisplayInfo(
- getCutout(
- safeInsets = Insets.of(0, 1, 1, 0),
- cutoutBounds = arrayOf(
- null,
- Rect(9, 0, 10, 1),
- Rect(99, 40, 100, 60),
- null
- ),
- rotation = Surface.ROTATION_180
- ),
- Surface.ROTATION_180
- )
-
- Assert.assertTrue(factory.hasProviders)
-
- val providers = factory.providers
- Assert.assertEquals(2, providers.size)
- Assert.assertEquals(1, providers[0].numOfAlignedBound)
- Assert.assertEquals(1, providers[1].numOfAlignedBound)
- providers.sortedBy { it.alignedBounds[0] }.let {
- Assert.assertEquals(DisplayCutout.BOUNDS_POSITION_TOP, it[0].alignedBounds[0])
- Assert.assertEquals(DisplayCutout.BOUNDS_POSITION_RIGHT, it[1].alignedBounds[0])
- }
- }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java
index 51c258055465..23516c94d851 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java
@@ -45,6 +45,7 @@ import androidx.slice.core.SliceQuery;
import androidx.test.filters.SmallTest;
import com.android.keyguard.KeyguardUpdateMonitor;
+import com.android.systemui.SystemUIInitializerImpl;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.NotificationMediaManager;
@@ -100,7 +101,7 @@ public class KeyguardSliceProviderTest extends SysuiTestCase {
MockitoAnnotations.initMocks(this);
mIsZenMode = false;
mProvider = new TestableKeyguardSliceProvider();
- mProvider.setContextAvailableCallback(context -> { });
+ mProvider.setContextAvailableCallback(context -> new SystemUIInitializerImpl(mContext));
mProvider.attachInfo(getContext(), null);
reset(mContentResolver);
SliceProvider.setSpecs(new HashSet<>(Arrays.asList(SliceSpecs.LIST)));
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
index a80aed7a6d18..9b665555562a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
@@ -203,6 +203,13 @@ public class KeyguardViewMediatorTest extends SysuiTestCase {
mViewMediator.mViewMediatorCallback.getBouncerPromptReason());
}
+ @Test
+ public void testHideSurfaceBehindKeyguardMarksKeyguardNotGoingAway() {
+ mViewMediator.hideSurfaceBehindKeyguard();
+
+ verify(mKeyguardStateController).notifyKeyguardGoingAway(false);
+ }
+
private void createAndStartViewMediator() {
mViewMediator = new KeyguardViewMediator(
mContext,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java
index 3f56cf9cb8ad..54cbe24df732 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java
@@ -206,11 +206,9 @@ public class NotificationInterruptStateProviderImplTest extends SysuiTestCase {
@Test
public void testDoNotRunFilterOnNewPipeline() {
- when(mFlags.isNewPipelineEnabled()).thenReturn(true);
// WHEN this entry should be filtered out
NotificationEntry entry = createNotification(IMPORTANCE_DEFAULT);
mNotifInterruptionStateProvider.shouldHeadsUp(entry);
- verify(mFlags, times(1)).isNewPipelineEnabled();
verify(mNotificationFilter, times(0)).shouldFilterOut(eq(entry));
}
@@ -326,7 +324,8 @@ public class NotificationInterruptStateProviderImplTest extends SysuiTestCase {
public void testShouldNotHeadsUp_filtered() throws RemoteException {
ensureStateForHeadsUpWhenAwake();
// Make canAlertCommon false by saying it's filtered out
- when(mNotificationFilter.shouldFilterOut(any())).thenReturn(true);
+ when(mKeyguardNotificationVisibilityProvider.shouldHideNotification(any()))
+ .thenReturn(true);
NotificationEntry entry = createNotification(IMPORTANCE_HIGH);
assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isFalse();
@@ -504,7 +503,8 @@ public class NotificationInterruptStateProviderImplTest extends SysuiTestCase {
ensureStateForBubbleUp();
// Make canAlertCommon false by saying it's filtered out
- when(mNotificationFilter.shouldFilterOut(any())).thenReturn(true);
+ when(mKeyguardNotificationVisibilityProvider.shouldHideNotification(any()))
+ .thenReturn(true);
assertThat(mNotifInterruptionStateProvider.shouldBubbleUp(createBubble())).isFalse();
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerLegacyTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerLegacyTest.java
deleted file mode 100644
index 429d2ed36cc7..000000000000
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerLegacyTest.java
+++ /dev/null
@@ -1,299 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.statusbar.notification.logging;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.app.Notification;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.UserHandle;
-import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper;
-
-import androidx.test.filters.SmallTest;
-
-import com.android.internal.logging.InstanceId;
-import com.android.internal.statusbar.IStatusBarService;
-import com.android.internal.statusbar.NotificationVisibility;
-import com.android.systemui.SysuiTestCase;
-import com.android.systemui.statusbar.NotificationListener;
-import com.android.systemui.statusbar.StatusBarState;
-import com.android.systemui.statusbar.StatusBarStateControllerImpl;
-import com.android.systemui.statusbar.notification.NotifPipelineFlags;
-import com.android.systemui.statusbar.notification.NotificationEntryManager;
-import com.android.systemui.statusbar.notification.collection.NotifLiveData;
-import com.android.systemui.statusbar.notification.collection.NotifLiveDataStore;
-import com.android.systemui.statusbar.notification.collection.NotifPipeline;
-import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
-import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider;
-import com.android.systemui.statusbar.notification.logging.nano.Notifications;
-import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
-import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
-import com.android.systemui.util.concurrency.FakeExecutor;
-import com.android.systemui.util.time.FakeSystemClock;
-
-import com.google.android.collect.Lists;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.Mockito;
-import org.mockito.MockitoAnnotations;
-
-import java.util.List;
-import java.util.concurrent.ConcurrentLinkedQueue;
-import java.util.concurrent.Executor;
-
-@SmallTest
-@RunWith(AndroidTestingRunner.class)
-@TestableLooper.RunWithLooper
-public class NotificationLoggerLegacyTest extends SysuiTestCase {
- private static final String TEST_PACKAGE_NAME = "test";
- private static final int TEST_UID = 0;
-
- @Mock private NotificationListContainer mListContainer;
- @Mock private IStatusBarService mBarService;
- @Mock private ExpandableNotificationRow mRow;
- @Mock private NotificationLogger.ExpansionStateLogger mExpansionStateLogger;
-
- // Dependency mocks:
- @Mock private NotifPipelineFlags mNotifPipelineFlags;
- @Mock private NotifLiveDataStore mNotifLiveDataStore;
- @Mock private NotifLiveData<List<NotificationEntry>> mActiveNotifList;
- @Mock private NotificationVisibilityProvider mVisibilityProvider;
- @Mock private NotificationEntryManager mEntryManager;
- @Mock private NotifPipeline mNotifPipeline;
- @Mock private NotificationListener mListener;
-
- private NotificationEntry mEntry;
- private TestableNotificationLogger mLogger;
- private ConcurrentLinkedQueue<AssertionError> mErrorQueue = new ConcurrentLinkedQueue<>();
- private FakeExecutor mUiBgExecutor = new FakeExecutor(new FakeSystemClock());
- private NotificationPanelLoggerFake mNotificationPanelLoggerFake =
- new NotificationPanelLoggerFake();
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
- when(mNotifLiveDataStore.getActiveNotifList()).thenReturn(mActiveNotifList);
-
- mEntry = new NotificationEntryBuilder()
- .setPkg(TEST_PACKAGE_NAME)
- .setOpPkg(TEST_PACKAGE_NAME)
- .setUid(TEST_UID)
- .setNotification(new Notification())
- .setUser(UserHandle.CURRENT)
- .setInstanceId(InstanceId.fakeInstanceId(1))
- .build();
- mEntry.setRow(mRow);
-
- mLogger = new TestableNotificationLogger(
- mListener,
- mUiBgExecutor,
- mNotifPipelineFlags,
- mNotifLiveDataStore,
- mVisibilityProvider,
- mEntryManager,
- mNotifPipeline,
- mock(StatusBarStateControllerImpl.class),
- mBarService,
- mExpansionStateLogger
- );
- mLogger.setUpWithContainer(mListContainer);
- verify(mEntryManager).addNotificationEntryListener(any());
- verify(mNotifPipeline, never()).addCollectionListener(any());
- }
-
- @After
- public void tearDown() {
- mLogger.mHandler.removeCallbacksAndMessages(null);
- }
-
- @Test
- public void testOnChildLocationsChangedReportsVisibilityChanged() throws Exception {
- NotificationVisibility[] newlyVisibleKeys = {
- NotificationVisibility.obtain(mEntry.getKey(), 0, 1, true)
- };
- NotificationVisibility[] noLongerVisibleKeys = {};
- doAnswer(invocation -> {
- try {
- assertArrayEquals(newlyVisibleKeys,
- (NotificationVisibility[]) invocation.getArguments()[0]);
- assertArrayEquals(noLongerVisibleKeys,
- (NotificationVisibility[]) invocation.getArguments()[1]);
- } catch (AssertionError error) {
- mErrorQueue.offer(error);
- }
- return null;
- }
- ).when(mBarService).onNotificationVisibilityChanged(any(NotificationVisibility[].class),
- any(NotificationVisibility[].class));
-
- when(mListContainer.isInVisibleLocation(any())).thenReturn(true);
- when(mActiveNotifList.getValue()).thenReturn(Lists.newArrayList(mEntry));
- mLogger.getChildLocationsChangedListenerForTest().onChildLocationsChanged();
- TestableLooper.get(this).processAllMessages();
- mUiBgExecutor.runAllReady();
-
- if (!mErrorQueue.isEmpty()) {
- throw mErrorQueue.poll();
- }
-
- // |mEntry| won't change visibility, so it shouldn't be reported again:
- Mockito.reset(mBarService);
- mLogger.getChildLocationsChangedListenerForTest().onChildLocationsChanged();
- TestableLooper.get(this).processAllMessages();
- mUiBgExecutor.runAllReady();
-
- verify(mBarService, never()).onNotificationVisibilityChanged(any(), any());
- }
-
- @Test
- public void testStoppingNotificationLoggingReportsCurrentNotifications()
- throws Exception {
- when(mListContainer.isInVisibleLocation(any())).thenReturn(true);
- when(mActiveNotifList.getValue()).thenReturn(Lists.newArrayList(mEntry));
- mLogger.getChildLocationsChangedListenerForTest().onChildLocationsChanged();
- TestableLooper.get(this).processAllMessages();
- mUiBgExecutor.runAllReady();
- Mockito.reset(mBarService);
-
- setStateAsleep();
- mLogger.onDozingChanged(false); // Wake to lockscreen
- mLogger.onDozingChanged(true); // And go back to sleep, turning off logging
- mUiBgExecutor.runAllReady();
- // The visibility objects are recycled by NotificationLogger, so we can't use specific
- // matchers here.
- verify(mBarService, times(1)).onNotificationVisibilityChanged(any(), any());
- }
-
- private void setStateAsleep() {
- mLogger.onPanelExpandedChanged(true);
- mLogger.onDozingChanged(true);
- mLogger.onStateChanged(StatusBarState.KEYGUARD);
- }
-
- private void setStateAwake() {
- mLogger.onPanelExpandedChanged(false);
- mLogger.onDozingChanged(false);
- mLogger.onStateChanged(StatusBarState.SHADE);
- }
-
- @Test
- public void testLogPanelShownOnWake() {
- when(mActiveNotifList.getValue()).thenReturn(Lists.newArrayList(mEntry));
- setStateAsleep();
- mLogger.onDozingChanged(false); // Wake to lockscreen
- assertEquals(1, mNotificationPanelLoggerFake.getCalls().size());
- assertTrue(mNotificationPanelLoggerFake.get(0).isLockscreen);
- assertEquals(1, mNotificationPanelLoggerFake.get(0).list.notifications.length);
- Notifications.Notification n = mNotificationPanelLoggerFake.get(0).list.notifications[0];
- assertEquals(TEST_PACKAGE_NAME, n.packageName);
- assertEquals(TEST_UID, n.uid);
- assertEquals(1, n.instanceId);
- assertFalse(n.isGroupSummary);
- assertEquals(Notifications.Notification.SECTION_ALERTING, n.section);
- }
-
- @Test
- public void testLogPanelShownOnShadePull() {
- when(mActiveNotifList.getValue()).thenReturn(Lists.newArrayList(mEntry));
- setStateAwake();
- // Now expand panel
- mLogger.onPanelExpandedChanged(true);
- assertEquals(1, mNotificationPanelLoggerFake.getCalls().size());
- assertFalse(mNotificationPanelLoggerFake.get(0).isLockscreen);
- assertEquals(1, mNotificationPanelLoggerFake.get(0).list.notifications.length);
- Notifications.Notification n = mNotificationPanelLoggerFake.get(0).list.notifications[0];
- assertEquals(TEST_PACKAGE_NAME, n.packageName);
- assertEquals(TEST_UID, n.uid);
- assertEquals(1, n.instanceId);
- assertFalse(n.isGroupSummary);
- assertEquals(Notifications.Notification.SECTION_ALERTING, n.section);
- }
-
-
- @Test
- public void testLogPanelShownHandlesNullInstanceIds() {
- // Construct a NotificationEntry like mEntry, but with a null instance id.
- NotificationEntry entry = new NotificationEntryBuilder()
- .setPkg(TEST_PACKAGE_NAME)
- .setOpPkg(TEST_PACKAGE_NAME)
- .setUid(TEST_UID)
- .setNotification(new Notification())
- .setUser(UserHandle.CURRENT)
- .build();
- entry.setRow(mRow);
-
- when(mActiveNotifList.getValue()).thenReturn(Lists.newArrayList(entry));
- setStateAsleep();
- mLogger.onDozingChanged(false); // Wake to lockscreen
- assertEquals(1, mNotificationPanelLoggerFake.getCalls().size());
- assertEquals(1, mNotificationPanelLoggerFake.get(0).list.notifications.length);
- Notifications.Notification n = mNotificationPanelLoggerFake.get(0).list.notifications[0];
- assertEquals(0, n.instanceId);
- }
-
- private class TestableNotificationLogger extends NotificationLogger {
-
- TestableNotificationLogger(NotificationListener notificationListener,
- Executor uiBgExecutor,
- NotifPipelineFlags notifPipelineFlags,
- NotifLiveDataStore notifLiveDataStore,
- NotificationVisibilityProvider visibilityProvider,
- NotificationEntryManager entryManager,
- NotifPipeline notifPipeline,
- StatusBarStateControllerImpl statusBarStateController,
- IStatusBarService barService,
- ExpansionStateLogger expansionStateLogger) {
- super(
- notificationListener,
- uiBgExecutor,
- notifPipelineFlags,
- notifLiveDataStore,
- visibilityProvider,
- entryManager,
- notifPipeline,
- statusBarStateController,
- expansionStateLogger,
- mNotificationPanelLoggerFake
- );
- mBarService = barService;
- mHandler.removeCallbacksAndMessages(null);
- // Make this on the current thread so we can wait for it during tests.
- mHandler = Handler.createAsync(Looper.myLooper());
- }
-
- OnChildLocationsChangedListener getChildLocationsChangedListenerForTest() {
- return mNotificationLocationsChangedListener;
- }
- }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java
index b69bd8dfca9c..8a7b9d3b6024 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java
@@ -103,7 +103,6 @@ public class NotificationLoggerTest extends SysuiTestCase {
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
- when(mNotifPipelineFlags.isNewPipelineEnabled()).thenReturn(true);
when(mNotifLiveDataStore.getActiveNotifList()).thenReturn(mActiveNotifEntries);
mEntry = new NotificationEntryBuilder()
@@ -278,10 +277,8 @@ public class NotificationLoggerTest extends SysuiTestCase {
super(
notificationListener,
uiBgExecutor,
- notifPipelineFlags,
notifLiveDataStore,
visibilityProvider,
- entryManager,
notifPipeline,
statusBarStateController,
expansionStateLogger,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
index 2e26a2be4382..b4532c431415 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
@@ -322,10 +322,8 @@ public class CentralSurfacesImplTest extends SysuiTestCase {
NotificationLogger notificationLogger = new NotificationLogger(
mNotificationListener,
mUiBgExecutor,
- mNotifPipelineFlags,
mNotifLiveDataStore,
mVisibilityProvider,
- mock(NotificationEntryManager.class),
mock(NotifPipeline.class),
mStatusBarStateController,
mExpansionStateLogger,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaTest.kt
index 4b557dc423ff..3440fa5ac9b1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaTest.kt
@@ -42,7 +42,6 @@ class KeyguardBottomAreaTest : SysuiTestCase() {
mKeyguardBottomArea = LayoutInflater.from(mContext).inflate(
R.layout.keyguard_bottom_area, null, false) as KeyguardBottomAreaView
- mKeyguardBottomArea.setCentralSurfaces(mCentralSurfaces)
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java
index 7fd61cfecfac..5b0f3c4b32ae 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java
@@ -487,7 +487,6 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase {
mNotificationPanelViewController = new NotificationPanelViewController(
mView,
- mResources,
mMainHandler,
mLayoutInflater,
mFeatureFlags,
@@ -528,8 +527,6 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase {
mQuickAccessWalletController,
mQrCodeScannerController,
mRecordingController,
- mExecutor,
- mSecureSettings,
mLargeScreenShadeHeaderController,
mScreenOffAnimationController,
mLockscreenGestureLogger,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java
index 3d03c4750869..6f9e60fc5d69 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java
@@ -44,6 +44,7 @@ import com.android.systemui.SysuiBaseFragmentTest;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.log.LogBuffer;
import com.android.systemui.log.LogcatEchoTracker;
+import com.android.systemui.plugins.DarkIconDispatcher;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.DisableFlagsLogger;
@@ -112,6 +113,7 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest {
@Before
public void setup() {
injectLeakCheckedDependencies(ALL_SUPPORTED_CLASSES);
+ mDependency.injectMockDependency(DarkIconDispatcher.class);
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/UserSwitcherControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/UserSwitcherControllerTest.kt
index e0bf9e7b0081..1af8a77b1610 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/UserSwitcherControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/UserSwitcherControllerTest.kt
@@ -44,6 +44,7 @@ import com.android.systemui.GuestResumeSessionReceiver
import com.android.systemui.GuestSessionNotification
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
+import com.android.systemui.animation.DialogCuj
import com.android.systemui.animation.DialogLaunchAnimator
import com.android.systemui.broadcast.BroadcastDispatcher
import com.android.systemui.broadcast.BroadcastSender
@@ -72,12 +73,12 @@ import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentMatchers.anyInt
import org.mockito.Mock
-import org.mockito.Mockito.`when`
import org.mockito.Mockito.doNothing
import org.mockito.Mockito.doReturn
import org.mockito.Mockito.eq
import org.mockito.Mockito.mock
import org.mockito.Mockito.verify
+import org.mockito.Mockito.`when`
import org.mockito.MockitoAnnotations
@RunWith(AndroidTestingRunner::class)
@@ -362,7 +363,10 @@ class UserSwitcherControllerTest : SysuiTestCase() {
userSwitcherController.onUserListItemClicked(currentGuestUserRecord, dialogShower)
assertNotNull(userSwitcherController.mExitGuestDialog)
testableLooper.processAllMessages()
- verify(dialogShower).showDialog(userSwitcherController.mExitGuestDialog)
+ verify(dialogShower)
+ .showDialog(
+ userSwitcherController.mExitGuestDialog,
+ DialogCuj(InteractionJankMonitor.CUJ_USER_DIALOG_OPEN, "exit_guest_mode"))
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/service/ObservableServiceConnectionTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/service/ObservableServiceConnectionTest.java
index 22d7273dcd20..046ad1293521 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/service/ObservableServiceConnectionTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/service/ObservableServiceConnectionTest.java
@@ -145,4 +145,28 @@ public class ObservableServiceConnectionTest extends SysuiTestCase {
connection.unbind();
verify(mContext, never()).unbindService(eq(connection));
}
+
+ @Test
+ public void testUnbind() {
+ ObservableServiceConnection<Foo> connection = new ObservableServiceConnection<>(mContext,
+ mIntent, mExecutor, mTransformer);
+ connection.addCallback(mCallback);
+ connection.onServiceDisconnected(mComponentName);
+
+ // Disconnects before binds should be ignored.
+ verify(mCallback, never()).onDisconnected(eq(connection), anyInt());
+
+ when(mContext.bindService(eq(mIntent), anyInt(), eq(mExecutor), eq(connection)))
+ .thenReturn(true);
+ connection.bind();
+
+ mExecutor.runAllReady();
+
+ connection.unbind();
+
+ mExecutor.runAllReady();
+
+ verify(mCallback).onDisconnected(eq(connection),
+ eq(ObservableServiceConnection.DISCONNECT_REASON_UNBIND));
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/service/PersistentConnectionManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/service/PersistentConnectionManagerTest.java
index 53d4a96b0640..db0139c9b0d1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/service/PersistentConnectionManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/service/PersistentConnectionManagerTest.java
@@ -16,6 +16,7 @@
package com.android.systemui.util.service;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import android.testing.AndroidTestingRunner;
@@ -120,6 +121,24 @@ public class PersistentConnectionManagerTest extends SysuiTestCase {
}
/**
+ * Ensures manual unbind does not reconnect.
+ */
+ @Test
+ public void testStopDoesNotReconnect() {
+ mConnectionManager.start();
+ ArgumentCaptor<ObservableServiceConnection.Callback<Proxy>> connectionCallbackCaptor =
+ ArgumentCaptor.forClass(ObservableServiceConnection.Callback.class);
+
+ verify(mConnection).addCallback(connectionCallbackCaptor.capture());
+ verify(mConnection).bind();
+ Mockito.clearInvocations(mConnection);
+ mConnectionManager.stop();
+ mFakeExecutor.advanceClockToNext();
+ mFakeExecutor.runAllReady();
+ verify(mConnection, never()).bind();
+ }
+
+ /**
* Ensures rebind on package change.
*/
@Test
diff --git a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
index 9b29bae1fc46..b34482f0964f 100644
--- a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
+++ b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
@@ -2300,9 +2300,9 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
int processId, long threadId, int callingUid, Bundle callingStack) {
if (mTrace.isA11yTracingEnabledForTypes(loggingTypes)) {
ArrayList<StackTraceElement> list =
- (ArrayList<StackTraceElement>) callingStack.getSerializable(CALL_STACK);
+ (ArrayList<StackTraceElement>) callingStack.getSerializable(CALL_STACK, java.util.ArrayList.class);
HashSet<String> ignoreList =
- (HashSet<String>) callingStack.getSerializable(IGNORE_CALL_STACK);
+ (HashSet<String>) callingStack.getSerializable(IGNORE_CALL_STACK, java.util.HashSet.class);
mTrace.logTrace(timestamp, where, loggingTypes, callingParams, processId, threadId,
callingUid, list.toArray(new StackTraceElement[list.size()]), ignoreList);
}
diff --git a/services/accessibility/java/com/android/server/accessibility/PolicyWarningUIController.java b/services/accessibility/java/com/android/server/accessibility/PolicyWarningUIController.java
index af816451dca2..7fd859ca9333 100644
--- a/services/accessibility/java/com/android/server/accessibility/PolicyWarningUIController.java
+++ b/services/accessibility/java/com/android/server/accessibility/PolicyWarningUIController.java
@@ -227,7 +227,7 @@ public class PolicyWarningUIController {
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
final ComponentName componentName = intent.getParcelableExtra(
- Intent.EXTRA_COMPONENT_NAME);
+ Intent.EXTRA_COMPONENT_NAME, android.content.ComponentName.class);
if (TextUtils.isEmpty(action) || componentName == null) {
return;
}
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceShellCommand.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceShellCommand.java
index 1eaa59a0871a..b09cb00f5eed 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceShellCommand.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceShellCommand.java
@@ -251,7 +251,7 @@ public final class AutofillManagerServiceShellCommand extends ShellCommand {
final CountDownLatch latch = new CountDownLatch(1);
mService.calculateScore(algorithm, value1, value2, new RemoteCallback((result) -> {
- final Scores scores = result.getParcelable(EXTRA_SCORES);
+ final Scores scores = result.getParcelable(EXTRA_SCORES, android.service.autofill.AutofillFieldClassificationService.Scores.class);
if (scores == null) {
pw.println("no score");
} else {
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 9f9846117a29..1fea539fa016 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -395,7 +395,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
Slog.v(TAG, "mDelayedFillBroadcastReceiver delayed fill action received");
synchronized (mLock) {
int requestId = intent.getIntExtra(EXTRA_REQUEST_ID, 0);
- FillResponse response = intent.getParcelableExtra(EXTRA_FILL_RESPONSE);
+ FillResponse response = intent.getParcelableExtra(EXTRA_FILL_RESPONSE, android.service.autofill.FillResponse.class);
mAssistReceiver.processDelayedFillLocked(requestId, response);
}
}
@@ -559,7 +559,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
return;
}
- final AssistStructure structure = resultData.getParcelable(ASSIST_KEY_STRUCTURE);
+ final AssistStructure structure = resultData.getParcelable(ASSIST_KEY_STRUCTURE, android.app.assist.AssistStructure.class);
if (structure == null) {
Slog.e(TAG, "No assist structure - app might have crashed providing it");
return;
@@ -1811,7 +1811,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
@GuardedBy("mLock")
void setAuthenticationResultForAugmentedAutofillLocked(Bundle data, int authId) {
final Dataset dataset = (data == null) ? null :
- data.getParcelable(AutofillManager.EXTRA_AUTHENTICATION_RESULT);
+ data.getParcelable(AutofillManager.EXTRA_AUTHENTICATION_RESULT, android.service.autofill.Dataset.class);
if (sDebug) {
Slog.d(TAG, "Auth result for augmented autofill: sessionId=" + id
+ ", authId=" + authId + ", dataset=" + dataset);
@@ -2251,7 +2251,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
logContextCommitted(null, null, saveDialogNotShowReason, commitReason);
return;
}
- final Scores scores = result.getParcelable(EXTRA_SCORES);
+ final Scores scores = result.getParcelable(EXTRA_SCORES, android.service.autofill.AutofillFieldClassificationService.Scores.class);
if (scores == null) {
Slog.w(TAG, "No field classification score on " + result);
return;
diff --git a/services/companion/java/com/android/server/companion/AssociationRequestsProcessor.java b/services/companion/java/com/android/server/companion/AssociationRequestsProcessor.java
index 5457ef9acaf7..b3314ede8e50 100644
--- a/services/companion/java/com/android/server/companion/AssociationRequestsProcessor.java
+++ b/services/companion/java/com/android/server/companion/AssociationRequestsProcessor.java
@@ -300,10 +300,10 @@ class AssociationRequestsProcessor {
return;
}
- final AssociationRequest request = data.getParcelable(EXTRA_ASSOCIATION_REQUEST);
+ final AssociationRequest request = data.getParcelable(EXTRA_ASSOCIATION_REQUEST, android.companion.AssociationRequest.class);
final IAssociationRequestCallback callback = IAssociationRequestCallback.Stub
.asInterface(data.getBinder(EXTRA_APPLICATION_CALLBACK));
- final ResultReceiver resultReceiver = data.getParcelable(EXTRA_RESULT_RECEIVER);
+ final ResultReceiver resultReceiver = data.getParcelable(EXTRA_RESULT_RECEIVER, android.os.ResultReceiver.class);
requireNonNull(request);
requireNonNull(callback);
@@ -313,7 +313,7 @@ class AssociationRequestsProcessor {
if (request.isSelfManaged()) {
macAddress = null;
} else {
- macAddress = data.getParcelable(EXTRA_MAC_ADDRESS);
+ macAddress = data.getParcelable(EXTRA_MAC_ADDRESS, android.net.MacAddress.class);
requireNonNull(macAddress);
}
diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java
index 41a759254909..7a95a8fe8c7f 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java
@@ -446,8 +446,8 @@ final class ContentCapturePerUserService
@NonNull Bundle data) {
final int id = getSessionId(activityToken);
final Bundle assistData = data.getBundle(ASSIST_KEY_DATA);
- final AssistStructure assistStructure = data.getParcelable(ASSIST_KEY_STRUCTURE);
- final AssistContent assistContent = data.getParcelable(ASSIST_KEY_CONTENT);
+ final AssistStructure assistStructure = data.getParcelable(ASSIST_KEY_STRUCTURE, android.app.assist.AssistStructure.class);
+ final AssistContent assistContent = data.getParcelable(ASSIST_KEY_CONTENT, android.app.assist.AssistContent.class);
final SnapshotData snapshotData = new SnapshotData(assistData,
assistStructure, assistContent);
if (id != NO_SESSION_ID) {
diff --git a/services/core/java/com/android/server/ExplicitHealthCheckController.java b/services/core/java/com/android/server/ExplicitHealthCheckController.java
index 77059d918052..20de40e73130 100644
--- a/services/core/java/com/android/server/ExplicitHealthCheckController.java
+++ b/services/core/java/com/android/server/ExplicitHealthCheckController.java
@@ -246,7 +246,7 @@ class ExplicitHealthCheckController {
try {
mRemoteService.getSupportedPackages(new RemoteCallback(result -> {
List<PackageConfig> packages =
- result.getParcelableArrayList(EXTRA_SUPPORTED_PACKAGES);
+ result.getParcelableArrayList(EXTRA_SUPPORTED_PACKAGES, android.service.watchdog.ExplicitHealthCheckService.PackageConfig.class);
Slog.i(TAG, "Explicit health check supported packages " + packages);
consumer.accept(packages);
}));
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index ce3502c8f442..9cdb2df6bc79 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -351,6 +351,8 @@ class StorageManagerService extends IStorageManager.Stub
private static final float DEFAULT_LOW_BATTERY_LEVEL = 20F;
// Decide whether charging is required to turn on the feature
private static final boolean DEFAULT_CHARGING_REQUIRED = true;
+ // Minimum GC interval sleep time in ms
+ private static final int DEFAULT_MIN_GC_SLEEPTIME = 10000;
private volatile int mLifetimePercentThreshold;
private volatile int mMinSegmentsThreshold;
@@ -358,6 +360,7 @@ class StorageManagerService extends IStorageManager.Stub
private volatile float mSegmentReclaimWeight;
private volatile float mLowBatteryLevel;
private volatile boolean mChargingRequired;
+ private volatile int mMinGCSleepTime;
private volatile boolean mNeedGC;
private volatile boolean mPassedLifetimeThresh;
@@ -2576,6 +2579,8 @@ class StorageManagerService extends IStorageManager.Stub
"low_battery_level", DEFAULT_LOW_BATTERY_LEVEL);
mChargingRequired = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT,
"charging_required", DEFAULT_CHARGING_REQUIRED);
+ mMinGCSleepTime = DeviceConfig.getInt(DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT,
+ "min_gc_sleeptime", DEFAULT_MIN_GC_SLEEPTIME);
// If we use the smart idle maintenance, we need to turn off GC in the traditional idle
// maintenance to avoid the conflict
@@ -2693,6 +2698,14 @@ class StorageManagerService extends IStorageManager.Stub
enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
try {
+ int latestWrite = mVold.getWriteAmount();
+ if (latestWrite == -1) {
+ Slog.w(TAG, "Failed to get storage write record");
+ return;
+ }
+
+ updateStorageWriteRecords(latestWrite);
+
// Block based checkpoint process runs fstrim. So, if checkpoint is in progress
// (first boot after OTA), We skip the smart idle maintenance
if (!needsCheckpoint() || !supportsBlockCheckpoint()) {
@@ -2700,13 +2713,6 @@ class StorageManagerService extends IStorageManager.Stub
return;
}
- int latestWrite = mVold.getWriteAmount();
- if (latestWrite == -1) {
- Slog.w(TAG, "Failed to get storage write record");
- return;
- }
-
- updateStorageWriteRecords(latestWrite);
int avgWriteAmount = getAverageWriteAmount();
Slog.i(TAG, "Set smart idle maintenance: " + "latest write amount: " +
@@ -2714,9 +2720,11 @@ class StorageManagerService extends IStorageManager.Stub
", min segment threshold: " + mMinSegmentsThreshold +
", dirty reclaim rate: " + mDirtyReclaimRate +
", segment reclaim weight: " + mSegmentReclaimWeight +
- ", period: " + sSmartIdleMaintPeriod);
+ ", period(min): " + sSmartIdleMaintPeriod +
+ ", min gc sleep time(ms): " + mMinGCSleepTime);
mVold.setGCUrgentPace(avgWriteAmount, mMinSegmentsThreshold, mDirtyReclaimRate,
- mSegmentReclaimWeight, sSmartIdleMaintPeriod);
+ mSegmentReclaimWeight, sSmartIdleMaintPeriod,
+ mMinGCSleepTime);
} else {
Slog.i(TAG, "Skipping smart idle maintenance - block based checkpoint in progress");
}
diff --git a/services/core/java/com/android/server/Watchdog.java b/services/core/java/com/android/server/Watchdog.java
index 76c897aac051..7cf790ad5b54 100644
--- a/services/core/java/com/android/server/Watchdog.java
+++ b/services/core/java/com/android/server/Watchdog.java
@@ -230,10 +230,10 @@ public class Watchdog implements Dumpable {
private final String mName;
private final ArrayList<Monitor> mMonitors = new ArrayList<Monitor>();
private final ArrayList<Monitor> mMonitorQueue = new ArrayList<Monitor>();
- private long mWaitMax;
+ private long mWaitMaxMillis;
private boolean mCompleted;
private Monitor mCurrentMonitor;
- private long mStartTime;
+ private long mStartTimeMillis;
private int mPauseCount;
HandlerChecker(Handler handler, String name) {
@@ -254,7 +254,7 @@ public class Watchdog implements Dumpable {
* @param handlerCheckerTimeoutMillis the timeout to use for this run
*/
public void scheduleCheckLocked(long handlerCheckerTimeoutMillis) {
- mWaitMax = handlerCheckerTimeoutMillis;
+ mWaitMaxMillis = handlerCheckerTimeoutMillis;
if (mCompleted) {
// Safe to update monitors in queue, Handler is not in the middle of work
mMonitors.addAll(mMonitorQueue);
@@ -279,7 +279,7 @@ public class Watchdog implements Dumpable {
mCompleted = false;
mCurrentMonitor = null;
- mStartTime = SystemClock.uptimeMillis();
+ mStartTimeMillis = SystemClock.uptimeMillis();
mHandler.postAtFrontOfQueue(this);
}
@@ -287,10 +287,10 @@ public class Watchdog implements Dumpable {
if (mCompleted) {
return COMPLETED;
} else {
- long latency = SystemClock.uptimeMillis() - mStartTime;
- if (latency < mWaitMax/2) {
+ long latency = SystemClock.uptimeMillis() - mStartTimeMillis;
+ if (latency < mWaitMaxMillis / 2) {
return WAITING;
- } else if (latency < mWaitMax) {
+ } else if (latency < mWaitMaxMillis) {
return WAITED_HALF;
}
}
@@ -306,14 +306,17 @@ public class Watchdog implements Dumpable {
}
String describeBlockedStateLocked() {
- Thread thread = getThread();
- String threadIdentifier = thread.getName() + ", tid=" + thread.getId();
+ final String prefix;
if (mCurrentMonitor == null) {
- return "Blocked in handler on " + mName + " (" + threadIdentifier + ")";
+ prefix = "Blocked in handler on ";
} else {
- return "Blocked in monitor " + mCurrentMonitor.getClass().getName()
- + " on " + mName + " (" + threadIdentifier + ")";
+ prefix = "Blocked in monitor " + mCurrentMonitor.getClass().getName();
}
+ Thread thread = getThread();
+ String threadIdentifier = thread.getName() + ", tid=" + thread.getId();
+ long latencySeconds = (SystemClock.uptimeMillis() - mStartTimeMillis) / 1000;
+ return prefix + " on " + mName + " (" + threadIdentifier + ")"
+ + " for " + latencySeconds + "s";
}
@Override
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index 6b731c319c4b..eb0f3f00d291 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -3090,7 +3090,7 @@ public class AccountManagerService
}
}
- Intent intent = result.getParcelable(AccountManager.KEY_INTENT);
+ Intent intent = result.getParcelable(AccountManager.KEY_INTENT, android.content.Intent.class);
if (intent != null && notifyOnAuthFailure && !customTokens) {
/*
* Make sure that the supplied intent is owned by the authenticator
@@ -3516,7 +3516,7 @@ public class AccountManagerService
mNumResults++;
Intent intent = null;
if (result != null
- && (intent = result.getParcelable(AccountManager.KEY_INTENT)) != null) {
+ && (intent = result.getParcelable(AccountManager.KEY_INTENT, android.content.Intent.class)) != null) {
if (!checkKeyIntent(
Binder.getCallingUid(),
intent)) {
@@ -5048,7 +5048,7 @@ public class AccountManagerService
}
}
if (result != null
- && (intent = result.getParcelable(AccountManager.KEY_INTENT)) != null) {
+ && (intent = result.getParcelable(AccountManager.KEY_INTENT, android.content.Intent.class)) != null) {
if (!checkKeyIntent(
Binder.getCallingUid(),
intent)) {
diff --git a/services/core/java/com/android/server/adb/AdbDebuggingManager.java b/services/core/java/com/android/server/adb/AdbDebuggingManager.java
index 049f4bea6fa1..2eaf323ea370 100644
--- a/services/core/java/com/android/server/adb/AdbDebuggingManager.java
+++ b/services/core/java/com/android/server/adb/AdbDebuggingManager.java
@@ -649,7 +649,7 @@ public class AdbDebuggingManager {
} else if (WifiManager.NETWORK_STATE_CHANGED_ACTION.equals(action)) {
// We only care about wifi type connections
NetworkInfo networkInfo = (NetworkInfo) intent.getParcelableExtra(
- WifiManager.EXTRA_NETWORK_INFO);
+ WifiManager.EXTRA_NETWORK_INFO, android.net.NetworkInfo.class);
if (networkInfo.getType() == ConnectivityManager.TYPE_WIFI) {
// Check for network disconnect
if (!networkInfo.isConnected()) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 60286bece7d7..e49e63acd388 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -14445,6 +14445,19 @@ public class ActivityManagerService extends IActivityManager.Stub
final int callingPid = Binder.getCallingPid();
final int callingUid = Binder.getCallingUid();
+ // Non-system callers can't declare that a broadcast is alarm-related.
+ // The PendingIntent invocation case is handled in PendingIntentRecord.
+ if (bOptions != null && callingUid != SYSTEM_UID) {
+ if (bOptions.containsKey(BroadcastOptions.KEY_ALARM_BROADCAST)) {
+ if (DEBUG_BROADCAST) {
+ Slog.w(TAG, "Non-system caller " + callingUid
+ + " may not flag broadcast as alarm-related");
+ }
+ throw new SecurityException(
+ "Non-system callers may not flag broadcasts as alarm-related");
+ }
+ }
+
final long origId = Binder.clearCallingIdentity();
try {
return broadcastIntentLocked(callerApp,
@@ -14458,6 +14471,7 @@ public class ActivityManagerService extends IActivityManager.Stub
}
}
+ // Not the binder call surface
int broadcastIntentInPackage(String packageName, @Nullable String featureId, int uid,
int realCallingUid, int realCallingPid, Intent intent, String resolvedType,
IIntentReceiver resultTo, int resultCode, String resultData, Bundle resultExtras,
diff --git a/services/core/java/com/android/server/am/BroadcastRecord.java b/services/core/java/com/android/server/am/BroadcastRecord.java
index 19ffc1733f3d..ae91d75ef0ce 100644
--- a/services/core/java/com/android/server/am/BroadcastRecord.java
+++ b/services/core/java/com/android/server/am/BroadcastRecord.java
@@ -70,6 +70,7 @@ final class BroadcastRecord extends Binder {
final boolean callerInstantApp; // caller is an Instant App?
final boolean ordered; // serialize the send to receivers?
final boolean sticky; // originated from existing sticky data?
+ final boolean alarm; // originated from an alarm triggering?
final boolean initialSticky; // initial broadcast from register to sticky?
final int userId; // user id this broadcast was for
final String resolvedType; // the resolved data type
@@ -305,6 +306,7 @@ final class BroadcastRecord extends Binder {
this.allowBackgroundActivityStarts = allowBackgroundActivityStarts;
mBackgroundActivityStartsToken = backgroundActivityStartsToken;
this.timeoutExempt = timeoutExempt;
+ alarm = options != null && options.isAlarmBroadcast();
}
/**
@@ -357,6 +359,7 @@ final class BroadcastRecord extends Binder {
allowBackgroundActivityStarts = from.allowBackgroundActivityStarts;
mBackgroundActivityStartsToken = from.mBackgroundActivityStartsToken;
timeoutExempt = from.timeoutExempt;
+ alarm = from.alarm;
}
/**
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index c65e61a2b60f..9607e401f9c8 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -1482,7 +1482,9 @@ public class OomAdjuster {
if (!cycleReEval) {
// Don't reset this flag when doing cycles re-evaluation.
state.setNoKillOnBgRestrictedAndIdle(false);
- app.mOptRecord.setShouldNotFreeze(false);
+ // If this UID is currently allowlisted, it should not be frozen.
+ final UidRecord uidRec = app.getUidRecord();
+ app.mOptRecord.setShouldNotFreeze(uidRec != null && uidRec.isCurAllowListed());
}
final int appUid = app.info.uid;
diff --git a/services/core/java/com/android/server/am/PendingIntentRecord.java b/services/core/java/com/android/server/am/PendingIntentRecord.java
index 4044cceb606b..bda60ff2172b 100644
--- a/services/core/java/com/android/server/am/PendingIntentRecord.java
+++ b/services/core/java/com/android/server/am/PendingIntentRecord.java
@@ -18,6 +18,7 @@ package com.android.server.am;
import static android.app.ActivityManager.START_SUCCESS;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BROADCAST_LIGHT;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
@@ -34,6 +35,7 @@ import android.os.Bundle;
import android.os.IBinder;
import android.os.PowerWhitelistManager;
import android.os.PowerWhitelistManager.ReasonCode;
+import android.os.Process;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.TransactionTooLargeException;
@@ -416,6 +418,22 @@ public final class PendingIntentRecord extends IIntentSender.Stub {
final int callingUid = Binder.getCallingUid();
final int callingPid = Binder.getCallingPid();
+
+ // Only system senders can declare a broadcast to be alarm-originated. We check
+ // this here rather than in the general case handling below to fail before the other
+ // invocation side effects such as allowlisting.
+ if (options != null && callingUid != Process.SYSTEM_UID
+ && key.type == ActivityManager.INTENT_SENDER_BROADCAST) {
+ if (options.containsKey(BroadcastOptions.KEY_ALARM_BROADCAST)) {
+ if (DEBUG_BROADCAST_LIGHT) {
+ Slog.w(TAG, "Non-system caller " + callingUid
+ + " may not flag broadcast as alarm-related");
+ }
+ throw new SecurityException(
+ "Non-system callers may not flag broadcasts as alarm-related");
+ }
+ }
+
final long origId = Binder.clearCallingIdentity();
int res = START_SUCCESS;
diff --git a/services/core/java/com/android/server/audio/BtHelper.java b/services/core/java/com/android/server/audio/BtHelper.java
index 0e3823275777..73e4cf23c347 100644
--- a/services/core/java/com/android/server/audio/BtHelper.java
+++ b/services/core/java/com/android/server/audio/BtHelper.java
@@ -303,7 +303,7 @@ public class BtHelper {
Log.i(TAG, "receiveBtEvent action: " + action + " mScoAudioState: " + mScoAudioState);
if (action.equals(BluetoothHeadset.ACTION_ACTIVE_DEVICE_CHANGED)) {
- BluetoothDevice btDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
+ BluetoothDevice btDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE, android.bluetooth.BluetoothDevice.class);
setBtScoActiveDevice(btDevice);
} else if (action.equals(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED)) {
int btState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1);
diff --git a/services/core/java/com/android/server/camera/CameraServiceProxy.java b/services/core/java/com/android/server/camera/CameraServiceProxy.java
index b425420479f0..66ef5e761194 100644
--- a/services/core/java/com/android/server/camera/CameraServiceProxy.java
+++ b/services/core/java/com/android/server/camera/CameraServiceProxy.java
@@ -355,7 +355,7 @@ public class CameraServiceProxy extends SystemService
case UsbManager.ACTION_USB_DEVICE_ATTACHED:
case UsbManager.ACTION_USB_DEVICE_DETACHED:
synchronized (mLock) {
- UsbDevice device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
+ UsbDevice device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE, android.hardware.usb.UsbDevice.class);
if (device != null) {
notifyUsbDeviceHotplugLocked(device,
action.equals(UsbManager.ACTION_USB_DEVICE_ATTACHED));
diff --git a/services/core/java/com/android/server/clipboard/ClipboardService.java b/services/core/java/com/android/server/clipboard/ClipboardService.java
index 61350bb6095e..076ac2b4bfe7 100644
--- a/services/core/java/com/android/server/clipboard/ClipboardService.java
+++ b/services/core/java/com/android/server/clipboard/ClipboardService.java
@@ -215,9 +215,12 @@ public class ClipboardService extends SystemService {
private class ListenerInfo {
final int mUid;
final String mPackageName;
- ListenerInfo(int uid, String packageName) {
+ final String mAttributionTag;
+
+ ListenerInfo(int uid, String packageName, String attributionTag) {
mUid = uid;
mPackageName = packageName;
+ mAttributionTag = attributionTag;
}
}
@@ -355,27 +358,43 @@ public class ClipboardService extends SystemService {
}
@Override
- public void setPrimaryClip(ClipData clip, String callingPackage, @UserIdInt int userId) {
- checkAndSetPrimaryClip(clip, callingPackage, userId, callingPackage);
+ public void setPrimaryClip(
+ ClipData clip,
+ String callingPackage,
+ String attributionTag,
+ @UserIdInt int userId) {
+ checkAndSetPrimaryClip(clip, callingPackage, attributionTag, userId, callingPackage);
}
@Override
public void setPrimaryClipAsPackage(
- ClipData clip, String callingPackage, @UserIdInt int userId, String sourcePackage) {
+ ClipData clip,
+ String callingPackage,
+ String attributionTag,
+ @UserIdInt int userId,
+ String sourcePackage) {
getContext().enforceCallingOrSelfPermission(Manifest.permission.SET_CLIP_SOURCE,
"Requires SET_CLIP_SOURCE permission");
- checkAndSetPrimaryClip(clip, callingPackage, userId, sourcePackage);
+ checkAndSetPrimaryClip(clip, callingPackage, attributionTag, userId, sourcePackage);
}
private void checkAndSetPrimaryClip(
- ClipData clip, String callingPackage, @UserIdInt int userId, String sourcePackage) {
+ ClipData clip,
+ String callingPackage,
+ String attributionTag,
+ @UserIdInt int userId,
+ String sourcePackage) {
if (clip == null || clip.getItemCount() <= 0) {
throw new IllegalArgumentException("No items");
}
final int intendingUid = getIntendingUid(callingPackage, userId);
final int intendingUserId = UserHandle.getUserId(intendingUid);
- if (!clipboardAccessAllowed(AppOpsManager.OP_WRITE_CLIPBOARD, callingPackage,
- intendingUid, intendingUserId)) {
+ if (!clipboardAccessAllowed(
+ AppOpsManager.OP_WRITE_CLIPBOARD,
+ callingPackage,
+ attributionTag,
+ intendingUid,
+ intendingUserId)) {
return;
}
checkDataOwner(clip, intendingUid);
@@ -392,8 +411,13 @@ public class ClipboardService extends SystemService {
PROPERTY_AUTO_CLEAR_ENABLED, true)) {
mClipboardClearHandler.removeEqualMessages(ClipboardClearHandler.MSG_CLEAR,
userId);
- Message clearMessage = Message.obtain(mClipboardClearHandler,
- ClipboardClearHandler.MSG_CLEAR, userId, intendingUid, userId);
+ Message clearMessage =
+ Message.obtain(
+ mClipboardClearHandler,
+ ClipboardClearHandler.MSG_CLEAR,
+ userId,
+ intendingUid,
+ userId);
mClipboardClearHandler.sendMessageDelayed(clearMessage,
getTimeoutForAutoClear());
}
@@ -409,11 +433,16 @@ public class ClipboardService extends SystemService {
}
@Override
- public void clearPrimaryClip(String callingPackage, @UserIdInt int userId) {
+ public void clearPrimaryClip(
+ String callingPackage, String attributionTag, @UserIdInt int userId) {
final int intendingUid = getIntendingUid(callingPackage, userId);
final int intendingUserId = UserHandle.getUserId(intendingUid);
- if (!clipboardAccessAllowed(AppOpsManager.OP_WRITE_CLIPBOARD, callingPackage,
- intendingUid, intendingUserId)) {
+ if (!clipboardAccessAllowed(
+ AppOpsManager.OP_WRITE_CLIPBOARD,
+ callingPackage,
+ attributionTag,
+ intendingUid,
+ intendingUserId)) {
return;
}
synchronized (mLock) {
@@ -424,11 +453,15 @@ public class ClipboardService extends SystemService {
}
@Override
- public ClipData getPrimaryClip(String pkg, @UserIdInt int userId) {
+ public ClipData getPrimaryClip(String pkg, String attributionTag, @UserIdInt int userId) {
final int intendingUid = getIntendingUid(pkg, userId);
final int intendingUserId = UserHandle.getUserId(intendingUid);
- if (!clipboardAccessAllowed(AppOpsManager.OP_READ_CLIPBOARD, pkg,
- intendingUid, intendingUserId)
+ if (!clipboardAccessAllowed(
+ AppOpsManager.OP_READ_CLIPBOARD,
+ pkg,
+ attributionTag,
+ intendingUid,
+ intendingUserId)
|| isDeviceLocked(intendingUserId)) {
return null;
}
@@ -453,12 +486,17 @@ public class ClipboardService extends SystemService {
}
@Override
- public ClipDescription getPrimaryClipDescription(String callingPackage,
- @UserIdInt int userId) {
+ public ClipDescription getPrimaryClipDescription(
+ String callingPackage, String attributionTag, @UserIdInt int userId) {
final int intendingUid = getIntendingUid(callingPackage, userId);
final int intendingUserId = UserHandle.getUserId(intendingUid);
- if (!clipboardAccessAllowed(AppOpsManager.OP_READ_CLIPBOARD, callingPackage,
- intendingUid, intendingUserId, false)
+ if (!clipboardAccessAllowed(
+ AppOpsManager.OP_READ_CLIPBOARD,
+ callingPackage,
+ attributionTag,
+ intendingUid,
+ intendingUserId,
+ false)
|| isDeviceLocked(intendingUserId)) {
return null;
}
@@ -470,11 +508,17 @@ public class ClipboardService extends SystemService {
}
@Override
- public boolean hasPrimaryClip(String callingPackage, @UserIdInt int userId) {
+ public boolean hasPrimaryClip(
+ String callingPackage, String attributionTag, @UserIdInt int userId) {
final int intendingUid = getIntendingUid(callingPackage, userId);
final int intendingUserId = UserHandle.getUserId(intendingUid);
- if (!clipboardAccessAllowed(AppOpsManager.OP_READ_CLIPBOARD, callingPackage,
- intendingUid, intendingUserId, false)
+ if (!clipboardAccessAllowed(
+ AppOpsManager.OP_READ_CLIPBOARD,
+ callingPackage,
+ attributionTag,
+ intendingUid,
+ intendingUserId,
+ false)
|| isDeviceLocked(intendingUserId)) {
return false;
}
@@ -484,19 +528,28 @@ public class ClipboardService extends SystemService {
}
@Override
- public void addPrimaryClipChangedListener(IOnPrimaryClipChangedListener listener,
- String callingPackage, @UserIdInt int userId) {
+ public void addPrimaryClipChangedListener(
+ IOnPrimaryClipChangedListener listener,
+ String callingPackage,
+ String attributionTag,
+ @UserIdInt int userId) {
final int intendingUid = getIntendingUid(callingPackage, userId);
final int intendingUserId = UserHandle.getUserId(intendingUid);
synchronized (mLock) {
- getClipboardLocked(intendingUserId).primaryClipListeners.register(listener,
- new ListenerInfo(intendingUid, callingPackage));
+ getClipboardLocked(intendingUserId)
+ .primaryClipListeners
+ .register(
+ listener,
+ new ListenerInfo(intendingUid, callingPackage, attributionTag));
}
}
@Override
- public void removePrimaryClipChangedListener(IOnPrimaryClipChangedListener listener,
- String callingPackage, @UserIdInt int userId) {
+ public void removePrimaryClipChangedListener(
+ IOnPrimaryClipChangedListener listener,
+ String callingPackage,
+ String attributionTag,
+ @UserIdInt int userId) {
final int intendingUserId = getIntendingUserId(callingPackage, userId);
synchronized (mLock) {
getClipboardLocked(intendingUserId).primaryClipListeners.unregister(listener);
@@ -504,11 +557,16 @@ public class ClipboardService extends SystemService {
}
@Override
- public boolean hasClipboardText(String callingPackage, int userId) {
+ public boolean hasClipboardText(String callingPackage, String attributionTag, int userId) {
final int intendingUid = getIntendingUid(callingPackage, userId);
final int intendingUserId = UserHandle.getUserId(intendingUid);
- if (!clipboardAccessAllowed(AppOpsManager.OP_READ_CLIPBOARD, callingPackage,
- intendingUid, intendingUserId, false)
+ if (!clipboardAccessAllowed(
+ AppOpsManager.OP_READ_CLIPBOARD,
+ callingPackage,
+ attributionTag,
+ intendingUid,
+ intendingUserId,
+ false)
|| isDeviceLocked(intendingUserId)) {
return false;
}
@@ -523,13 +581,19 @@ public class ClipboardService extends SystemService {
}
@Override
- public String getPrimaryClipSource(String callingPackage, int userId) {
+ public String getPrimaryClipSource(
+ String callingPackage, String attributionTag, int userId) {
getContext().enforceCallingOrSelfPermission(Manifest.permission.SET_CLIP_SOURCE,
"Requires SET_CLIP_SOURCE permission");
final int intendingUid = getIntendingUid(callingPackage, userId);
final int intendingUserId = UserHandle.getUserId(intendingUid);
- if (!clipboardAccessAllowed(AppOpsManager.OP_READ_CLIPBOARD, callingPackage,
- intendingUid, intendingUserId, false)
+ if (!clipboardAccessAllowed(
+ AppOpsManager.OP_READ_CLIPBOARD,
+ callingPackage,
+ attributionTag,
+ intendingUid,
+ intendingUserId,
+ false)
|| isDeviceLocked(intendingUserId)) {
return null;
}
@@ -718,8 +782,12 @@ public class ClipboardService extends SystemService {
ListenerInfo li = (ListenerInfo)
clipboard.primaryClipListeners.getBroadcastCookie(i);
- if (clipboardAccessAllowed(AppOpsManager.OP_READ_CLIPBOARD, li.mPackageName,
- li.mUid, UserHandle.getUserId(li.mUid))) {
+ if (clipboardAccessAllowed(
+ AppOpsManager.OP_READ_CLIPBOARD,
+ li.mPackageName,
+ li.mAttributionTag,
+ li.mUid,
+ UserHandle.getUserId(li.mUid))) {
clipboard.primaryClipListeners.getBroadcastItem(i)
.dispatchPrimaryClipChanged();
}
@@ -965,13 +1033,18 @@ public class ClipboardService extends SystemService {
}
}
- private boolean clipboardAccessAllowed(int op, String callingPackage, int uid,
- @UserIdInt int userId) {
- return clipboardAccessAllowed(op, callingPackage, uid, userId, true);
+ private boolean clipboardAccessAllowed(
+ int op, String callingPackage, String attributionTag, int uid, @UserIdInt int userId) {
+ return clipboardAccessAllowed(op, callingPackage, attributionTag, uid, userId, true);
}
- private boolean clipboardAccessAllowed(int op, String callingPackage, int uid,
- @UserIdInt int userId, boolean shouldNoteOp) {
+ private boolean clipboardAccessAllowed(
+ int op,
+ String callingPackage,
+ String attributionTag,
+ int uid,
+ @UserIdInt int userId,
+ boolean shouldNoteOp) {
boolean allowed;
@@ -1040,7 +1113,7 @@ public class ClipboardService extends SystemService {
// Finally, check the app op.
int appOpsResult;
if (shouldNoteOp) {
- appOpsResult = mAppOps.noteOp(op, uid, callingPackage);
+ appOpsResult = mAppOps.noteOp(op, uid, callingPackage, attributionTag, null);
} else {
appOpsResult = mAppOps.checkOp(op, uid, callingPackage);
}
diff --git a/services/core/java/com/android/server/display/WifiDisplayController.java b/services/core/java/com/android/server/display/WifiDisplayController.java
index a7e1a2876f81..5b204ad9c853 100644
--- a/services/core/java/com/android/server/display/WifiDisplayController.java
+++ b/services/core/java/com/android/server/display/WifiDisplayController.java
@@ -1090,7 +1090,7 @@ final class WifiDisplayController implements DumpUtils.Dump {
handlePeersChanged();
} else if (action.equals(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION)) {
NetworkInfo networkInfo = (NetworkInfo)intent.getParcelableExtra(
- WifiP2pManager.EXTRA_NETWORK_INFO);
+ WifiP2pManager.EXTRA_NETWORK_INFO, android.net.NetworkInfo.class);
if (DEBUG) {
Slog.d(TAG, "Received WIFI_P2P_CONNECTION_CHANGED_ACTION: networkInfo="
+ networkInfo);
@@ -1099,7 +1099,7 @@ final class WifiDisplayController implements DumpUtils.Dump {
handleConnectionChanged(networkInfo);
} else if (action.equals(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION)) {
mThisDevice = (WifiP2pDevice) intent.getParcelableExtra(
- WifiP2pManager.EXTRA_WIFI_P2P_DEVICE);
+ WifiP2pManager.EXTRA_WIFI_P2P_DEVICE, android.net.wifi.p2p.WifiP2pDevice.class);
if (DEBUG) {
Slog.d(TAG, "Received WIFI_P2P_THIS_DEVICE_CHANGED_ACTION: mThisDevice= "
+ mThisDevice);
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 3c0cc6d60c7a..deea90f31e9e 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -173,7 +173,6 @@ import com.android.internal.inputmethod.StartInputReason;
import com.android.internal.inputmethod.UnbindReason;
import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
import com.android.internal.notification.SystemNotificationChannels;
-import com.android.internal.os.SomeArgs;
import com.android.internal.os.TransferPipe;
import com.android.internal.util.ConcurrentUtils;
import com.android.internal.util.DumpUtils;
@@ -3412,7 +3411,6 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
@Override
public void reportPerceptibleAsync(IBinder windowToken, boolean perceptible) {
Objects.requireNonNull(windowToken, "windowToken must not be null");
- int uid = Binder.getCallingUid();
synchronized (ImfLock.class) {
if (!calledFromValidUserLocked()) {
return;
@@ -4694,7 +4692,6 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
@UiThread
@Override
public boolean handleMessage(Message msg) {
- SomeArgs args;
switch (msg.what) {
case MSG_SHOW_IM_SUBTYPE_PICKER:
final boolean showAuxSubtypes;
diff --git a/services/core/java/com/android/server/location/contexthub/ContextHubClientBroker.java b/services/core/java/com/android/server/location/contexthub/ContextHubClientBroker.java
index 9fb1d8e744fb..c04768651c08 100644
--- a/services/core/java/com/android/server/location/contexthub/ContextHubClientBroker.java
+++ b/services/core/java/com/android/server/location/contexthub/ContextHubClientBroker.java
@@ -322,6 +322,17 @@ public class ContextHubClientBroker extends IContextHubClient.Stub
} else {
mPendingIntentRequest = new PendingIntentRequest(pendingIntent, nanoAppId);
}
+
+ if (packageName == null) {
+ String[] packages = mContext.getPackageManager().getPackagesForUid(
+ Binder.getCallingUid());
+ if (packages != null && packages.length > 0) {
+ packageName = packages[0];
+ }
+ Log.e(TAG, "createClient: Provided package name null. Using first package name "
+ + packageName);
+ }
+
mPackage = packageName;
mAttributionTag = attributionTag;
mTransactionManager = transactionManager;
diff --git a/services/core/java/com/android/server/location/contexthub/ContextHubService.java b/services/core/java/com/android/server/location/contexthub/ContextHubService.java
index 95178f4c7883..7100ac8f0d9f 100644
--- a/services/core/java/com/android/server/location/contexthub/ContextHubService.java
+++ b/services/core/java/com/android/server/location/contexthub/ContextHubService.java
@@ -1042,6 +1042,9 @@ public class ContextHubService extends IContextHubService.Stub {
}
/* package */ void denyClientAuthState(int contextHubId, String packageName, long nanoAppId) {
+ Log.i(TAG, "Denying " + packageName + " access to " + Long.toHexString(nanoAppId)
+ + " on context hub # " + contextHubId);
+
mClientManager.forEachClientOfHub(contextHubId, client -> {
if (client.getPackageName().equals(packageName)) {
client.updateNanoAppAuthState(
@@ -1201,11 +1204,11 @@ public class ContextHubService extends IContextHubService.Stub {
}
} else {
Log.d(TAG, "BT adapter not available. Defaulting to disabled");
- if (mIsBtMainEnabled) {
+ if (forceUpdate || mIsBtMainEnabled) {
mIsBtMainEnabled = false;
mContextHubWrapper.onBtMainSettingChanged(mIsBtMainEnabled);
}
- if (mIsBtScanningEnabled) {
+ if (forceUpdate || mIsBtScanningEnabled) {
mIsBtScanningEnabled = false;
mContextHubWrapper.onBtScanningSettingChanged(mIsBtScanningEnabled);
}
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsStorage.java b/services/core/java/com/android/server/locksettings/LockSettingsStorage.java
index 9ddf1efbaef2..8161503652ff 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsStorage.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsStorage.java
@@ -202,6 +202,16 @@ class LockSettingsStorage extends WatchableImpl {
}
@VisibleForTesting
+ boolean isKeyValueCached(String key, int userId) {
+ return mCache.hasKeyValue(key, userId);
+ }
+
+ @VisibleForTesting
+ boolean isUserPrefetched(int userId) {
+ return mCache.isFetched(userId);
+ }
+
+ @VisibleForTesting
public void removeKey(String key, int userId) {
removeKey(mOpenHelper.getWritableDatabase(), key, userId);
}
@@ -762,19 +772,24 @@ class LockSettingsStorage extends WatchableImpl {
}
}
- /**
- * Cache consistency model:
- * - Writes to storage write directly to the cache, but this MUST happen within the atomic
- * section either provided by the database transaction or mWriteLock, such that writes to the
- * cache and writes to the backing storage are guaranteed to occur in the same order
+ /*
+ * A cache for the following types of data:
+ *
+ * - Key-value entries from the locksettings database, where the key is the combination of a
+ * userId and a string key, and the value is a string.
+ * - File paths to file contents.
+ * - The per-user "prefetched" flag.
*
- * - Reads can populate the cache, but because they are no strong ordering guarantees with
- * respect to writes this precaution is taken:
- * - The cache is assigned a version number that increases every time the cache is modified.
- * Reads from backing storage can only populate the cache if the backing storage
- * has not changed since the load operation has begun.
- * This guarantees that no read operation can shadow a write to the cache that happens
- * after it had begun.
+ * Cache consistency model:
+ * - Writes to storage write directly to the cache, but this MUST happen within an atomic
+ * section either provided by the database transaction or mFileWriteLock, such that writes to
+ * the cache and writes to the backing storage are guaranteed to occur in the same order.
+ * - Reads can populate the cache, but because there are no strong ordering guarantees with
+ * respect to writes the following precaution is taken: The cache is assigned a version
+ * number that increases every time the backing storage is modified. Reads from backing
+ * storage can only populate the cache if the backing storage has not changed since the load
+ * operation has begun. This guarantees that a read operation can't clobber a different value
+ * that was written to the cache by a concurrent write operation.
*/
private static class Cache {
private final ArrayMap<CacheKey, Object> mCache = new ArrayMap<>();
@@ -819,7 +834,7 @@ class LockSettingsStorage extends WatchableImpl {
}
void setFetched(int userId) {
- put(CacheKey.TYPE_FETCHED, "isFetched", "true", userId);
+ put(CacheKey.TYPE_FETCHED, "", "true", userId);
}
boolean isFetched(int userId) {
@@ -828,10 +843,11 @@ class LockSettingsStorage extends WatchableImpl {
private synchronized void remove(int type, String key, int userId) {
mCache.remove(mCacheKey.set(type, key, userId));
+ mVersion++;
}
private synchronized void put(int type, String key, Object value, int userId) {
- // Create a new CachKey here because it may be saved in the map if the key is absent.
+ // Create a new CacheKey here because it may be saved in the map if the key is absent.
mCache.put(new CacheKey().set(type, key, userId), value);
mVersion++;
}
@@ -839,7 +855,9 @@ class LockSettingsStorage extends WatchableImpl {
private synchronized void putIfUnchanged(int type, String key, Object value, int userId,
int version) {
if (!contains(type, key, userId) && mVersion == version) {
- put(type, key, value, userId);
+ mCache.put(new CacheKey().set(type, key, userId), value);
+ // Don't increment mVersion, as this method should only be called in cases where the
+ // backing storage isn't being modified.
}
}
diff --git a/services/core/java/com/android/server/locksettings/ResumeOnRebootServiceProvider.java b/services/core/java/com/android/server/locksettings/ResumeOnRebootServiceProvider.java
index ec80521be2e5..70fdccdf2f7f 100644
--- a/services/core/java/com/android/server/locksettings/ResumeOnRebootServiceProvider.java
+++ b/services/core/java/com/android/server/locksettings/ResumeOnRebootServiceProvider.java
@@ -182,7 +182,7 @@ public class ResumeOnRebootServiceProvider {
waitForLatch(binderLatch, "wrapSecret", timeOutInMillis);
if (resultCallback.getResult().containsKey(ResumeOnRebootService.EXCEPTION_KEY)) {
throwTypedException(resultCallback.getResult().getParcelable(
- ResumeOnRebootService.EXCEPTION_KEY));
+ ResumeOnRebootService.EXCEPTION_KEY, android.os.ParcelableException.class));
}
return resultCallback.mResult.getByteArray(ResumeOnRebootService.WRAPPED_BLOB_KEY);
}
@@ -202,7 +202,7 @@ public class ResumeOnRebootServiceProvider {
waitForLatch(binderLatch, "unWrapSecret", timeOut);
if (resultCallback.getResult().containsKey(ResumeOnRebootService.EXCEPTION_KEY)) {
throwTypedException(resultCallback.getResult().getParcelable(
- ResumeOnRebootService.EXCEPTION_KEY));
+ ResumeOnRebootService.EXCEPTION_KEY, android.os.ParcelableException.class));
}
return resultCallback.getResult().getByteArray(
ResumeOnRebootService.UNWRAPPED_BLOB_KEY);
diff --git a/services/core/java/com/android/server/media/BluetoothRouteProvider.java b/services/core/java/com/android/server/media/BluetoothRouteProvider.java
index d4d3a39c724e..e1a990d0f6bd 100644
--- a/services/core/java/com/android/server/media/BluetoothRouteProvider.java
+++ b/services/core/java/com/android/server/media/BluetoothRouteProvider.java
@@ -500,7 +500,7 @@ class BluetoothRouteProvider {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
- BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
+ BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE, android.bluetooth.BluetoothDevice.class);
BluetoothEventReceiver receiver = mEventReceiverMap.get(action);
if (receiver != null) {
diff --git a/services/core/java/com/android/server/media/MediaRouterService.java b/services/core/java/com/android/server/media/MediaRouterService.java
index e61f55381b0c..82dfd3ae178b 100644
--- a/services/core/java/com/android/server/media/MediaRouterService.java
+++ b/services/core/java/com/android/server/media/MediaRouterService.java
@@ -956,7 +956,7 @@ public final class MediaRouterService extends IMediaRouterService.Stub
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(BluetoothA2dp.ACTION_ACTIVE_DEVICE_CHANGED)) {
- BluetoothDevice btDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
+ BluetoothDevice btDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE, android.bluetooth.BluetoothDevice.class);
synchronized (mLock) {
mActiveBluetoothDevice = btDevice;
mGlobalBluetoothA2dpOn = btDevice != null;
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 1ea949ede03d..f2a12b468fef 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -1299,7 +1299,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
// on background handler thread, and verified MANAGE_NETWORK_POLICY
// permission above.
- final NetworkTemplate template = intent.getParcelableExtra(EXTRA_NETWORK_TEMPLATE);
+ final NetworkTemplate template = intent.getParcelableExtra(EXTRA_NETWORK_TEMPLATE, android.net.NetworkTemplate.class);
if (ACTION_SNOOZE_WARNING.equals(intent.getAction())) {
performSnooze(template, TYPE_WARNING);
} else if (ACTION_SNOOZE_RAPID.equals(intent.getAction())) {
diff --git a/services/core/java/com/android/server/notification/CountdownConditionProvider.java b/services/core/java/com/android/server/notification/CountdownConditionProvider.java
index 4b70e2e31888..efca5986e35a 100644
--- a/services/core/java/com/android/server/notification/CountdownConditionProvider.java
+++ b/services/core/java/com/android/server/notification/CountdownConditionProvider.java
@@ -155,7 +155,7 @@ public class CountdownConditionProvider extends SystemConditionProviderService {
@Override
public void onReceive(Context context, Intent intent) {
if (ACTION.equals(intent.getAction())) {
- final Uri conditionId = intent.getParcelableExtra(EXTRA_CONDITION_ID);
+ final Uri conditionId = intent.getParcelableExtra(EXTRA_CONDITION_ID, android.net.Uri.class);
final boolean alarm = ZenModeConfig.isValidCountdownToAlarmConditionId(conditionId);
final long time = ZenModeConfig.tryParseCountdownConditionId(conditionId);
if (DEBUG) Slog.d(TAG, "Countdown condition fired: " + conditionId);
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index d3580a4e3317..e35e4c9b178b 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -7031,6 +7031,7 @@ public class NotificationManagerService extends SystemService {
@GuardedBy("mNotificationLock")
void snoozeLocked(NotificationRecord r) {
+ final List<NotificationRecord> recordsToSnooze = new ArrayList<>();
if (r.getSbn().isGroup()) {
final List<NotificationRecord> groupNotifications =
findCurrentAndSnoozedGroupNotificationsLocked(
@@ -7039,8 +7040,8 @@ public class NotificationManagerService extends SystemService {
if (r.getNotification().isGroupSummary()) {
// snooze all children
for (int i = 0; i < groupNotifications.size(); i++) {
- if (mKey != groupNotifications.get(i).getKey()) {
- snoozeNotificationLocked(groupNotifications.get(i));
+ if (!mKey.equals(groupNotifications.get(i).getKey())) {
+ recordsToSnooze.add(groupNotifications.get(i));
}
}
} else {
@@ -7050,8 +7051,8 @@ public class NotificationManagerService extends SystemService {
if (groupNotifications.size() == 2) {
// snooze summary and the one child
for (int i = 0; i < groupNotifications.size(); i++) {
- if (mKey != groupNotifications.get(i).getKey()) {
- snoozeNotificationLocked(groupNotifications.get(i));
+ if (!mKey.equals(groupNotifications.get(i).getKey())) {
+ recordsToSnooze.add(groupNotifications.get(i));
}
}
}
@@ -7059,7 +7060,15 @@ public class NotificationManagerService extends SystemService {
}
}
// snooze the notification
- snoozeNotificationLocked(r);
+ recordsToSnooze.add(r);
+
+ if (mSnoozeHelper.canSnooze(recordsToSnooze.size())) {
+ for (int i = 0; i < recordsToSnooze.size(); i++) {
+ snoozeNotificationLocked(recordsToSnooze.get(i));
+ }
+ } else {
+ Log.w(TAG, "Cannot snooze " + r.getKey() + ": too many snoozed notifications");
+ }
}
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index cbaf485c077f..6dd0daa77ac6 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -682,7 +682,7 @@ public final class NotificationRecord {
if (signals.containsKey(Adjustment.KEY_SNOOZE_CRITERIA)) {
final ArrayList<SnoozeCriterion> snoozeCriterionList =
adjustment.getSignals().getParcelableArrayList(
- Adjustment.KEY_SNOOZE_CRITERIA);
+ Adjustment.KEY_SNOOZE_CRITERIA, android.service.notification.SnoozeCriterion.class);
setSnoozeCriteria(snoozeCriterionList);
EventLogTags.writeNotificationAdjusted(getKey(), Adjustment.KEY_SNOOZE_CRITERIA,
snoozeCriterionList.toString());
@@ -708,7 +708,7 @@ public final class NotificationRecord {
}
if (signals.containsKey(Adjustment.KEY_CONTEXTUAL_ACTIONS)) {
setSystemGeneratedSmartActions(
- signals.getParcelableArrayList(Adjustment.KEY_CONTEXTUAL_ACTIONS));
+ signals.getParcelableArrayList(Adjustment.KEY_CONTEXTUAL_ACTIONS, android.app.Notification.Action.class));
EventLogTags.writeNotificationAdjusted(getKey(),
Adjustment.KEY_CONTEXTUAL_ACTIONS,
getSystemGeneratedSmartActions().toString());
diff --git a/services/core/java/com/android/server/notification/NotificationRecordLogger.java b/services/core/java/com/android/server/notification/NotificationRecordLogger.java
index 9a89efabc689..2789bcff0f68 100644
--- a/services/core/java/com/android/server/notification/NotificationRecordLogger.java
+++ b/services/core/java/com/android/server/notification/NotificationRecordLogger.java
@@ -399,7 +399,7 @@ public interface NotificationRecordLogger {
private int getNumPeople(@Nullable Bundle extras) {
if (extras != null) {
ArrayList<Person> people = extras.getParcelableArrayList(
- Notification.EXTRA_PEOPLE_LIST);
+ Notification.EXTRA_PEOPLE_LIST, android.app.Person.class);
if (people != null && !people.isEmpty()) {
return people.size();
}
diff --git a/services/core/java/com/android/server/notification/SnoozeHelper.java b/services/core/java/com/android/server/notification/SnoozeHelper.java
index 7f265df3f416..15d7c1e7a210 100644
--- a/services/core/java/com/android/server/notification/SnoozeHelper.java
+++ b/services/core/java/com/android/server/notification/SnoozeHelper.java
@@ -62,6 +62,8 @@ import java.util.Set;
public class SnoozeHelper {
public static final int XML_SNOOZED_NOTIFICATION_VERSION = 1;
+ static final int CONCURRENT_SNOOZE_LIMIT = 500;
+
protected static final String XML_TAG_NAME = "snoozed-notifications";
private static final String XML_SNOOZED_NOTIFICATION = "notification";
@@ -135,6 +137,15 @@ public class SnoozeHelper {
}
}
+ protected boolean canSnooze(int numberToSnooze) {
+ synchronized (mLock) {
+ if ((mPackages.size() + numberToSnooze) > CONCURRENT_SNOOZE_LIMIT) {
+ return false;
+ }
+ }
+ return true;
+ }
+
@NonNull
protected Long getSnoozeTimeForUnpostedNotification(int userId, String pkg, String key) {
Long time = null;
diff --git a/services/core/java/com/android/server/om/OverlayManagerService.java b/services/core/java/com/android/server/om/OverlayManagerService.java
index 0ba8d2c87e99..715967369ffb 100644
--- a/services/core/java/com/android/server/om/OverlayManagerService.java
+++ b/services/core/java/com/android/server/om/OverlayManagerService.java
@@ -942,7 +942,7 @@ public final class OverlayManagerService extends SystemService {
final FabricatedOverlayInternal fabricated =
request.extras.getParcelable(
OverlayManagerTransaction.Request.BUNDLE_FABRICATED_OVERLAY
- );
+ , android.os.FabricatedOverlayInternal.class);
Objects.requireNonNull(fabricated,
"no fabricated overlay attached to request");
return mImpl.registerFabricatedOverlay(fabricated);
diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java
index e2bf4a46653b..89bb17f37382 100644
--- a/services/core/java/com/android/server/pm/InstallPackageHelper.java
+++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java
@@ -473,9 +473,13 @@ final class InstallPackageHelper {
mApexManager.registerApkInApex(pkg);
}
- // Add the package's KeySets to the global KeySetManagerService
- KeySetManagerService ksms = mPm.mSettings.getKeySetManagerService();
- ksms.addScannedPackageLPw(pkg);
+ // Don't add keysets for APEX as their package settings are not persisted and will
+ // result in orphaned keysets.
+ if ((scanFlags & SCAN_AS_APEX) == 0) {
+ // Add the package's KeySets to the global KeySetManagerService
+ KeySetManagerService ksms = mPm.mSettings.getKeySetManagerService();
+ ksms.addScannedPackageLPw(pkg);
+ }
final Computer snapshot = mPm.snapshotComputer();
mPm.mComponentResolver.addAllComponents(pkg, chatty, mPm.mSetupWizardPackage, snapshot);
@@ -3464,8 +3468,9 @@ final class InstallPackageHelper {
}
// Sort the list to ensure we always process factory packages first
Collections.sort(parseResults, (a, b) -> {
- ApexInfo ai = parsingApexInfo.get(a.scanFile);
- return ai.isFactory ? -1 : 1;
+ ApexInfo i1 = parsingApexInfo.get(a.scanFile);
+ ApexInfo i2 = parsingApexInfo.get(b.scanFile);
+ return Boolean.compare(i2.isFactory, i1.isFactory);
});
@@ -3476,7 +3481,8 @@ final class InstallPackageHelper {
Throwable throwable = parseResult.throwable;
ApexInfo ai = parsingApexInfo.get(parseResult.scanFile);
int newParseFlags = parseFlags;
- int newScanFlags = scanFlags | SCAN_AS_APEX;
+ int newScanFlags = scanFlags | SCAN_AS_APEX
+ | mPm.getSystemPackageScanFlags(parseResult.scanFile);
if (!ai.isFactory) {
newParseFlags &= ~ParsingPackageUtils.PARSE_IS_SYSTEM_DIR;
newScanFlags |= SCAN_NEW_INSTALL;
diff --git a/services/core/java/com/android/server/pm/InstantAppResolverConnection.java b/services/core/java/com/android/server/pm/InstantAppResolverConnection.java
index 4f75f04b11b6..b4c40e6fd361 100644
--- a/services/core/java/com/android/server/pm/InstantAppResolverConnection.java
+++ b/services/core/java/com/android/server/pm/InstantAppResolverConnection.java
@@ -121,7 +121,7 @@ final class InstantAppResolverConnection implements DeathRecipient {
public void sendResult(Bundle data) throws RemoteException {
final ArrayList<InstantAppResolveInfo> resolveList =
data.getParcelableArrayList(
- InstantAppResolverService.EXTRA_RESOLVE_INFO);
+ InstantAppResolverService.EXTRA_RESOLVE_INFO, android.content.pm.InstantAppResolveInfo.class);
callbackHandler.post(() -> callback.onPhaseTwoResolved(resolveList, startTime));
}
};
@@ -343,7 +343,7 @@ final class InstantAppResolverConnection implements DeathRecipient {
public void sendResult(Bundle data) throws RemoteException {
final ArrayList<InstantAppResolveInfo> resolveList =
data.getParcelableArrayList(
- InstantAppResolverService.EXTRA_RESOLVE_INFO);
+ InstantAppResolverService.EXTRA_RESOLVE_INFO, android.content.pm.InstantAppResolveInfo.class);
int sequence =
data.getInt(InstantAppResolverService.EXTRA_SEQUENCE, -1);
onRemoteMethodResult(resolveList, sequence);
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 79e5dd2f2304..b7a5f7031046 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -508,7 +508,7 @@ public class UserManagerService extends IUserManager.Stub {
if (!ACTION_DISABLE_QUIET_MODE_AFTER_UNLOCK.equals(intent.getAction())) {
return;
}
- final IntentSender target = intent.getParcelableExtra(Intent.EXTRA_INTENT);
+ final IntentSender target = intent.getParcelableExtra(Intent.EXTRA_INTENT, android.content.IntentSender.class);
final int userId = intent.getIntExtra(Intent.EXTRA_USER_ID, UserHandle.USER_NULL);
// Call setQuietModeEnabled on bg thread to avoid ANR
BackgroundThread.getHandler().post(() ->
diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedPermissionUtils.java b/services/core/java/com/android/server/pm/pkg/component/ParsedPermissionUtils.java
index 10e8c47f7b1a..c6d1775307f8 100644
--- a/services/core/java/com/android/server/pm/pkg/component/ParsedPermissionUtils.java
+++ b/services/core/java/com/android/server/pm/pkg/component/ParsedPermissionUtils.java
@@ -316,8 +316,7 @@ public class ParsedPermissionUtils {
final ParsedPermission perm = checkDuplicatePerm.get(name);
if (isMalformedDuplicate(parsedPermission, perm)) {
// Fix for b/213323615
- EventLog.writeEvent(0x534e4554, "213323615",
- "The package " + pkg.getPackageName() + " seems malicious");
+ EventLog.writeEvent(0x534e4554, "213323615");
return true;
}
checkDuplicatePerm.put(name, parsedPermission);
diff --git a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageImpl.java b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageImpl.java
index 67d9aecf01bd..6a4513d45d8f 100644
--- a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageImpl.java
+++ b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageImpl.java
@@ -1432,7 +1432,7 @@ public class ParsingPackageImpl implements ParsingPackage, ParsingPackageHidden,
this.processes = in.readHashMap(ParsedProcess.class.getClassLoader());
this.metaData = in.readBundle(boot);
this.volumeUuid = sForInternedString.unparcel(in);
- this.signingDetails = in.readParcelable(boot);
+ this.signingDetails = in.readParcelable(boot, android.content.pm.SigningDetails.class);
this.mPath = in.readString();
this.queriesIntents = in.createTypedArrayList(Intent.CREATOR);
this.queriesPackages = sForInternedStringList.unparcel(in);
diff --git a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java
index 201ca9c4e9cd..b60b9a04d620 100644
--- a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java
+++ b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java
@@ -3280,7 +3280,7 @@ public class ParsingPackageUtils {
ArraySet<PublicKey> keys = new ArraySet<>(M);
for (int j = 0; j < M; ++j) {
- PublicKey pk = (PublicKey) in.readSerializable();
+ PublicKey pk = (PublicKey) in.readSerializable(java.security.PublicKey.class.getClassLoader(), java.security.PublicKey.class);
keys.add(pk);
}
diff --git a/services/core/java/com/android/server/policy/GlobalKeyIntent.java b/services/core/java/com/android/server/policy/GlobalKeyIntent.java
index f8682be7c49a..3d34bee0f328 100644
--- a/services/core/java/com/android/server/policy/GlobalKeyIntent.java
+++ b/services/core/java/com/android/server/policy/GlobalKeyIntent.java
@@ -76,7 +76,7 @@ public final class GlobalKeyIntent {
return null;
}
- final KeyEvent event = intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT);
+ final KeyEvent event = intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT, android.view.KeyEvent.class);
final boolean fromNonInteractive =
intent.getBooleanExtra(EXTRA_BEGAN_FROM_NON_INTERACTIVE, false);
return new GlobalKeyIntent(intent.getComponent(), event, fromNonInteractive);
diff --git a/services/core/java/com/android/server/sensorprivacy/SensorPrivacyService.java b/services/core/java/com/android/server/sensorprivacy/SensorPrivacyService.java
index c354f116af5f..c79bc89efbe9 100644
--- a/services/core/java/com/android/server/sensorprivacy/SensorPrivacyService.java
+++ b/services/core/java/com/android/server/sensorprivacy/SensorPrivacyService.java
@@ -282,7 +282,7 @@ public final class SensorPrivacyService extends SystemService {
public void onReceive(Context context, Intent intent) {
setToggleSensorPrivacy(
((UserHandle) intent.getParcelableExtra(
- Intent.EXTRA_USER)).getIdentifier(), OTHER,
+ Intent.EXTRA_USER, android.os.UserHandle.class)).getIdentifier(), OTHER,
intent.getIntExtra(EXTRA_SENSOR, UNKNOWN), false);
}
}, new IntentFilter(ACTION_DISABLE_TOGGLE_SENSOR_PRIVACY),
diff --git a/services/core/java/com/android/server/storage/CacheQuotaStrategy.java b/services/core/java/com/android/server/storage/CacheQuotaStrategy.java
index ff8b8d2b7b47..fc77ef155952 100644
--- a/services/core/java/com/android/server/storage/CacheQuotaStrategy.java
+++ b/services/core/java/com/android/server/storage/CacheQuotaStrategy.java
@@ -207,7 +207,7 @@ public class CacheQuotaStrategy implements RemoteCallback.OnResultListener {
public void onResult(Bundle data) {
final List<CacheQuotaHint> processedRequests =
data.getParcelableArrayList(
- CacheQuotaService.REQUEST_LIST_KEY);
+ CacheQuotaService.REQUEST_LIST_KEY, android.app.usage.CacheQuotaHint.class);
pushProcessedQuotas(processedRequests);
writeXmlToFile(processedRequests);
}
diff --git a/services/core/java/com/android/server/storage/StorageUserConnection.java b/services/core/java/com/android/server/storage/StorageUserConnection.java
index 0b11b0b6d212..27ca83addec8 100644
--- a/services/core/java/com/android/server/storage/StorageUserConnection.java
+++ b/services/core/java/com/android/server/storage/StorageUserConnection.java
@@ -445,7 +445,7 @@ public final class StorageUserConnection {
}
private void setResult(Bundle result, CompletableFuture<Void> future) {
- ParcelableException ex = result.getParcelable(EXTRA_ERROR);
+ ParcelableException ex = result.getParcelable(EXTRA_ERROR, android.os.ParcelableException.class);
if (ex != null) {
future.completeExceptionally(ex);
} else {
diff --git a/services/core/java/com/android/server/trust/TrustAgentWrapper.java b/services/core/java/com/android/server/trust/TrustAgentWrapper.java
index 4b8c7c176fda..0b1f6b9ba285 100644
--- a/services/core/java/com/android/server/trust/TrustAgentWrapper.java
+++ b/services/core/java/com/android/server/trust/TrustAgentWrapper.java
@@ -132,7 +132,7 @@ public class TrustAgentWrapper {
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
- ComponentName component = intent.getParcelableExtra(EXTRA_COMPONENT_NAME);
+ ComponentName component = intent.getParcelableExtra(EXTRA_COMPONENT_NAME, android.content.ComponentName.class);
if (TRUST_EXPIRED_ACTION.equals(intent.getAction())
&& mName.equals(component)) {
mHandler.removeMessages(MSG_TRUST_TIMEOUT);
diff --git a/services/core/java/com/android/server/vr/Vr2dDisplay.java b/services/core/java/com/android/server/vr/Vr2dDisplay.java
index 769749038315..51c5a89189c5 100644
--- a/services/core/java/com/android/server/vr/Vr2dDisplay.java
+++ b/services/core/java/com/android/server/vr/Vr2dDisplay.java
@@ -170,7 +170,7 @@ class Vr2dDisplay {
} else if (DEBUG_ACTION_SET_SURFACE.equals(action)) {
if (mVirtualDisplay != null) {
if (intent.hasExtra(DEBUG_EXTRA_SURFACE)) {
- setSurfaceLocked(intent.getParcelableExtra(DEBUG_EXTRA_SURFACE));
+ setSurfaceLocked(intent.getParcelableExtra(DEBUG_EXTRA_SURFACE, android.view.Surface.class));
}
} else {
Log.w(TAG, "Cannot set the surface because the VD is null.");
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 85f6f0cb14a9..fa8ea76bf0d1 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -5338,11 +5338,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
ANIMATION_TYPE_APP_TRANSITION | ANIMATION_TYPE_WINDOW_ANIMATION
| ANIMATION_TYPE_RECENTS);
if (!delayed) {
- // We aren't delayed anything, but exiting windows rely on the animation finished
- // callback being called in case the ActivityRecord was pretending to be delayed,
- // which we might have done because we were in closing/opening apps list.
if (!usingShellTransitions) {
- onAnimationFinished(ANIMATION_TYPE_APP_TRANSITION, null /* AnimationAdapter */);
if (visible) {
// The token was made immediately visible, there will be no entrance animation.
// We need to inform the client the enter animation was finished.
@@ -7737,9 +7733,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// relatively fixed.
overrideConfig.colorMode = fullConfig.colorMode;
overrideConfig.densityDpi = fullConfig.densityDpi;
- // The smallest screen width is the short side of screen bounds. Because the bounds
- // and density won't be changed, smallestScreenWidthDp is also fixed.
- overrideConfig.smallestScreenWidthDp = fullConfig.smallestScreenWidthDp;
if (info.isFixedOrientation()) {
// lock rotation too. When in size-compat, onConfigurationChanged will watch for and
// apply runtime rotation changes.
@@ -7836,7 +7829,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// computed accordingly.
if (!matchParentBounds()) {
getTaskFragment().computeConfigResourceOverrides(resolvedConfig,
- newParentConfiguration);
+ newParentConfiguration, areBoundsLetterboxed());
}
// If activity in fullscreen mode is letterboxed because of fixed orientation then bounds
// are already calculated in resolveFixedOrientationConfiguration.
@@ -8007,7 +8000,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
// Since bounds has changed, the configuration needs to be computed accordingly.
- getTaskFragment().computeConfigResourceOverrides(resolvedConfig, newParentConfiguration);
+ getTaskFragment().computeConfigResourceOverrides(resolvedConfig, newParentConfiguration,
+ areBoundsLetterboxed());
}
void recomputeConfiguration() {
@@ -8223,7 +8217,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// Calculate app bounds using fixed orientation bounds because they will be needed later
// for comparison with size compat app bounds in {@link resolveSizeCompatModeConfiguration}.
getTaskFragment().computeConfigResourceOverrides(getResolvedOverrideConfiguration(),
- newParentConfig);
+ newParentConfig, mCompatDisplayInsets, areBoundsLetterboxed());
mLetterboxBoundsForFixedOrientationAndAspectRatio = new Rect(resolvedBounds);
}
@@ -8251,7 +8245,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// Compute the configuration based on the resolved bounds. If aspect ratio doesn't
// restrict, the bounds should be the requested override bounds.
getTaskFragment().computeConfigResourceOverrides(resolvedConfig, newParentConfiguration,
- getFixedRotationTransformDisplayInfo());
+ getFixedRotationTransformDisplayInfo(), areBoundsLetterboxed());
}
}
@@ -8315,7 +8309,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// are calculated in compat container space. The actual position on screen will be applied
// later, so the calculation is simpler that doesn't need to involve offset from parent.
getTaskFragment().computeConfigResourceOverrides(resolvedConfig, newParentConfiguration,
- mCompatDisplayInsets);
+ mCompatDisplayInsets, areBoundsLetterboxed());
// Use current screen layout as source because the size of app is independent to parent.
resolvedConfig.screenLayout = TaskFragment.computeScreenLayoutOverride(
getConfiguration().screenLayout, resolvedConfig.screenWidthDp,
diff --git a/services/core/java/com/android/server/wm/BackNavigationController.java b/services/core/java/com/android/server/wm/BackNavigationController.java
index d07cc68af890..9295c18fe80e 100644
--- a/services/core/java/com/android/server/wm/BackNavigationController.java
+++ b/services/core/java/com/android/server/wm/BackNavigationController.java
@@ -112,6 +112,7 @@ class BackNavigationController {
RemoteAnimationTarget topAppTarget = null;
int prevTaskId;
int prevUserId;
+ boolean prepareAnimation;
BackNavigationInfo.Builder infoBuilder = new BackNavigationInfo.Builder();
synchronized (wmService.mGlobalLock) {
@@ -257,7 +258,8 @@ class BackNavigationController {
BackNavigationInfo.typeToString(backType));
// For now, we only animate when going home.
- boolean prepareAnimation = backType == BackNavigationInfo.TYPE_RETURN_TO_HOME
+ prepareAnimation = backType == BackNavigationInfo.TYPE_RETURN_TO_HOME
+ && requestAnimation
// Only create a new leash if no leash has been created.
// Otherwise return null for animation target to avoid conflict.
&& !removedWindowContainer.hasCommittedReparentToAnimationLeash();
@@ -292,7 +294,7 @@ class BackNavigationController {
}
// Special handling for back to home animation
- if (backType == BackNavigationInfo.TYPE_RETURN_TO_HOME && requestAnimation
+ if (backType == BackNavigationInfo.TYPE_RETURN_TO_HOME && prepareAnimation
&& prevTask != null) {
currentTask.mBackGestureStarted = true;
// Make launcher show from behind by marking its top activity as visible and
@@ -347,7 +349,7 @@ class BackNavigationController {
Task finalTask = currentTask;
RemoteCallback onBackNavigationDone = new RemoteCallback(result -> onBackNavigationDone(
result, finalRemovedWindowContainer, finalBackType, finalTask,
- finalprevActivity, requestAnimation));
+ finalprevActivity, prepareAnimation));
infoBuilder.setOnBackNavigationDone(onBackNavigationDone);
}
@@ -381,14 +383,14 @@ class BackNavigationController {
private void onBackNavigationDone(
Bundle result, WindowContainer<?> windowContainer, int backType,
- Task task, ActivityRecord prevActivity, boolean requestAnimation) {
+ Task task, ActivityRecord prevActivity, boolean prepareAnimation) {
SurfaceControl surfaceControl = windowContainer.getSurfaceControl();
boolean triggerBack = result != null && result.getBoolean(
BackNavigationInfo.KEY_TRIGGER_BACK);
ProtoLog.d(WM_DEBUG_BACK_PREVIEW, "onBackNavigationDone backType=%s, "
+ "task=%s, prevActivity=%s", backType, task, prevActivity);
- if (backType == BackNavigationInfo.TYPE_RETURN_TO_HOME && requestAnimation) {
+ if (backType == BackNavigationInfo.TYPE_RETURN_TO_HOME && prepareAnimation) {
if (triggerBack) {
if (surfaceControl != null && surfaceControl.isValid()) {
// When going back to home, hide the task surface before it is re-parented to
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 2b359cadb377..95f76180c600 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -46,6 +46,7 @@ import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_INTERCEPT_GLOBAL_DRAG_AND_DROP;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_LAYOUT_SIZE_EXTENDED_BY_CUTOUT;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
@@ -1166,7 +1167,8 @@ public class DisplayPolicy {
continue;
}
calculateInsetsFrame(displayFrames, win, inOutFrame,
- provider.source, provider.insetsSize
+ provider.source, provider.insetsSize,
+ lp.privateFlags, lp.gravity
);
}
}
@@ -1241,21 +1243,25 @@ public class DisplayPolicy {
provider.insetsSize != null
? (displayFrames, windowContainer, inOutFrame) -> {
inOutFrame.inset(win.mGivenContentInsets);
+ final LayoutParams lp =
+ win.mAttrs.forRotation(displayFrames.mRotation);
final InsetsFrameProvider ifp =
- win.mAttrs.forRotation(displayFrames.mRotation)
- .providedInsets[index];
+ lp.providedInsets[index];
calculateInsetsFrame(displayFrames, windowContainer,
- inOutFrame, ifp.source, ifp.insetsSize);
+ inOutFrame, ifp.source, ifp.insetsSize,
+ lp.privateFlags, lp.gravity);
} : null;
final TriConsumer<DisplayFrames, WindowContainer, Rect> imeFrameProvider =
provider.imeInsetsSize != null
? (displayFrames, windowContainer, inOutFrame) -> {
inOutFrame.inset(win.mGivenContentInsets);
+ final LayoutParams lp =
+ win.mAttrs.forRotation(displayFrames.mRotation);
final InsetsFrameProvider ifp =
- win.mAttrs.forRotation(displayFrames.mRotation)
- .providedInsets[index];
+ lp.providedInsets[index];
calculateInsetsFrame(displayFrames, windowContainer,
- inOutFrame, ifp.source, ifp.imeInsetsSize);
+ inOutFrame, ifp.source, ifp.imeInsetsSize,
+ lp.privateFlags, lp.gravity);
} : null;
mDisplayContent.setInsetProvider(provider.type, win, frameProvider,
imeFrameProvider);
@@ -1267,11 +1273,15 @@ public class DisplayPolicy {
}
private void calculateInsetsFrame(DisplayFrames df, WindowContainer container, Rect inOutFrame,
- int source, Insets insetsSize) {
+ int source, Insets insetsSize, @LayoutParams.PrivateFlags int privateFlags,
+ int windowGravity) {
+ boolean extendByCutout = false;
if (source == InsetsFrameProvider.SOURCE_DISPLAY) {
inOutFrame.set(df.mUnrestricted);
} else if (source == InsetsFrameProvider.SOURCE_CONTAINER_BOUNDS) {
inOutFrame.set(container.getBounds());
+ } else {
+ extendByCutout = (privateFlags & PRIVATE_FLAG_LAYOUT_SIZE_EXTENDED_BY_CUTOUT) != 0;
}
if (insetsSize == null) {
return;
@@ -1289,6 +1299,11 @@ public class DisplayPolicy {
} else {
inOutFrame.setEmpty();
}
+
+ if (extendByCutout) {
+ WindowLayout.extendFrameByCutout(windowGravity, df.mDisplayCutoutSafe,
+ df.mUnrestricted, inOutFrame, sTmpRect);
+ }
}
@WindowManagerPolicy.AltBarPosition
diff --git a/services/core/java/com/android/server/wm/EventLogTags.logtags b/services/core/java/com/android/server/wm/EventLogTags.logtags
index 6d63331622b9..1e5a219e5e52 100644
--- a/services/core/java/com/android/server/wm/EventLogTags.logtags
+++ b/services/core/java/com/android/server/wm/EventLogTags.logtags
@@ -66,4 +66,4 @@ option java_package com.android.server.wm
31007 wm_boot_animation_done (time|2|3)
# Request surface flinger to show / hide the wallpaper surface.
-33001 wm_wallpaper_surface (Display Id|1|5),(visible|1)
+33001 wm_wallpaper_surface (Display Id|1|5),(Visible|1),(Target|3)
diff --git a/services/core/java/com/android/server/wm/InsetsPolicy.java b/services/core/java/com/android/server/wm/InsetsPolicy.java
index db2ee2de06ca..ee1ff2cd61ff 100644
--- a/services/core/java/com/android/server/wm/InsetsPolicy.java
+++ b/services/core/java/com/android/server/wm/InsetsPolicy.java
@@ -265,7 +265,7 @@ class InsetsPolicy {
state = originalState;
}
state = adjustVisibilityForIme(target, state, state == originalState);
- return adjustInsetsForRoundedCorners(target, state, state == originalState);
+ return adjustInsetsForRoundedCorners(target.mToken, state, state == originalState);
}
InsetsState adjustInsetsForWindow(WindowState target, InsetsState originalState) {
@@ -290,7 +290,8 @@ class InsetsPolicy {
final InsetsState originalState = mDisplayContent.getInsetsPolicy()
.enforceInsetsPolicyForTarget(type, WINDOWING_MODE_FULLSCREEN, alwaysOnTop,
mStateController.getRawInsetsState());
- return adjustVisibilityForTransientTypes(originalState);
+ InsetsState state = adjustVisibilityForTransientTypes(originalState);
+ return adjustInsetsForRoundedCorners(token, state, state == originalState);
}
/**
@@ -465,15 +466,19 @@ class InsetsPolicy {
return originalState;
}
- private InsetsState adjustInsetsForRoundedCorners(WindowState w, InsetsState originalState,
+ private InsetsState adjustInsetsForRoundedCorners(WindowToken token, InsetsState originalState,
boolean copyState) {
- final Task task = w.getTask();
- if (task != null && !task.getWindowConfiguration().tasksAreFloating()) {
- // Use task bounds to calculating rounded corners if the task is not floating.
- final Rect roundedCornerFrame = new Rect(task.getBounds());
- final InsetsState state = copyState ? new InsetsState(originalState) : originalState;
- state.setRoundedCornerFrame(roundedCornerFrame);
- return state;
+ if (token != null) {
+ final ActivityRecord activityRecord = token.asActivityRecord();
+ final Task task = activityRecord != null ? activityRecord.getTask() : null;
+ if (task != null && !task.getWindowConfiguration().tasksAreFloating()) {
+ // Use task bounds to calculating rounded corners if the task is not floating.
+ final Rect roundedCornerFrame = new Rect(task.getBounds());
+ final InsetsState state = copyState ? new InsetsState(originalState)
+ : originalState;
+ state.setRoundedCornerFrame(roundedCornerFrame);
+ return state;
+ }
}
return originalState;
}
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 1525fb3930d6..e65f0bbc1e55 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -738,8 +738,9 @@ class Task extends TaskFragment {
"removeTask:" + reason + " deferring removing taskId=" + mTaskId);
return;
}
+ final boolean isLeafTask = isLeafTask();
removeImmediately(reason);
- if (isLeafTask()) {
+ if (isLeafTask) {
mAtmService.getTaskChangeNotificationController().notifyTaskRemoved(mTaskId);
final TaskDisplayArea taskDisplayArea = getDisplayArea();
diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java
index 3e6546ebb647..23adee6f6503 100644
--- a/services/core/java/com/android/server/wm/TaskFragment.java
+++ b/services/core/java/com/android/server/wm/TaskFragment.java
@@ -1957,29 +1957,37 @@ class TaskFragment extends WindowContainer<WindowContainer> {
void computeConfigResourceOverrides(@NonNull Configuration inOutConfig,
@NonNull Configuration parentConfig) {
computeConfigResourceOverrides(inOutConfig, parentConfig, null /* overrideDisplayInfo */,
- null /* compatInsets */);
+ null /* compatInsets */, false /* areBoundsLetterboxed */);
}
void computeConfigResourceOverrides(@NonNull Configuration inOutConfig,
- @NonNull Configuration parentConfig, @Nullable DisplayInfo overrideDisplayInfo) {
+ @NonNull Configuration parentConfig, boolean areBoundsLetterboxed) {
+ computeConfigResourceOverrides(inOutConfig, parentConfig, null /* overrideDisplayInfo */,
+ null /* compatInsets */, areBoundsLetterboxed);
+ }
+
+ void computeConfigResourceOverrides(@NonNull Configuration inOutConfig,
+ @NonNull Configuration parentConfig, @Nullable DisplayInfo overrideDisplayInfo,
+ boolean areBoundsLetterboxed) {
if (overrideDisplayInfo != null) {
// Make sure the screen related configs can be computed by the provided display info.
inOutConfig.screenLayout = Configuration.SCREENLAYOUT_UNDEFINED;
invalidateAppBoundsConfig(inOutConfig);
}
computeConfigResourceOverrides(inOutConfig, parentConfig, overrideDisplayInfo,
- null /* compatInsets */);
+ null /* compatInsets */, areBoundsLetterboxed);
}
void computeConfigResourceOverrides(@NonNull Configuration inOutConfig,
@NonNull Configuration parentConfig,
- @Nullable ActivityRecord.CompatDisplayInsets compatInsets) {
+ @Nullable ActivityRecord.CompatDisplayInsets compatInsets,
+ boolean areBoundsLetterboxed) {
if (compatInsets != null) {
// Make sure the app bounds can be computed by the compat insets.
invalidateAppBoundsConfig(inOutConfig);
}
computeConfigResourceOverrides(inOutConfig, parentConfig, null /* overrideDisplayInfo */,
- compatInsets);
+ compatInsets, areBoundsLetterboxed);
}
/**
@@ -2006,7 +2014,8 @@ class TaskFragment extends WindowContainer<WindowContainer> {
**/
void computeConfigResourceOverrides(@NonNull Configuration inOutConfig,
@NonNull Configuration parentConfig, @Nullable DisplayInfo overrideDisplayInfo,
- @Nullable ActivityRecord.CompatDisplayInsets compatInsets) {
+ @Nullable ActivityRecord.CompatDisplayInsets compatInsets,
+ boolean areBoundsLetterboxed) {
int windowingMode = inOutConfig.windowConfiguration.getWindowingMode();
if (windowingMode == WINDOWING_MODE_UNDEFINED) {
windowingMode = parentConfig.windowConfiguration.getWindowingMode();
@@ -2113,6 +2122,7 @@ class TaskFragment extends WindowContainer<WindowContainer> {
: overrideScreenHeightDp;
}
+ // TODO(b/238331848): Consider simplifying logic that computes smallestScreenWidthDp.
if (inOutConfig.smallestScreenWidthDp
== Configuration.SMALLEST_SCREEN_WIDTH_DP_UNDEFINED) {
// When entering to or exiting from Pip, the PipTaskOrganizer will set the
@@ -2128,9 +2138,10 @@ class TaskFragment extends WindowContainer<WindowContainer> {
// task, because they should not be affected by insets.
inOutConfig.smallestScreenWidthDp = (int) (0.5f
+ Math.min(mTmpFullBounds.width(), mTmpFullBounds.height()) / density);
- } else if (isEmbedded()) {
- // For embedded TFs, the smallest width should be updated. Otherwise, inherit
- // from the parent task would result in applications loaded wrong resource.
+ } else if (isEmbedded() || areBoundsLetterboxed || customContainerPolicy) {
+ // For embedded TFs and activities that are letteboxed or eligible for size
+ // compat mode, the smallest width should be updated. Otherwise, inherit from
+ // the parent task would result in applications loaded wrong resource.
inOutConfig.smallestScreenWidthDp =
Math.min(inOutConfig.screenWidthDp, inOutConfig.screenHeightDp);
}
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 00ee94af0b1c..33b49823c620 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -3212,6 +3212,10 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
void resetSurfacePositionForAnimationLeash(Transaction t) {
t.setPosition(mSurfaceControl, 0, 0);
+ if (mSyncState != SYNC_STATE_NONE && t != mSyncTransaction) {
+ // Avoid restoring to old position if the sync transaction is applied later.
+ mSyncTransaction.setPosition(mSurfaceControl, 0, 0);
+ }
mLastSurfacePosition.set(0, 0);
}
@@ -3752,6 +3756,15 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
* hierarchy change implies a configuration change.
*/
private void onSyncReparent(WindowContainer oldParent, WindowContainer newParent) {
+ // Check if this is changing displays. If so, mark the old display as "ready" for
+ // transitions. This is to work around the problem where setting readiness against this
+ // container will only set the new display as ready and leave the old display as unready.
+ if (mSyncState != SYNC_STATE_NONE && oldParent != null
+ && oldParent.getDisplayContent() != null && (newParent == null
+ || oldParent.getDisplayContent() != newParent.getDisplayContent())) {
+ mTransitionController.setReady(oldParent.getDisplayContent());
+ }
+
if (newParent == null || newParent.mSyncState == SYNC_STATE_NONE) {
if (mSyncState == SYNC_STATE_NONE) {
return;
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index bcf05a6f8fe1..6ffddd96ecd2 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -1020,7 +1020,7 @@ public class WindowManagerService extends IWindowManager.Stub
private int mExitAnimId, mEnterAnimId;
/** The display that the rotation animation is applying to. */
- private int mFrozenDisplayId;
+ private int mFrozenDisplayId = INVALID_DISPLAY;
/** Skip repeated ActivityRecords initialization. Note that AppWindowsToken's version of this
* is a long initialized to Long.MIN_VALUE so that it doesn't match this value on startup. */
@@ -5962,10 +5962,10 @@ public class WindowManagerService extends IWindowManager.Stub
}
void makeWindowFreezingScreenIfNeededLocked(WindowState w) {
- // If the screen is currently frozen or off, then keep
- // it frozen/off until this window draws at its new
- // orientation.
- if (!w.mToken.okToDisplay() && mWindowsFreezingScreen != WINDOWS_FREEZING_SCREENS_TIMEOUT) {
+ // If the screen is currently frozen, then keep it frozen until this window draws at its
+ // new orientation.
+ if (mFrozenDisplayId != INVALID_DISPLAY && mFrozenDisplayId == w.getDisplayId()
+ && mWindowsFreezingScreen != WINDOWS_FREEZING_SCREENS_TIMEOUT) {
ProtoLog.v(WM_DEBUG_ORIENTATION, "Changing surface while display frozen: %s", w);
w.setOrientationChanging(true);
if (mWindowsFreezingScreen == WINDOWS_FREEZING_SCREENS_NONE) {
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index 97dcb7574e3c..4bbb1b1fb745 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -817,7 +817,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
}
if (parent.isAllowedToEmbedActivity(activity) != EMBEDDING_ALLOWED) {
final Throwable exception = new SecurityException(
- "The task fragment is not trusted to embed the given activity.");
+ "The task fragment is not allowed to embed the given activity.");
sendTaskFragmentOperationFailure(organizer, errorCallbackToken, exception);
break;
}
@@ -827,11 +827,6 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
sendTaskFragmentOperationFailure(organizer, errorCallbackToken, exception);
break;
}
- if (parent.smallerThanMinDimension(activity)) {
- sendMinimumDimensionViolation(parent, activity.getMinDimensions(),
- errorCallbackToken, "reparentActivityToTask");
- break;
- }
activity.reparent(parent, POSITION_TOP);
effects |= TRANSACT_EFFECTS_LIFECYCLE;
@@ -1673,10 +1668,10 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
// We are reparenting activities to a new embedded TaskFragment, this operation is only
// allowed if the new parent is trusted by all reparent activities.
final boolean isEmbeddingDisallowed = oldParent.forAllActivities(activity ->
- newParentTF.isAllowedToEmbedActivity(activity) == EMBEDDING_ALLOWED);
+ newParentTF.isAllowedToEmbedActivity(activity) != EMBEDDING_ALLOWED);
if (isEmbeddingDisallowed) {
final Throwable exception = new SecurityException(
- "The new parent is not trusted to embed the activities.");
+ "The new parent is not allowed to embed the activities.");
sendTaskFragmentOperationFailure(organizer, errorCallbackToken, exception);
return;
}
@@ -1693,14 +1688,6 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
sendTaskFragmentOperationFailure(organizer, errorCallbackToken, exception);
return;
}
- final Point minDimensions = oldParent.calculateMinDimension();
- final Rect newParentBounds = newParentTF.getBounds();
- if (newParentBounds.width() < minDimensions.x
- || newParentBounds.height() < minDimensions.y) {
- sendMinimumDimensionViolation(newParentTF, minDimensions, errorCallbackToken,
- "reparentTaskFragment");
- return;
- }
while (oldParent.hasChild()) {
oldParent.getChildAt(0).reparent(newParentTF, POSITION_TOP);
}
diff --git a/services/core/java/com/android/server/wm/WindowSurfaceController.java b/services/core/java/com/android/server/wm/WindowSurfaceController.java
index fd379bf1d9f4..4a5c4737cbbc 100644
--- a/services/core/java/com/android/server/wm/WindowSurfaceController.java
+++ b/services/core/java/com/android/server/wm/WindowSurfaceController.java
@@ -126,8 +126,10 @@ class WindowSurfaceController {
try {
transaction.hide(mSurfaceControl);
if (mAnimator.mIsWallpaper) {
+ final DisplayContent dc = mAnimator.mWin.getDisplayContent();
EventLog.writeEvent(EventLogTags.WM_WALLPAPER_SURFACE,
- mAnimator.mWin.getDisplayId(), 0 /* request hidden */);
+ dc.mDisplayId, 0 /* request hidden */,
+ String.valueOf(dc.mWallpaperController.getWallpaperTarget()));
}
} catch (RuntimeException e) {
Slog.w(TAG, "Exception hiding surface in " + this);
@@ -266,8 +268,10 @@ class WindowSurfaceController {
setShown(true);
t.show(mSurfaceControl);
if (mAnimator.mIsWallpaper) {
+ final DisplayContent dc = mAnimator.mWin.getDisplayContent();
EventLog.writeEvent(EventLogTags.WM_WALLPAPER_SURFACE,
- mAnimator.mWin.getDisplayId(), 1 /* request shown */);
+ dc.mDisplayId, 1 /* request shown */,
+ String.valueOf(dc.mWallpaperController.getWallpaperTarget()));
}
return true;
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index cbd574348de0..4c2803fa17da 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -11608,34 +11608,32 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
&& (isProfileOwner(caller) || isDefaultDeviceOwner(caller)))
|| (caller.hasPackage() && isCallerDelegate(caller, DELEGATION_ENABLE_SYSTEM_APP)));
- synchronized (getLockObject()) {
- final boolean isDemo = isCurrentUserDemo();
- int userId = caller.getUserId();
- long id = mInjector.binderClearCallingIdentity();
- try {
- if (VERBOSE_LOG) {
- Slogf.v(LOG_TAG, "installing " + packageName + " for " + userId);
- }
+ final boolean isDemo = isCurrentUserDemo();
+ int userId = caller.getUserId();
+ long id = mInjector.binderClearCallingIdentity();
+ try {
+ if (VERBOSE_LOG) {
+ Slogf.v(LOG_TAG, "installing " + packageName + " for " + userId);
+ }
- Preconditions.checkArgument(isDemo || isSystemApp(mIPackageManager, packageName,
- getProfileParentId(userId)), "Only system apps can be enabled this way");
+ Preconditions.checkArgument(isDemo || isSystemApp(mIPackageManager, packageName,
+ getProfileParentId(userId)), "Only system apps can be enabled this way");
- // Install the app.
- mIPackageManager.installExistingPackageAsUser(packageName, userId,
- PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS,
- PackageManager.INSTALL_REASON_POLICY, null);
- if (isDemo) {
- // Ensure the app is also ENABLED for demo users.
- mIPackageManager.setApplicationEnabledSetting(packageName,
- PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
- PackageManager.DONT_KILL_APP, userId, "DevicePolicyManager");
- }
- } catch (RemoteException re) {
- // shouldn't happen
- Slogf.wtf(LOG_TAG, "Failed to install " + packageName, re);
- } finally {
- mInjector.binderRestoreCallingIdentity(id);
+ // Install the app.
+ mIPackageManager.installExistingPackageAsUser(packageName, userId,
+ PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS,
+ PackageManager.INSTALL_REASON_POLICY, null);
+ if (isDemo) {
+ // Ensure the app is also ENABLED for demo users.
+ mIPackageManager.setApplicationEnabledSetting(packageName,
+ PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
+ PackageManager.DONT_KILL_APP, userId, "DevicePolicyManager");
}
+ } catch (RemoteException re) {
+ // shouldn't happen
+ Slogf.wtf(LOG_TAG, "Failed to install " + packageName, re);
+ } finally {
+ mInjector.binderRestoreCallingIdentity(id);
}
DevicePolicyEventLogger
.createEvent(DevicePolicyEnums.ENABLE_SYSTEM_APP)
@@ -11653,45 +11651,43 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
|| (caller.hasPackage() && isCallerDelegate(caller, DELEGATION_ENABLE_SYSTEM_APP)));
int numberOfAppsInstalled = 0;
- synchronized (getLockObject()) {
- long id = mInjector.binderClearCallingIdentity();
- try {
- final int parentUserId = getProfileParentId(caller.getUserId());
- List<ResolveInfo> activitiesToEnable = mIPackageManager
- .queryIntentActivities(intent,
- intent.resolveTypeIfNeeded(mContext.getContentResolver()),
- PackageManager.MATCH_DIRECT_BOOT_AWARE
- | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
- parentUserId)
- .getList();
+ long id = mInjector.binderClearCallingIdentity();
+ try {
+ final int parentUserId = getProfileParentId(caller.getUserId());
+ List<ResolveInfo> activitiesToEnable = mIPackageManager
+ .queryIntentActivities(intent,
+ intent.resolveTypeIfNeeded(mContext.getContentResolver()),
+ PackageManager.MATCH_DIRECT_BOOT_AWARE
+ | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
+ parentUserId)
+ .getList();
- if (VERBOSE_LOG) {
- Slogf.d(LOG_TAG, "Enabling system activities: " + activitiesToEnable);
- }
- if (activitiesToEnable != null) {
- for (ResolveInfo info : activitiesToEnable) {
- if (info.activityInfo != null) {
- String packageName = info.activityInfo.packageName;
- if (isSystemApp(mIPackageManager, packageName, parentUserId)) {
- numberOfAppsInstalled++;
- mIPackageManager.installExistingPackageAsUser(packageName,
- caller.getUserId(),
- PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS,
- PackageManager.INSTALL_REASON_POLICY, null);
- } else {
- Slogf.d(LOG_TAG, "Not enabling " + packageName + " since is not a"
- + " system app");
- }
+ if (VERBOSE_LOG) {
+ Slogf.d(LOG_TAG, "Enabling system activities: " + activitiesToEnable);
+ }
+ if (activitiesToEnable != null) {
+ for (ResolveInfo info : activitiesToEnable) {
+ if (info.activityInfo != null) {
+ String packageName = info.activityInfo.packageName;
+ if (isSystemApp(mIPackageManager, packageName, parentUserId)) {
+ numberOfAppsInstalled++;
+ mIPackageManager.installExistingPackageAsUser(packageName,
+ caller.getUserId(),
+ PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS,
+ PackageManager.INSTALL_REASON_POLICY, null);
+ } else {
+ Slogf.d(LOG_TAG, "Not enabling " + packageName + " since is not a"
+ + " system app");
}
}
}
- } catch (RemoteException e) {
- // shouldn't happen
- Slogf.wtf(LOG_TAG, "Failed to resolve intent for: " + intent);
- return 0;
- } finally {
- mInjector.binderRestoreCallingIdentity(id);
}
+ } catch (RemoteException e) {
+ // shouldn't happen
+ Slogf.wtf(LOG_TAG, "Failed to resolve intent for: " + intent);
+ return 0;
+ } finally {
+ mInjector.binderRestoreCallingIdentity(id);
}
DevicePolicyEventLogger
.createEvent(DevicePolicyEnums.ENABLE_SYSTEM_APP_WITH_INTENT)
@@ -18000,7 +17996,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
Slogf.i(LOG_TAG, "Account removed from the primary user.");
} else {
// TODO(174768447): Revisit start activity logic.
- final Intent removeIntent = result.getParcelable(AccountManager.KEY_INTENT);
+ final Intent removeIntent = result.getParcelable(AccountManager.KEY_INTENT, android.content.Intent.class);
removeIntent.addFlags(FLAG_ACTIVITY_NEW_TASK);
if (removeIntent != null) {
Slogf.i(LOG_TAG, "Starting activity to remove account");
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/NetworkLoggingHandler.java b/services/devicepolicy/java/com/android/server/devicepolicy/NetworkLoggingHandler.java
index 84e89a08e1f4..06cbe787ac90 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/NetworkLoggingHandler.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/NetworkLoggingHandler.java
@@ -134,7 +134,7 @@ final class NetworkLoggingHandler extends Handler {
public void handleMessage(Message msg) {
switch (msg.what) {
case LOG_NETWORK_EVENT_MSG: {
- final NetworkEvent networkEvent = msg.getData().getParcelable(NETWORK_EVENT_KEY);
+ final NetworkEvent networkEvent = msg.getData().getParcelable(NETWORK_EVENT_KEY, android.app.admin.NetworkEvent.class);
if (networkEvent != null) {
Bundle notificationExtras = null;
synchronized (NetworkLoggingHandler.this) {
diff --git a/services/midi/java/com/android/server/midi/MidiService.java b/services/midi/java/com/android/server/midi/MidiService.java
index 994a76700dc0..b519a782ce26 100644
--- a/services/midi/java/com/android/server/midi/MidiService.java
+++ b/services/midi/java/com/android/server/midi/MidiService.java
@@ -365,7 +365,7 @@ public class MidiService extends IMidiManager.Stub {
mServiceInfo = serviceInfo;
mUid = uid;
mBluetoothDevice = (BluetoothDevice)deviceInfo.getProperties().getParcelable(
- MidiDeviceInfo.PROPERTY_BLUETOOTH_DEVICE);;
+ MidiDeviceInfo.PROPERTY_BLUETOOTH_DEVICE, android.bluetooth.BluetoothDevice.class);;
setDeviceServer(server);
}
@@ -745,7 +745,7 @@ public class MidiService extends IMidiManager.Stub {
Log.d(TAG, "BLE Device");
BluetoothDevice btDevice =
- intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
+ intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE, android.bluetooth.BluetoothDevice.class);
dumpUuids(btDevice);
// See if there are any service UUIDs and if so do any of them indicate a
@@ -764,7 +764,7 @@ public class MidiService extends IMidiManager.Stub {
{
Log.d(TAG, "ACTION_ACL_DISCONNECTED");
BluetoothDevice btDevice =
- intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
+ intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE, android.bluetooth.BluetoothDevice.class);
// We DO know at this point if we are disconnecting a MIDI device, so
// don't bother if we are not.
if (isBLEMIDIDevice(btDevice)) {
@@ -793,7 +793,7 @@ public class MidiService extends IMidiManager.Stub {
{
Log.d(TAG, "ACTION_UUID");
BluetoothDevice btDevice =
- intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
+ intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE, android.bluetooth.BluetoothDevice.class);
dumpUuids(btDevice);
if (isBLEMIDIDevice(btDevice)) {
Log.d(TAG, "BT MIDI DEVICE");
@@ -1165,7 +1165,7 @@ public class MidiService extends IMidiManager.Stub {
BluetoothDevice bluetoothDevice = null;
if (type == MidiDeviceInfo.TYPE_BLUETOOTH) {
bluetoothDevice = (BluetoothDevice)properties.getParcelable(
- MidiDeviceInfo.PROPERTY_BLUETOOTH_DEVICE);
+ MidiDeviceInfo.PROPERTY_BLUETOOTH_DEVICE, android.bluetooth.BluetoothDevice.class);
device = mBluetoothDevices.get(bluetoothDevice);
if (device != null) {
device.setDeviceInfo(deviceInfo);
diff --git a/services/net/java/android/net/ConnectivityModuleConnector.java b/services/net/java/android/net/ConnectivityModuleConnector.java
index c6b15c17bd3c..6bf6349bc4b3 100644
--- a/services/net/java/android/net/ConnectivityModuleConnector.java
+++ b/services/net/java/android/net/ConnectivityModuleConnector.java
@@ -25,7 +25,6 @@ import android.content.Intent;
import android.content.ServiceConnection;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
-import android.net.util.SharedLog;
import android.os.Build;
import android.os.Environment;
import android.os.IBinder;
@@ -35,13 +34,13 @@ import android.os.UserHandle;
import android.provider.DeviceConfig;
import android.text.format.DateUtils;
import android.util.ArraySet;
+import android.util.Log;
import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import java.io.File;
-import java.io.PrintWriter;
/**
* Class used to communicate to the various networking mainline modules running in the network stack
@@ -73,8 +72,6 @@ public class ConnectivityModuleConnector {
private static ConnectivityModuleConnector sInstance;
private Context mContext;
- @GuardedBy("mLog")
- private final SharedLog mLog = new SharedLog(TAG);
@GuardedBy("mHealthListeners")
private final ArraySet<ConnectivityModuleHealthListener> mHealthListeners = new ArraySet<>();
@NonNull
@@ -384,38 +381,19 @@ public class ConnectivityModuleConnector {
}
private void log(@NonNull String message) {
- Slog.d(TAG, message);
- synchronized (mLog) {
- mLog.log(message);
- }
+ Log.d(TAG, message);
}
private void logWtf(@NonNull String message, @Nullable Throwable e) {
Slog.wtf(TAG, message, e);
- synchronized (mLog) {
- mLog.e(message);
- }
+ Log.e(TAG, message, e);
}
private void loge(@NonNull String message, @Nullable Throwable e) {
- Slog.e(TAG, message, e);
- synchronized (mLog) {
- mLog.e(message);
- }
+ Log.e(TAG, message, e);
}
private void logi(@NonNull String message) {
- Slog.i(TAG, message);
- synchronized (mLog) {
- mLog.i(message);
- }
- }
-
- /**
- * Dump ConnectivityModuleConnector logs to the specified {@link PrintWriter}.
- */
- public void dump(PrintWriter pw) {
- // dump is thread-safe on SharedLog
- mLog.dump(null, pw, null);
+ Log.i(TAG, message);
}
}
diff --git a/services/net/java/android/net/NetworkStackClient.java b/services/net/java/android/net/NetworkStackClient.java
index 865e3b8cc109..b7eb5cd61329 100644
--- a/services/net/java/android/net/NetworkStackClient.java
+++ b/services/net/java/android/net/NetworkStackClient.java
@@ -25,19 +25,18 @@ import android.content.Context;
import android.net.dhcp.DhcpServingParamsParcel;
import android.net.dhcp.IDhcpServerCallbacks;
import android.net.ip.IIpClientCallbacks;
-import android.net.util.SharedLog;
import android.os.Binder;
import android.os.IBinder;
import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
+import android.util.Log;
import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
-import java.io.PrintWriter;
import java.util.ArrayList;
/**
@@ -61,9 +60,6 @@ public class NetworkStackClient {
@GuardedBy("mPendingNetStackRequests")
private INetworkStackConnector mConnector;
- @GuardedBy("mLog")
- private final SharedLog mLog = new SharedLog(TAG);
-
private volatile boolean mWasSystemServerInitialized = false;
private interface NetworkStackCallback {
@@ -237,34 +233,23 @@ public class NetworkStackClient {
}
/**
- * Log a message in the local log.
+ * Log a debug message.
*/
private void log(@NonNull String message) {
- synchronized (mLog) {
- mLog.log(message);
- }
+ Log.d(TAG, message);
}
private void logWtf(@NonNull String message, @Nullable Throwable e) {
Slog.wtf(TAG, message);
- synchronized (mLog) {
- mLog.e(message, e);
- }
+ Log.e(TAG, message, e);
}
private void loge(@NonNull String message, @Nullable Throwable e) {
- synchronized (mLog) {
- mLog.e(message, e);
- }
+ Log.e(TAG, message, e);
}
- /**
- * Log a message in the local and system logs.
- */
private void logi(@NonNull String message) {
- synchronized (mLog) {
- mLog.i(message);
- }
+ Log.i(TAG, message);
}
/**
@@ -320,22 +305,4 @@ public class NetworkStackClient {
request.onNetworkStackConnected(connector);
}
-
- /**
- * Dump NetworkStackClient logs to the specified {@link PrintWriter}.
- */
- public void dump(PrintWriter pw) {
- // dump is thread-safe on SharedLog
- mLog.dump(null, pw, null);
- // dump connectivity module connector logs.
- ConnectivityModuleConnector.getInstance().dump(pw);
-
- final int requestsQueueLength;
- synchronized (mPendingNetStackRequests) {
- requestsQueueLength = mPendingNetStackRequests.size();
- }
-
- pw.println();
- pw.println("pendingNetStackRequests length: " + requestsQueueLength);
- }
}
diff --git a/services/people/java/com/android/server/people/prediction/ShareTargetPredictor.java b/services/people/java/com/android/server/people/prediction/ShareTargetPredictor.java
index 368b737d2133..b6204073d1cc 100644
--- a/services/people/java/com/android/server/people/prediction/ShareTargetPredictor.java
+++ b/services/people/java/com/android/server/people/prediction/ShareTargetPredictor.java
@@ -70,7 +70,7 @@ class ShareTargetPredictor extends AppTargetPredictor {
@UserIdInt int callingUserId, @NonNull Context context) {
super(predictionContext, updatePredictionsMethod, dataManager, callingUserId);
mIntentFilter = predictionContext.getExtras().getParcelable(
- ChooserActivity.APP_PREDICTION_INTENT_FILTER_KEY);
+ ChooserActivity.APP_PREDICTION_INTENT_FILTER_KEY, android.content.IntentFilter.class);
if (DeviceConfig.getBoolean(NAMESPACE_SYSTEMUI,
SystemUiDeviceConfigFlags.DARK_LAUNCH_REMOTE_PREDICTION_SERVICE_ENABLED,
false)) {
diff --git a/services/tests/apexsystemservices/Android.bp b/services/tests/apexsystemservices/Android.bp
index a6ed1ae56567..e724e804f4e7 100644
--- a/services/tests/apexsystemservices/Android.bp
+++ b/services/tests/apexsystemservices/Android.bp
@@ -39,6 +39,6 @@ java_test_host {
],
test_suites: [
"device-tests",
- "mts-core",
+ "mts-mainline-infra",
],
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
index 494246491e47..2d0ef405b9d7 100644
--- a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
@@ -73,7 +73,6 @@ import static com.android.server.alarm.AlarmManagerService.Constants.KEY_ALLOW_W
import static com.android.server.alarm.AlarmManagerService.Constants.KEY_ALLOW_WHILE_IDLE_QUOTA;
import static com.android.server.alarm.AlarmManagerService.Constants.KEY_ALLOW_WHILE_IDLE_WHITELIST_DURATION;
import static com.android.server.alarm.AlarmManagerService.Constants.KEY_ALLOW_WHILE_IDLE_WINDOW;
-import static com.android.server.alarm.AlarmManagerService.Constants.KEY_CRASH_NON_CLOCK_APPS;
import static com.android.server.alarm.AlarmManagerService.Constants.KEY_EXACT_ALARM_DENY_LIST;
import static com.android.server.alarm.AlarmManagerService.Constants.KEY_LAZY_BATCHING;
import static com.android.server.alarm.AlarmManagerService.Constants.KEY_LISTENER_TIMEOUT;
@@ -722,6 +721,25 @@ public class AlarmManagerServiceTest {
}
@Test
+ public void testAlarmBroadcastOption() throws Exception {
+ final long triggerTime = mNowElapsedTest + 5000;
+ final PendingIntent alarmPi = getNewMockPendingIntent();
+ setTestAlarm(ELAPSED_REALTIME_WAKEUP, triggerTime, alarmPi);
+
+ mNowElapsedTest = mTestTimer.getElapsed();
+ mTestTimer.expire();
+
+ final ArgumentCaptor<PendingIntent.OnFinished> onFinishedCaptor =
+ ArgumentCaptor.forClass(PendingIntent.OnFinished.class);
+ final ArgumentCaptor<Bundle> optionsCaptor = ArgumentCaptor.forClass(Bundle.class);
+ verify(alarmPi).send(eq(mMockContext), eq(0), any(Intent.class),
+ onFinishedCaptor.capture(), any(Handler.class), isNull(),
+ optionsCaptor.capture());
+ assertTrue(optionsCaptor.getValue()
+ .getBoolean(BroadcastOptions.KEY_ALARM_BROADCAST, false));
+ }
+
+ @Test
public void testUpdateConstants() {
setDeviceConfigLong(KEY_MIN_FUTURITY, 5);
setDeviceConfigLong(KEY_MIN_INTERVAL, 10);
@@ -2424,7 +2442,6 @@ public class AlarmManagerServiceTest {
@Test
public void alarmClockBinderCallWithoutPermission() throws RemoteException {
- setDeviceConfigBoolean(KEY_CRASH_NON_CLOCK_APPS, true);
mockChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, true);
mockScheduleExactAlarmState(true, false, MODE_ERRORED);
@@ -2593,7 +2610,6 @@ public class AlarmManagerServiceTest {
@Test
public void exactBinderCallsWithoutPermissionWithoutAllowlist() throws RemoteException {
- setDeviceConfigBoolean(KEY_CRASH_NON_CLOCK_APPS, true);
mockChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, true);
mockScheduleExactAlarmState(true, false, MODE_ERRORED);
diff --git a/services/tests/servicestests/AndroidTest.xml b/services/tests/servicestests/AndroidTest.xml
index 0ce87d7b48b1..9052f58b2a8b 100644
--- a/services/tests/servicestests/AndroidTest.xml
+++ b/services/tests/servicestests/AndroidTest.xml
@@ -51,5 +51,6 @@
<option name="package" value="com.android.frameworks.servicestests" />
<option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
<option name="hidden-api-checks" value="false"/>
+ <option name="exclude-annotation" value="androidx.test.filters.FlakyTest" />
</test>
</configuration>
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTests.java b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTests.java
index 609c05c040c2..c4df05149d4b 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTests.java
@@ -19,6 +19,7 @@ package com.android.server.locksettings;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
@@ -60,7 +61,10 @@ import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
+import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.CyclicBarrier;
+import java.util.concurrent.atomic.AtomicReference;
/**
* atest FrameworksServicesTests:LockSettingsStorageTests
@@ -137,12 +141,12 @@ public class LockSettingsStorageTests {
}
@Test
- public void testKeyValue_Concurrency() {
+ public void testKeyValue_ReadWriteConcurrency() {
final CountDownLatch latch = new CountDownLatch(1);
List<Thread> threads = new ArrayList<>();
for (int i = 0; i < 100; i++) {
final int threadId = i;
- threads.add(new Thread("testKeyValue_Concurrency_" + i) {
+ threads.add(new Thread("testKeyValue_ReadWriteConcurrency_" + i) {
@Override
public void run() {
try {
@@ -164,7 +168,7 @@ public class LockSettingsStorageTests {
});
threads.get(i).start();
}
- mStorage.writeKeyValue("key", "initalValue", 0);
+ mStorage.writeKeyValue("key", "initialValue", 0);
latch.countDown();
joinAll(threads, 10000);
assertEquals('5', mStorage.readKeyValue("key", "default", 0).charAt(0));
@@ -172,6 +176,52 @@ public class LockSettingsStorageTests {
assertEquals('5', mStorage.readKeyValue("key", "default", 0).charAt(0));
}
+ // Test that readKeyValue() doesn't pollute the cache when run concurrently with removeKey().
+ @Test
+ @SuppressWarnings("AssertionFailureIgnored") // intentional try-catch of AssertionError
+ public void testKeyValue_ReadRemoveConcurrency() {
+ final int numThreads = 2;
+ final int numIterations = 50;
+ final CyclicBarrier barrier = new CyclicBarrier(numThreads);
+ final List<Thread> threads = new ArrayList<>();
+ final AtomicReference<Throwable> failure = new AtomicReference<>();
+ for (int threadId = 0; threadId < numThreads; threadId++) {
+ final boolean isWriter = (threadId == 0);
+ threads.add(new Thread("testKeyValue_ReadRemoveConcurrency_" + threadId) {
+ @Override
+ public void run() {
+ try {
+ for (int iter = 0; iter < numIterations; iter++) {
+ if (isWriter) {
+ mStorage.writeKeyValue("key", "value", 0);
+ mStorage.clearCache();
+ }
+ barrier.await();
+ if (isWriter) {
+ mStorage.removeKey("key", 0);
+ } else {
+ mStorage.readKeyValue("key", "default", 0);
+ }
+ barrier.await();
+ try {
+ assertEquals("default", mStorage.readKeyValue("key", "default", 0));
+ } catch (AssertionError e) {
+ failure.compareAndSet(null, e);
+ }
+ barrier.await();
+ }
+ } catch (InterruptedException | BrokenBarrierException e) {
+ failure.compareAndSet(null, e);
+ return;
+ }
+ }
+ });
+ threads.get(threadId).start();
+ }
+ joinAll(threads, 60000);
+ assertNull(failure.get());
+ }
+
@Test
public void testKeyValue_CacheStarvedWriter() {
final CountDownLatch latch = new CountDownLatch(1);
@@ -232,12 +282,22 @@ public class LockSettingsStorageTests {
@Test
public void testPrefetch() {
- mStorage.writeKeyValue("key", "toBeFetched", 0);
+ mStorage.writeKeyValue("key1", "value1", 0);
+ mStorage.writeKeyValue("key2", "value2", 0);
mStorage.clearCache();
+
+ assertFalse(mStorage.isUserPrefetched(0));
+ assertFalse(mStorage.isKeyValueCached("key1", 0));
+ assertFalse(mStorage.isKeyValueCached("key2", 0));
+
mStorage.prefetchUser(0);
- assertEquals("toBeFetched", mStorage.readKeyValue("key", "default", 0));
+ assertTrue(mStorage.isUserPrefetched(0));
+ assertTrue(mStorage.isKeyValueCached("key1", 0));
+ assertTrue(mStorage.isKeyValueCached("key2", 0));
+ assertEquals("value1", mStorage.readKeyValue("key1", "default", 0));
+ assertEquals("value2", mStorage.readKeyValue("key2", "default", 0));
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
index c016406fc96a..308a4b67de24 100644
--- a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
@@ -928,6 +928,7 @@ public class AppStandbyControllerTests {
}
@Test
+ @FlakyTest(bugId = 185169504)
public void testNotificationEvent_quotaBump() throws Exception {
mInjector.mSettingsBuilder
.setBoolean("trigger_quota_bump_on_notification_seen", true);
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index 6e3bc5ba0cc2..830237a35b07 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -3380,39 +3380,98 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
}
@Test
- public void testSnoozeRunnable_reSnoozeASingleSnoozedNotification() throws Exception {
+ public void testSnoozeRunnable_tooManySnoozed_singleNotification() {
final NotificationRecord notification = generateNotificationRecord(
mTestNotificationChannel, 1, null, true);
mService.addNotification(notification);
- when(mSnoozeHelper.getNotification(any())).thenReturn(notification);
+
+ when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true);
+ when(mSnoozeHelper.canSnooze(1)).thenReturn(false);
NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable =
mService.new SnoozeNotificationRunnable(
- notification.getKey(), 100, null);
+ notification.getKey(), 100, null);
snoozeNotificationRunnable.run();
- NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable2 =
+
+ verify(mSnoozeHelper, never()).snooze(any(NotificationRecord.class), anyLong());
+ assertThat(mService.getNotificationRecordCount()).isEqualTo(1);
+ }
+
+ @Test
+ public void testSnoozeRunnable_tooManySnoozed_singleGroupChildNotification() {
+ final NotificationRecord notification = generateNotificationRecord(
+ mTestNotificationChannel, 1, "group", true);
+ final NotificationRecord notificationChild = generateNotificationRecord(
+ mTestNotificationChannel, 1, "group", false);
+ mService.addNotification(notification);
+ mService.addNotification(notificationChild);
+
+ when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true);
+ when(mSnoozeHelper.canSnooze(2)).thenReturn(false);
+
+ NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable =
+ mService.new SnoozeNotificationRunnable(
+ notificationChild.getKey(), 100, null);
+ snoozeNotificationRunnable.run();
+
+ verify(mSnoozeHelper, never()).snooze(any(NotificationRecord.class), anyLong());
+ assertThat(mService.getNotificationRecordCount()).isEqualTo(2);
+ }
+
+ @Test
+ public void testSnoozeRunnable_tooManySnoozed_summaryNotification() {
+ final NotificationRecord notification = generateNotificationRecord(
+ mTestNotificationChannel, 1, "group", true);
+ final NotificationRecord notificationChild = generateNotificationRecord(
+ mTestNotificationChannel, 12, "group", false);
+ final NotificationRecord notificationChild2 = generateNotificationRecord(
+ mTestNotificationChannel, 13, "group", false);
+ mService.addNotification(notification);
+ mService.addNotification(notificationChild);
+ mService.addNotification(notificationChild2);
+
+ when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true);
+ when(mSnoozeHelper.canSnooze(3)).thenReturn(false);
+
+ NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable =
+ mService.new SnoozeNotificationRunnable(
+ notification.getKey(), 100, null);
+ snoozeNotificationRunnable.run();
+
+ verify(mSnoozeHelper, never()).snooze(any(NotificationRecord.class), anyLong());
+ assertThat(mService.getNotificationRecordCount()).isEqualTo(3);
+ }
+
+ @Test
+ public void testSnoozeRunnable_reSnoozeASingleSnoozedNotification() {
+ final NotificationRecord notification = generateNotificationRecord(
+ mTestNotificationChannel, 1, null, true);
+ mService.addNotification(notification);
+ when(mSnoozeHelper.getNotification(any())).thenReturn(notification);
+ when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true);
+
+ NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable =
mService.new SnoozeNotificationRunnable(
notification.getKey(), 100, null);
snoozeNotificationRunnable.run();
+ snoozeNotificationRunnable.run();
// snooze twice
verify(mSnoozeHelper, times(2)).snooze(any(NotificationRecord.class), anyLong());
}
@Test
- public void testSnoozeRunnable_reSnoozeASnoozedNotificationWithGroupKey() throws Exception {
+ public void testSnoozeRunnable_reSnoozeASnoozedNotificationWithGroupKey() {
final NotificationRecord notification = generateNotificationRecord(
mTestNotificationChannel, 1, "group", true);
mService.addNotification(notification);
when(mSnoozeHelper.getNotification(any())).thenReturn(notification);
+ when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true);
NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable =
mService.new SnoozeNotificationRunnable(
notification.getKey(), 100, null);
snoozeNotificationRunnable.run();
- NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable2 =
- mService.new SnoozeNotificationRunnable(
- notification.getKey(), 100, null);
snoozeNotificationRunnable.run();
// snooze twice
@@ -3430,6 +3489,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
when(mSnoozeHelper.getNotification(any())).thenReturn(notification);
when(mSnoozeHelper.getNotifications(
anyString(), anyString(), anyInt())).thenReturn(new ArrayList<>());
+ when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true);
NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable =
mService.new SnoozeNotificationRunnable(
@@ -3439,8 +3499,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
.thenReturn(new ArrayList<>(Arrays.asList(notification, notification2)));
NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable2 =
mService.new SnoozeNotificationRunnable(
- notification.getKey(), 100, null);
- snoozeNotificationRunnable.run();
+ notification2.getKey(), 100, null);
+ snoozeNotificationRunnable2.run();
// snooze twice
verify(mSnoozeHelper, times(4)).snooze(any(NotificationRecord.class), anyLong());
@@ -3454,6 +3514,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
mTestNotificationChannel, 2, "group", false);
mService.addNotification(grouped);
mService.addNotification(nonGrouped);
+ when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true);
NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable =
mService.new SnoozeNotificationRunnable(
@@ -3483,6 +3544,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
mService.addNotification(parent);
mService.addNotification(child);
mService.addNotification(child2);
+ when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true);
NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable =
mService.new SnoozeNotificationRunnable(
@@ -3504,6 +3566,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
mService.addNotification(parent);
mService.addNotification(child);
mService.addNotification(child2);
+ when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true);
NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable =
mService.new SnoozeNotificationRunnable(
@@ -3529,6 +3592,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
mTestNotificationChannel, 2, "group", false);
mService.addNotification(parent);
mService.addNotification(child);
+ when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true);
NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable =
mService.new SnoozeNotificationRunnable(
@@ -3556,6 +3620,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
final NotificationRecord child = generateNotificationRecord(
mTestNotificationChannel, 2, "group", false);
mService.addNotification(child);
+ when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true);
NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable =
mService.new SnoozeNotificationRunnable(
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java
index 2ae2ef7162a5..8bead5774548 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java
@@ -15,6 +15,7 @@
*/
package com.android.server.notification;
+import static com.android.server.notification.SnoozeHelper.CONCURRENT_SNOOZE_LIMIT;
import static com.android.server.notification.SnoozeHelper.EXTRA_KEY;
import static junit.framework.Assert.assertEquals;
@@ -281,6 +282,22 @@ public class SnoozeHelperTest extends UiServiceTestCase {
}
@Test
+ public void testSnoozeLimit() {
+ for (int i = 0; i < CONCURRENT_SNOOZE_LIMIT; i++ ) {
+ NotificationRecord r = getNotificationRecord("pkg", i, i+"", UserHandle.SYSTEM);
+
+ assertTrue("cannot snooze record " + i, mSnoozeHelper.canSnooze(1));
+
+ if (i % 2 == 0) {
+ mSnoozeHelper.snooze(r, null);
+ } else {
+ mSnoozeHelper.snooze(r, 9000);
+ }
+ }
+ assertFalse(mSnoozeHelper.canSnooze(1));
+ }
+
+ @Test
public void testCancelByApp() throws Exception {
NotificationRecord r = getNotificationRecord("pkg", 1, "one", UserHandle.SYSTEM);
NotificationRecord r2 = getNotificationRecord("pkg", 2, "two", UserHandle.SYSTEM);
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index 0c3b270518cf..3f3d01a14f80 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -49,7 +49,6 @@ import static android.os.InputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
import static android.os.Process.NOBODY_UID;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.InsetsState.ITYPE_IME;
-import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
import static android.view.WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD;
@@ -2539,21 +2538,6 @@ public class ActivityRecordTests extends WindowTestsBase {
}
@Test
- public void testStuckExitingWindow() {
- final WindowState closingWindow = createWindow(null, FIRST_APPLICATION_WINDOW,
- "closingWindow");
- closingWindow.mAnimatingExit = true;
- closingWindow.mRemoveOnExit = true;
- closingWindow.mActivityRecord.commitVisibility(
- false /* visible */, true /* performLayout */);
-
- // We pretended that we were running an exit animation, but that should have been cleared up
- // by changing visibility of ActivityRecord
- closingWindow.removeIfPossible();
- assertTrue(closingWindow.mRemoved);
- }
-
- @Test
public void testSetOrientation() {
final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true).build();
activity.setVisible(true);
@@ -3149,6 +3133,7 @@ public class ActivityRecordTests extends WindowTestsBase {
mDisplayContent.mOpeningApps.clear();
app.mActivityRecord.commitVisibility(false, false);
app.mActivityRecord.onWindowsGone();
+ mDisplayContent.computeImeTargetIfNeeded(app.mActivityRecord);
assertTrue(app.mActivityRecord.mLastImeShown);
assertTrue(app.mActivityRecord.mImeInsetsFrozenUntilStartInput);
diff --git a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
index 324e244c46f5..f2640d2dc404 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
@@ -1496,6 +1496,79 @@ public class SizeCompatTests extends WindowTestsBase {
}
@Test
+ public void testComputeConfigResourceOverrides_unresizableApp() {
+ // Set up a display in landscape and ignoring orientation request.
+ setUpDisplaySizeWithApp(2800, 1400);
+ mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
+
+ prepareUnresizable(mActivity, SCREEN_ORIENTATION_PORTRAIT);
+
+ final Rect activityBounds = new Rect(mActivity.getBounds());
+
+ int originalScreenWidthDp = mActivity.getConfiguration().screenWidthDp;
+ int originalScreenHeighthDp = mActivity.getConfiguration().screenHeightDp;
+
+ // App should launch in fixed orientation letterbox.
+ // Activity bounds should be 700x1400 with the ratio as the display.
+ assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
+ assertFitted();
+ assertEquals(originalScreenWidthDp, mActivity.getConfiguration().smallestScreenWidthDp);
+ assertTrue(originalScreenWidthDp < originalScreenHeighthDp);
+
+ // Rotate display to portrait.
+ rotateDisplay(mActivity.mDisplayContent, ROTATION_90);
+
+ // After we rotate, the activity should go in the size-compat mode and report the same
+ // configuration values.
+ assertScaled();
+ assertEquals(originalScreenWidthDp, mActivity.getConfiguration().smallestScreenWidthDp);
+ assertEquals(originalScreenWidthDp, mActivity.getConfiguration().screenWidthDp);
+ assertEquals(originalScreenHeighthDp, mActivity.getConfiguration().screenHeightDp);
+
+ // Restart activity
+ mActivity.restartProcessIfVisible();
+
+ // Now configuration should be updated
+ assertFitted();
+ assertNotEquals(originalScreenWidthDp, mActivity.getConfiguration().screenWidthDp);
+ assertNotEquals(originalScreenHeighthDp, mActivity.getConfiguration().screenHeightDp);
+ assertEquals(mActivity.getConfiguration().screenWidthDp,
+ mActivity.getConfiguration().smallestScreenWidthDp);
+ }
+
+ @Test
+ public void testComputeConfigResourceOverrides_resizableFixedOrientationActivity() {
+ // Set up a display in landscape and ignoring orientation request.
+ setUpDisplaySizeWithApp(2800, 1400);
+ mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
+
+ // Portrait fixed app without max aspect.
+ prepareLimitedBounds(mActivity, SCREEN_ORIENTATION_PORTRAIT, false /* isUnresizable */);
+
+ final Rect activityBounds = new Rect(mActivity.getBounds());
+
+ int originalScreenWidthDp = mActivity.getConfiguration().screenWidthDp;
+ int originalScreenHeighthDp = mActivity.getConfiguration().screenHeightDp;
+
+ // App should launch in fixed orientation letterbox.
+ // Activity bounds should be 700x1400 with the ratio as the display.
+ assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
+ assertFitted();
+ assertEquals(originalScreenWidthDp, mActivity.getConfiguration().smallestScreenWidthDp);
+ assertTrue(originalScreenWidthDp < originalScreenHeighthDp);
+
+ // Rotate display to portrait.
+ rotateDisplay(mActivity.mDisplayContent, ROTATION_90);
+
+ // Now configuration should be updated
+ assertFitted();
+ assertNotEquals(originalScreenWidthDp, mActivity.getConfiguration().screenWidthDp);
+ assertNotEquals(originalScreenHeighthDp, mActivity.getConfiguration().screenHeightDp);
+ assertEquals(mActivity.getConfiguration().screenWidthDp,
+ mActivity.getConfiguration().smallestScreenWidthDp);
+ }
+
+ @Test
public void testSplitAspectRatioForUnresizablePortraitApps() {
// Set up a display in landscape and ignoring orientation request.
int screenWidth = 1600;
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
index 46e21f1ffdbc..e2fe1b175dc8 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
@@ -691,7 +691,8 @@ public class TaskTests extends WindowTestsBase {
final ActivityRecord.CompatDisplayInsets compatInsets =
new ActivityRecord.CompatDisplayInsets(
display, activity, /* fixedOrientationBounds= */ null);
- task.computeConfigResourceOverrides(inOutConfig, parentConfig, compatInsets);
+ task.computeConfigResourceOverrides(
+ inOutConfig, parentConfig, compatInsets, /* areBoundsLetterboxed */ true);
assertEquals(largerLandscapeBounds, inOutConfig.windowConfiguration.getAppBounds());
final float density = parentConfig.densityDpi * DisplayMetrics.DENSITY_DEFAULT_SCALE;
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
index fb7400bc83ef..446ec8b2680b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
@@ -720,6 +720,17 @@ public class WindowStateTests extends WindowTestsBase {
outWaitingForDrawn.clear();
invisibleApp.requestDrawIfNeeded(outWaitingForDrawn);
assertTrue(outWaitingForDrawn.isEmpty());
+
+ // Drawn state should not be changed for insets change when screen is off.
+ spyOn(mWm.mPolicy);
+ doReturn(false).when(mWm.mPolicy).isScreenOn();
+ makeWindowVisibleAndDrawn(startingApp);
+ startingApp.getConfiguration().orientation = 0; // Reset to be the same as last reported.
+ startingApp.getWindowFrames().setInsetsChanged(true);
+ startingApp.updateResizingWindowIfNeeded();
+ assertTrue(mWm.mResizingWindows.contains(startingApp));
+ assertTrue(startingApp.isDrawn());
+ assertFalse(startingApp.getOrientationChanging());
}
@UseTestDisplay(addWindows = W_ABOVE_ACTIVITY)
@@ -992,6 +1003,7 @@ public class WindowStateTests extends WindowTestsBase {
assertTrue(app.mActivityRecord.mImeInsetsFrozenUntilStartInput);
// Verify the IME insets is visible on app, but not for app2 during app task switching.
+ mDisplayContent.computeImeTargetIfNeeded(app.mActivityRecord);
assertTrue(app.getInsetsState().getSource(ITYPE_IME).isVisible());
assertFalse(app2.getInsetsState().getSource(ITYPE_IME).isVisible());
}
diff --git a/services/usb/java/com/android/server/usb/MtpNotificationManager.java b/services/usb/java/com/android/server/usb/MtpNotificationManager.java
index 8845f118f3a8..70bafc0d5146 100644
--- a/services/usb/java/com/android/server/usb/MtpNotificationManager.java
+++ b/services/usb/java/com/android/server/usb/MtpNotificationManager.java
@@ -117,7 +117,7 @@ class MtpNotificationManager {
@Override
public void onReceive(Context context, Intent intent) {
final UsbDevice device =
- intent.getExtras().<UsbDevice>getParcelable(UsbManager.EXTRA_DEVICE);
+ intent.getExtras().<UsbDevice>getParcelable(UsbManager.EXTRA_DEVICE, android.hardware.usb.UsbDevice.class);
if (device == null) {
return;
}
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index 6ea416b54811..85b9f759beac 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -341,8 +341,8 @@ public class UsbDeviceManager implements ActivityTaskManagerInternal.ScreenObser
BroadcastReceiver portReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
- ParcelableUsbPort port = intent.getParcelableExtra(UsbManager.EXTRA_PORT);
- UsbPortStatus status = intent.getParcelableExtra(UsbManager.EXTRA_PORT_STATUS);
+ ParcelableUsbPort port = intent.getParcelableExtra(UsbManager.EXTRA_PORT, android.hardware.usb.ParcelableUsbPort.class);
+ UsbPortStatus status = intent.getParcelableExtra(UsbManager.EXTRA_PORT_STATUS, android.hardware.usb.UsbPortStatus.class);
mHandler.updateHostState(
port.getUsbPort(context.getSystemService(UsbManager.class)), status);
}
diff --git a/services/usb/java/com/android/server/usb/UsbPortManager.java b/services/usb/java/com/android/server/usb/UsbPortManager.java
index 5e633ab3aef5..f8df6c6ea8df 100644
--- a/services/usb/java/com/android/server/usb/UsbPortManager.java
+++ b/services/usb/java/com/android/server/usb/UsbPortManager.java
@@ -1156,7 +1156,7 @@ public class UsbPortManager {
switch (msg.what) {
case MSG_UPDATE_PORTS: {
Bundle b = msg.getData();
- ArrayList<RawPortInfo> PortInfo = b.getParcelableArrayList(PORT_INFO);
+ ArrayList<RawPortInfo> PortInfo = b.getParcelableArrayList(PORT_INFO, com.android.server.usb.hal.port.RawPortInfo.class);
synchronized (mLock) {
updatePortsLocked(null, PortInfo);
}
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
index a061618b1ca7..093e97614b5a 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
@@ -399,8 +399,8 @@ final class VoiceInteractionSessionConnection implements ServiceConnection,
final int taskId = data.getInt(ASSIST_TASK_ID);
final IBinder activityId = data.getBinder(ASSIST_ACTIVITY_ID);
final Bundle assistData = data.getBundle(ASSIST_KEY_DATA);
- final AssistStructure structure = data.getParcelable(ASSIST_KEY_STRUCTURE);
- final AssistContent content = data.getParcelable(ASSIST_KEY_CONTENT);
+ final AssistStructure structure = data.getParcelable(ASSIST_KEY_STRUCTURE, android.app.assist.AssistStructure.class);
+ final AssistContent content = data.getParcelable(ASSIST_KEY_CONTENT, android.app.assist.AssistContent.class);
int uid = -1;
if (assistData != null) {
uid = assistData.getInt(Intent.EXTRA_ASSIST_UID, -1);
diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java
index bce6809ef32d..f341bc20fe01 100755
--- a/telecomm/java/android/telecom/ConnectionService.java
+++ b/telecomm/java/android/telecom/ConnectionService.java
@@ -2044,7 +2044,7 @@ public abstract class ConnectionService extends Service {
if (isHandover) {
PhoneAccountHandle fromPhoneAccountHandle = request.getExtras() != null
? (PhoneAccountHandle) request.getExtras().getParcelable(
- TelecomManager.EXTRA_HANDOVER_FROM_PHONE_ACCOUNT) : null;
+ TelecomManager.EXTRA_HANDOVER_FROM_PHONE_ACCOUNT, android.telecom.PhoneAccountHandle.class) : null;
if (!isIncoming) {
connection = onCreateOutgoingHandoverConnection(fromPhoneAccountHandle, request);
} else {
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index 6fe9bf97c5c3..bfa60ba960ca 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -1445,7 +1445,7 @@ public class ServiceState implements Parcelable {
*/
@UnsupportedAppUsage
private void setFromNotifierBundle(Bundle m) {
- ServiceState ssFromBundle = m.getParcelable(EXTRA_SERVICE_STATE);
+ ServiceState ssFromBundle = m.getParcelable(EXTRA_SERVICE_STATE, android.telephony.ServiceState.class);
if (ssFromBundle != null) {
copyFrom(ssFromBundle);
}
diff --git a/telephony/java/android/telephony/SignalStrength.java b/telephony/java/android/telephony/SignalStrength.java
index f74ef0fe764a..f1af68f5cfee 100644
--- a/telephony/java/android/telephony/SignalStrength.java
+++ b/telephony/java/android/telephony/SignalStrength.java
@@ -906,12 +906,12 @@ public class SignalStrength implements Parcelable {
@Deprecated
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
private void setFromNotifierBundle(Bundle m) {
- mCdma = m.getParcelable("Cdma");
- mGsm = m.getParcelable("Gsm");
- mWcdma = m.getParcelable("Wcdma");
- mTdscdma = m.getParcelable("Tdscdma");
- mLte = m.getParcelable("Lte");
- mNr = m.getParcelable("Nr");
+ mCdma = m.getParcelable("Cdma", android.telephony.CellSignalStrengthCdma.class);
+ mGsm = m.getParcelable("Gsm", android.telephony.CellSignalStrengthGsm.class);
+ mWcdma = m.getParcelable("Wcdma", android.telephony.CellSignalStrengthWcdma.class);
+ mTdscdma = m.getParcelable("Tdscdma", android.telephony.CellSignalStrengthTdscdma.class);
+ mLte = m.getParcelable("Lte", android.telephony.CellSignalStrengthLte.class);
+ mNr = m.getParcelable("Nr", android.telephony.CellSignalStrengthNr.class);
}
/**
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 432d08725e87..24374ee64719 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -4867,7 +4867,7 @@ public class TelephonyManager {
return;
}
ParcelUuid resultUuid =
- result.getParcelable(KEY_CALL_COMPOSER_PICTURE_HANDLE);
+ result.getParcelable(KEY_CALL_COMPOSER_PICTURE_HANDLE, android.os.ParcelUuid.class);
if (resultUuid == null) {
Log.e(TAG, "Got null uuid without an error"
+ " while uploading call composer pic");
@@ -10375,7 +10375,7 @@ public class TelephonyManager {
protected void onReceiveResult(int resultCode, Bundle ussdResponse) {
Rlog.d(TAG, "USSD:" + resultCode);
checkNotNull(ussdResponse, "ussdResponse cannot be null.");
- UssdResponse response = ussdResponse.getParcelable(USSD_RESPONSE);
+ UssdResponse response = ussdResponse.getParcelable(USSD_RESPONSE, android.telephony.UssdResponse.class);
if (resultCode == USSD_RETURN_SUCCESS) {
callback.onReceiveUssdResponse(telephonyManager, response.getUssdRequest(),
@@ -16867,7 +16867,7 @@ public class TelephonyManager {
}
NetworkSlicingConfig slicingConfig =
- result.getParcelable(KEY_SLICING_CONFIG_HANDLE);
+ result.getParcelable(KEY_SLICING_CONFIG_HANDLE, android.telephony.data.NetworkSlicingConfig.class);
executor.execute(() -> callback.onResult(slicingConfig));
}
});
diff --git a/telephony/java/android/telephony/VisualVoicemailService.java b/telephony/java/android/telephony/VisualVoicemailService.java
index fe30eb7bb005..a530917a271c 100644
--- a/telephony/java/android/telephony/VisualVoicemailService.java
+++ b/telephony/java/android/telephony/VisualVoicemailService.java
@@ -157,14 +157,14 @@ public abstract class VisualVoicemailService extends Service {
@Override
public void handleMessage(final Message msg) {
final PhoneAccountHandle handle = msg.getData()
- .getParcelable(DATA_PHONE_ACCOUNT_HANDLE);
+ .getParcelable(DATA_PHONE_ACCOUNT_HANDLE, android.telecom.PhoneAccountHandle.class);
VisualVoicemailTask task = new VisualVoicemailTask(msg.replyTo, msg.arg1);
switch (msg.what) {
case MSG_ON_CELL_SERVICE_CONNECTED:
onCellServiceConnected(task, handle);
break;
case MSG_ON_SMS_RECEIVED:
- VisualVoicemailSms sms = msg.getData().getParcelable(DATA_SMS);
+ VisualVoicemailSms sms = msg.getData().getParcelable(DATA_SMS, android.telephony.VisualVoicemailSms.class);
onSmsReceived(task, sms);
break;
case MSG_ON_SIM_REMOVED:
diff --git a/telephony/java/android/telephony/euicc/EuiccManager.java b/telephony/java/android/telephony/euicc/EuiccManager.java
index 1252dc178cb9..7d63688025e0 100644
--- a/telephony/java/android/telephony/euicc/EuiccManager.java
+++ b/telephony/java/android/telephony/euicc/EuiccManager.java
@@ -1001,7 +1001,7 @@ public class EuiccManager {
public void startResolutionActivity(Activity activity, int requestCode, Intent resultIntent,
PendingIntent callbackIntent) throws IntentSender.SendIntentException {
PendingIntent resolutionIntent =
- resultIntent.getParcelableExtra(EXTRA_EMBEDDED_SUBSCRIPTION_RESOLUTION_INTENT);
+ resultIntent.getParcelableExtra(EXTRA_EMBEDDED_SUBSCRIPTION_RESOLUTION_INTENT, android.app.PendingIntent.class);
if (resolutionIntent == null) {
throw new IllegalArgumentException("Invalid result intent");
}
@@ -1032,7 +1032,7 @@ public class EuiccManager {
if (!isEnabled()) {
PendingIntent callbackIntent =
resolutionIntent.getParcelableExtra(
- EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_RESOLUTION_CALLBACK_INTENT);
+ EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_RESOLUTION_CALLBACK_INTENT, android.app.PendingIntent.class);
if (callbackIntent != null) {
sendUnavailableError(callbackIntent);
}
diff --git a/telephony/java/android/telephony/mbms/MbmsDownloadReceiver.java b/telephony/java/android/telephony/mbms/MbmsDownloadReceiver.java
index dd1061f3bd46..556d6f4565d4 100644
--- a/telephony/java/android/telephony/mbms/MbmsDownloadReceiver.java
+++ b/telephony/java/android/telephony/mbms/MbmsDownloadReceiver.java
@@ -195,7 +195,7 @@ public class MbmsDownloadReceiver extends BroadcastReceiver {
return false;
}
DownloadRequest request = intent.getParcelableExtra(
- MbmsDownloadSession.EXTRA_MBMS_DOWNLOAD_REQUEST);
+ MbmsDownloadSession.EXTRA_MBMS_DOWNLOAD_REQUEST, android.telephony.mbms.DownloadRequest.class);
String expectedTokenFileName = request.getHash() + DOWNLOAD_TOKEN_SUFFIX;
File expectedTokenFile = new File(
MbmsUtils.getEmbmsTempFileDirForService(context, request.getFileServiceId()),
@@ -236,7 +236,7 @@ public class MbmsDownloadReceiver extends BroadcastReceiver {
private void moveDownloadedFile(Context context, Intent intent) {
DownloadRequest request = intent.getParcelableExtra(
- MbmsDownloadSession.EXTRA_MBMS_DOWNLOAD_REQUEST);
+ MbmsDownloadSession.EXTRA_MBMS_DOWNLOAD_REQUEST, android.telephony.mbms.DownloadRequest.class);
Intent intentForApp = request.getIntentForApp();
if (intentForApp == null) {
Log.i(LOG_TAG, "Malformed app notification intent");
@@ -256,7 +256,7 @@ public class MbmsDownloadReceiver extends BroadcastReceiver {
return;
}
- Uri finalTempFile = intent.getParcelableExtra(VendorUtils.EXTRA_FINAL_URI);
+ Uri finalTempFile = intent.getParcelableExtra(VendorUtils.EXTRA_FINAL_URI, android.net.Uri.class);
if (!verifyTempFilePath(context, request.getFileServiceId(), finalTempFile)) {
Log.w(LOG_TAG, "Download result specified an invalid temp file " + finalTempFile);
setResultCode(RESULT_DOWNLOAD_FINALIZATION_ERROR);
@@ -264,7 +264,7 @@ public class MbmsDownloadReceiver extends BroadcastReceiver {
}
FileInfo completedFileInfo =
- (FileInfo) intent.getParcelableExtra(MbmsDownloadSession.EXTRA_MBMS_FILE_INFO);
+ (FileInfo) intent.getParcelableExtra(MbmsDownloadSession.EXTRA_MBMS_FILE_INFO, android.telephony.mbms.FileInfo.class);
Path appSpecifiedDestination = FileSystems.getDefault().getPath(
request.getDestinationUri().getPath());
@@ -288,13 +288,13 @@ public class MbmsDownloadReceiver extends BroadcastReceiver {
private void cleanupPostMove(Context context, Intent intent) {
DownloadRequest request = intent.getParcelableExtra(
- MbmsDownloadSession.EXTRA_MBMS_DOWNLOAD_REQUEST);
+ MbmsDownloadSession.EXTRA_MBMS_DOWNLOAD_REQUEST, android.telephony.mbms.DownloadRequest.class);
if (request == null) {
Log.w(LOG_TAG, "Intent does not include a DownloadRequest. Ignoring.");
return;
}
- List<Uri> tempFiles = intent.getParcelableArrayListExtra(VendorUtils.EXTRA_TEMP_LIST);
+ List<Uri> tempFiles = intent.getParcelableArrayListExtra(VendorUtils.EXTRA_TEMP_LIST, android.net.Uri.class);
if (tempFiles == null) {
return;
}
@@ -318,7 +318,7 @@ public class MbmsDownloadReceiver extends BroadcastReceiver {
return;
}
int fdCount = intent.getIntExtra(VendorUtils.EXTRA_FD_COUNT, 0);
- List<Uri> pausedList = intent.getParcelableArrayListExtra(VendorUtils.EXTRA_PAUSED_LIST);
+ List<Uri> pausedList = intent.getParcelableArrayListExtra(VendorUtils.EXTRA_PAUSED_LIST, android.net.Uri.class);
if (fdCount == 0 && (pausedList == null || pausedList.size() == 0)) {
Log.i(LOG_TAG, "No temp files actually requested. Ending.");
@@ -417,7 +417,7 @@ public class MbmsDownloadReceiver extends BroadcastReceiver {
String serviceId = intent.getStringExtra(VendorUtils.EXTRA_SERVICE_ID);
File tempFileDir = MbmsUtils.getEmbmsTempFileDirForService(context, serviceId);
final List<Uri> filesInUse =
- intent.getParcelableArrayListExtra(VendorUtils.EXTRA_TEMP_FILES_IN_USE);
+ intent.getParcelableArrayListExtra(VendorUtils.EXTRA_TEMP_FILES_IN_USE, android.net.Uri.class);
File[] filesToDelete = tempFileDir.listFiles(new FileFilter() {
@Override
public boolean accept(File file) {
diff --git a/tests/FlickerTests/Android.bp b/tests/FlickerTests/Android.bp
index 7731e098d9f5..855d3c1f4ea7 100644
--- a/tests/FlickerTests/Android.bp
+++ b/tests/FlickerTests/Android.bp
@@ -46,6 +46,7 @@ android_test {
"launcher-helper-lib",
"launcher-aosp-tapl",
"platform-test-annotations",
+ "wm-flicker-window-extensions",
],
}
@@ -83,5 +84,21 @@ java_library {
"flickertestapplib",
"truth-prebuilt",
"app-helpers-core",
+ "wm-flicker-window-extensions",
],
}
+
+android_library_import {
+ name: "wm-flicker-window-extensions_nodeps",
+ aars: ["libs/window-extensions-release.aar"],
+ sdk_version: "current",
+}
+
+java_library {
+ name: "wm-flicker-window-extensions",
+ sdk_version: "current",
+ static_libs: [
+ "wm-flicker-window-extensions_nodeps",
+ ],
+ installable: false,
+}
diff --git a/tests/FlickerTests/AndroidManifest.xml b/tests/FlickerTests/AndroidManifest.xml
index fda609196456..e173eba0a393 100644
--- a/tests/FlickerTests/AndroidManifest.xml
+++ b/tests/FlickerTests/AndroidManifest.xml
@@ -43,6 +43,7 @@
<!-- Allow the test to write directly to /sdcard/ -->
<application android:requestLegacyExternalStorage="true">
<uses-library android:name="android.test.runner"/>
+ <uses-library android:name="androidx.window.extensions" android:required="false"/>
</application>
<instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
diff --git a/tests/FlickerTests/libs/window-extensions-release.aar b/tests/FlickerTests/libs/window-extensions-release.aar
new file mode 100644
index 000000000000..6fc9a67fb19f
--- /dev/null
+++ b/tests/FlickerTests/libs/window-extensions-release.aar
Binary files differ
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt
index 896c7309cf4c..2e97eb14249a 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt
@@ -21,11 +21,6 @@ import com.android.server.wm.flicker.helpers.WindowUtils
import com.android.server.wm.flicker.traces.region.RegionSubject
import com.android.server.wm.traces.common.FlickerComponentName
-val LAUNCHER_COMPONENT = FlickerComponentName(
- "com.google.android.apps.nexuslauncher",
- "com.google.android.apps.nexuslauncher.NexusLauncherActivity"
-)
-
/**
* Checks that [FlickerComponentName.STATUS_BAR] window is visible and above the app windows in
* all WM trace entries
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/ActivityEmbeddingTestBase.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/ActivityEmbeddingTestBase.kt
new file mode 100644
index 000000000000..ed411b5eaf02
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/ActivityEmbeddingTestBase.kt
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.activityembedding
+
+import android.app.Instrumentation
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.server.wm.flicker.helpers.ActivityEmbeddingAppHelper
+import org.junit.Before
+
+abstract class ActivityEmbeddingTestBase {
+ val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ val testApp = ActivityEmbeddingAppHelper(instrumentation)
+
+ @Before
+ fun assumeActivityEmbeddingSupported() {
+ // The test should only be run on devices that support ActivityEmbedding.
+ ActivityEmbeddingAppHelper.assumeActivityEmbeddingSupportedDevice()
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/OpenActivityEmbeddingPlaceholderSplit.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/OpenActivityEmbeddingPlaceholderSplit.kt
new file mode 100644
index 000000000000..28a72f4da592
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/OpenActivityEmbeddingPlaceholderSplit.kt
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.activityembedding
+
+import android.platform.test.annotations.Presubmit
+import android.view.Surface
+import android.view.WindowManagerPolicyConstants
+import androidx.test.filters.RequiresDevice
+import com.android.server.wm.flicker.FlickerBuilderProvider
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.helpers.ActivityEmbeddingAppHelper
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test opening an activity that will launch another activity as ActivityEmbedding placeholder in
+ * split.
+ *
+ * To run this test: `atest FlickerTests:OpenActivityEmbeddingPlaceholderSplit`
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+class OpenActivityEmbeddingPlaceholderSplit(private val testSpec: FlickerTestParameter) :
+ ActivityEmbeddingTestBase() {
+
+ @FlickerBuilderProvider
+ fun buildFlicker(): FlickerBuilder {
+ return FlickerBuilder(instrumentation).apply {
+ setup {
+ eachRun {
+ testApp.launchViaIntent(wmHelper)
+ }
+ }
+ transitions {
+ testApp.launchPlaceholderSplit(wmHelper)
+ }
+ teardown {
+ test {
+ device.pressHome()
+ testApp.exit(wmHelper)
+ }
+ }
+ }
+ }
+
+ @Presubmit
+ @Test
+ fun mainActivityBecomesInvisible() {
+ testSpec.assertLayers {
+ isVisible(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT)
+ .then()
+ .isInvisible(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT)
+ }
+ }
+
+ @Presubmit
+ @Test
+ fun placeholderSplitBecomesVisible() {
+ testSpec.assertLayers {
+ isInvisible(ActivityEmbeddingAppHelper.PLACEHOLDER_PRIMARY_COMPONENT)
+ .then()
+ .isVisible(ActivityEmbeddingAppHelper.PLACEHOLDER_PRIMARY_COMPONENT)
+ }
+ testSpec.assertLayers {
+ isInvisible(ActivityEmbeddingAppHelper.PLACEHOLDER_SECONDARY_COMPONENT)
+ .then()
+ .isVisible(ActivityEmbeddingAppHelper.PLACEHOLDER_SECONDARY_COMPONENT)
+ }
+ }
+
+ companion object {
+ /**
+ * Creates the test configurations.
+ *
+ * See [FlickerTestParameterFactory.getConfigNonRotationTests] for configuring
+ * repetitions, screen orientation and navigation modes.
+ */
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): Collection<FlickerTestParameter> {
+ return FlickerTestParameterFactory.getInstance()
+ .getConfigNonRotationTests(
+ repetitions = 1,
+ supportedRotations = listOf(Surface.ROTATION_0, Surface.ROTATION_90),
+ supportedNavigationModes = listOf(
+ WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY,
+ WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY
+ )
+ )
+ }
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppTransition.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppTransition.kt
index ae002c9458f5..730e5bcc3280 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppTransition.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppTransition.kt
@@ -191,6 +191,10 @@ abstract class CloseAppTransition(protected val testSpec: FlickerTestParameter)
@Presubmit
@Test
open fun launcherLayerReplacesApp() {
- testSpec.replacesLayer(testApp.component, LAUNCHER)
+ testSpec.replacesLayer(
+ testApp.component,
+ LAUNCHER,
+ ignoreEntriesWithRotationLayer = testSpec.isLandscapeOrSeascapeAtStart
+ )
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ActivityEmbeddingAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ActivityEmbeddingAppHelper.kt
new file mode 100644
index 000000000000..a01f633cbae4
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ActivityEmbeddingAppHelper.kt
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.helpers
+
+import android.app.Instrumentation
+import android.support.test.launcherhelper.ILauncherStrategy
+import android.support.test.launcherhelper.LauncherStrategyFactory
+import android.util.Log
+import androidx.test.uiautomator.By
+import androidx.test.uiautomator.Until
+import androidx.window.extensions.WindowExtensions
+import androidx.window.extensions.WindowExtensionsProvider
+import androidx.window.extensions.embedding.ActivityEmbeddingComponent
+import com.android.server.wm.flicker.testapp.ActivityOptions
+import com.android.server.wm.traces.common.FlickerComponentName
+import com.android.server.wm.traces.common.windowmanager.WindowManagerState.Companion.STATE_RESUMED
+import com.android.server.wm.traces.parser.toFlickerComponent
+import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
+import org.junit.Assume.assumeNotNull
+
+class ActivityEmbeddingAppHelper @JvmOverloads constructor(
+ instr: Instrumentation,
+ launcherName: String = ActivityOptions.ACTIVITY_EMBEDDING_LAUNCHER_NAME,
+ component: FlickerComponentName = MAIN_ACTIVITY_COMPONENT,
+ launcherStrategy: ILauncherStrategy = LauncherStrategyFactory
+ .getInstance(instr)
+ .launcherStrategy
+) : StandardAppHelper(instr, launcherName, component, launcherStrategy) {
+
+ /**
+ * Clicks the button to launch the placeholder primary activity, which should launch the
+ * placeholder secondary activity based on the placeholder rule.
+ */
+ fun launchPlaceholderSplit(wmHelper: WindowManagerStateHelper) {
+ val launchButton = uiDevice.wait(
+ Until.findObject(By.res(getPackage(), "launch_placeholder_split_button")),
+ FIND_TIMEOUT)
+ require(launchButton != null) {
+ "Can't find launch placeholder split button on screen."
+ }
+ launchButton.click()
+ wmHelper.StateSyncBuilder()
+ .withActivityState(PLACEHOLDER_PRIMARY_COMPONENT, STATE_RESUMED)
+ .withActivityState(PLACEHOLDER_SECONDARY_COMPONENT, STATE_RESUMED)
+ .waitForAndVerify()
+ }
+
+ companion object {
+ private const val TAG = "ActivityEmbeddingAppHelper"
+
+ val MAIN_ACTIVITY_COMPONENT = ActivityOptions
+ .ACTIVITY_EMBEDDING_MAIN_ACTIVITY_COMPONENT_NAME.toFlickerComponent()
+
+ val PLACEHOLDER_PRIMARY_COMPONENT = ActivityOptions
+ .ACTIVITY_EMBEDDING_PLACEHOLDER_PRIMARY_ACTIVITY_COMPONENT_NAME.toFlickerComponent()
+
+ val PLACEHOLDER_SECONDARY_COMPONENT = ActivityOptions
+ .ACTIVITY_EMBEDDING_PLACEHOLDER_SECONDARY_ACTIVITY_COMPONENT_NAME
+ .toFlickerComponent()
+
+ @JvmStatic
+ fun getWindowExtensions(): WindowExtensions? {
+ try {
+ return WindowExtensionsProvider.getWindowExtensions()
+ } catch (e: NoClassDefFoundError) {
+ Log.d(TAG, "Extension implementation not found")
+ } catch (e: UnsupportedOperationException) {
+ Log.d(TAG, "Stub Extension")
+ }
+ return null
+ }
+
+ @JvmStatic
+ fun getActivityEmbeddingComponent(): ActivityEmbeddingComponent? {
+ return getWindowExtensions()?.activityEmbeddingComponent
+ }
+
+ @JvmStatic
+ fun assumeActivityEmbeddingSupportedDevice() {
+ assumeNotNull(getActivityEmbeddingComponent())
+ }
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLauncherTransition.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLauncherTransition.kt
index 269d82d7fa5a..027a04fab4e3 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLauncherTransition.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLauncherTransition.kt
@@ -60,11 +60,11 @@ abstract class OpenAppFromLauncherTransition(testSpec: FlickerTestParameter) :
testSpec.assertWm {
this.isAppWindowOnTop(FlickerComponentName.LAUNCHER)
.then()
- .isAppWindowOnTop(FlickerComponentName.SNAPSHOT, isOptional = true)
- .then()
- .isAppWindowOnTop(FlickerComponentName.SPLASH_SCREEN, isOptional = true)
- .then()
- .isAppWindowOnTop(testApp.component)
+ .isAppWindowOnTop(
+ testApp.component
+ .or(FlickerComponentName.SNAPSHOT)
+ .or(FlickerComponentName.SPLASH_SCREEN)
+ )
}
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationCold.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationCold.kt
index cea97ad0302a..fcf7c1d6917f 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationCold.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationCold.kt
@@ -143,6 +143,12 @@ open class OpenAppFromLockNotificationCold(testSpec: FlickerTestParameter) :
override fun visibleLayersShownMoreThanOneConsecutiveEntry() =
super.visibleLayersShownMoreThanOneConsecutiveEntry()
+ /** {@inheritDoc} */
+ @Postsubmit
+ @Test
+ override fun appWindowIsTopWindowAtEnd() =
+ super.appWindowIsTopWindowAtEnd()
+
companion object {
/**
* Creates the test configurations.
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWarm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWarm.kt
index 3d5f31709a66..46f378e97726 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWarm.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWarm.kt
@@ -174,6 +174,12 @@ open class OpenAppFromLockNotificationWarm(testSpec: FlickerTestParameter) :
override fun visibleLayersShownMoreThanOneConsecutiveEntry() =
super.visibleLayersShownMoreThanOneConsecutiveEntry()
+ /** {@inheritDoc} */
+ @Postsubmit
+ @Test
+ override fun appWindowIsTopWindowAtEnd() =
+ super.appWindowIsTopWindowAtEnd()
+
companion object {
/**
* Creates the test configurations.
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWithLockOverlayApp.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWithLockOverlayApp.kt
index 446faa743450..f7ec940d90cd 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWithLockOverlayApp.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWithLockOverlayApp.kt
@@ -180,6 +180,12 @@ class OpenAppFromLockNotificationWithLockOverlayApp(testSpec: FlickerTestParamet
override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
super.visibleWindowsShownMoreThanOneConsecutiveEntry()
+ /** {@inheritDoc} */
+ @Postsubmit
+ @Test
+ override fun appWindowIsTopWindowAtEnd() =
+ super.appWindowIsTopWindowAtEnd()
+
companion object {
/**
* Creates the test configurations.
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationCold.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationCold.kt
index 68e8e467b950..eaf4daca6e20 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationCold.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationCold.kt
@@ -67,6 +67,12 @@ open class OpenAppFromNotificationCold(testSpec: FlickerTestParameter) :
@Postsubmit
override fun appLayerBecomesVisible() = appLayerBecomesVisible_coldStart()
+ /** {@inheritDoc} */
+ @Postsubmit
+ @Test
+ override fun appWindowIsTopWindowAtEnd() =
+ super.appWindowIsTopWindowAtEnd()
+
companion object {
/**
* Creates the test configurations.
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationWarm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationWarm.kt
index 6d5911152dc0..9e9b0c9a1fd9 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationWarm.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationWarm.kt
@@ -209,6 +209,12 @@ open class OpenAppFromNotificationWarm(testSpec: FlickerTestParameter) :
override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
super.visibleWindowsShownMoreThanOneConsecutiveEntry()
+ /** {@inheritDoc} */
+ @Postsubmit
+ @Test
+ override fun appWindowIsTopWindowAtEnd() =
+ super.appWindowIsTopWindowAtEnd()
+
companion object {
/**
* Creates the test configurations.
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt
index 04523398046f..ec083509f364 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt
@@ -159,6 +159,11 @@ open class OpenAppNonResizeableTest(testSpec: FlickerTestParameter) :
override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
super.visibleWindowsShownMoreThanOneConsecutiveEntry()
+ @FlakyTest(bugId = 227143265)
+ @Test
+ override fun appWindowBecomesTopWindow() =
+ super.appWindowBecomesTopWindow()
+
companion object {
/**
* Creates the test configurations.
diff --git a/tests/FlickerTests/test-apps/flickerapp/Android.bp b/tests/FlickerTests/test-apps/flickerapp/Android.bp
index 78660c04d8d4..0c698abeceeb 100644
--- a/tests/FlickerTests/test-apps/flickerapp/Android.bp
+++ b/tests/FlickerTests/test-apps/flickerapp/Android.bp
@@ -26,6 +26,11 @@ android_test {
srcs: ["**/*.java"],
sdk_version: "current",
test_suites: ["device-tests"],
+ static_libs: [
+ "androidx.test.ext.junit",
+ "wm-flicker-common-app-helpers",
+ "wm-flicker-window-extensions",
+ ],
}
java_library {
diff --git a/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml b/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml
index 3e2130dc480f..387f19b2396f 100644
--- a/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml
+++ b/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml
@@ -15,12 +15,14 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.server.wm.flicker.testapp">
+ package="com.android.server.wm.flicker.testapp">
<uses-sdk android:minSdkVersion="29"
android:targetSdkVersion="29"/>
<application android:allowBackup="false"
android:supportsRtl="true">
+ <uses-library android:name="androidx.window.extensions" android:required="false"/>
+
<activity android:name=".SimpleActivity"
android:taskAffinity="com.android.server.wm.flicker.testapp.SimpleActivity"
android:theme="@style/CutoutShortEdges"
@@ -163,5 +165,33 @@
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
+
+ <activity
+ android:name=".ActivityEmbeddingMainActivity"
+ android:label="ActivityEmbedding Main"
+ android:taskAffinity="com.android.server.wm.flicker.testapp.ActivityEmbedding"
+ android:theme="@style/CutoutShortEdges"
+ android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ <activity
+ android:name=".ActivityEmbeddingPlaceholderPrimaryActivity"
+ android:label="ActivityEmbedding Placeholder Primary"
+ android:taskAffinity="com.android.server.wm.flicker.testapp.ActivityEmbedding"
+ android:theme="@style/CutoutShortEdges"
+ android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout"
+ android:exported="false">
+ </activity>
+ <activity
+ android:name=".ActivityEmbeddingPlaceholderSecondaryActivity"
+ android:label="ActivityEmbedding Placeholder Secondary"
+ android:taskAffinity="com.android.server.wm.flicker.testapp.ActivityEmbedding"
+ android:theme="@style/CutoutShortEdges"
+ android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout"
+ android:exported="false"/>
</application>
</manifest>
diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_embedding_base_layout.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_embedding_base_layout.xml
new file mode 100644
index 000000000000..3a02cadc90dd
--- /dev/null
+++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_embedding_base_layout.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/root_activity_layout"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+</LinearLayout>
diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_embedding_main_layout.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_embedding_main_layout.xml
new file mode 100644
index 000000000000..19c81a8ba0f5
--- /dev/null
+++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_embedding_main_layout.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ android:background="@android:color/holo_orange_light">
+
+ <Button
+ android:id="@+id/launch_placeholder_split_button"
+ android:layout_width="wrap_content"
+ android:layout_height="48dp"
+ android:layout_centerHorizontal="true"
+ android:onClick="launchPlaceholderSplit"
+ android:text="Launch Placeholder Split" />
+
+</LinearLayout>
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityEmbeddingBaseActivity.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityEmbeddingBaseActivity.java
new file mode 100644
index 000000000000..cd23e9f76ebf
--- /dev/null
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityEmbeddingBaseActivity.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.testapp;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+/** Base activity of ActivityEmbedding split activities. */
+public abstract class ActivityEmbeddingBaseActivity extends Activity {
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_embedding_base_layout);
+ findViewById(R.id.root_activity_layout).setBackgroundColor(getBackgroundColor());
+ }
+
+ /** Sets different colors to visually distinguish split pairs. */
+ abstract int getBackgroundColor();
+}
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityEmbeddingMainActivity.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityEmbeddingMainActivity.java
new file mode 100644
index 000000000000..166e3ca2a156
--- /dev/null
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityEmbeddingMainActivity.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.testapp;
+
+import static com.android.server.wm.flicker.testapp.ActivityOptions.ACTIVITY_EMBEDDING_PLACEHOLDER_PRIMARY_ACTIVITY_COMPONENT_NAME;
+import static com.android.server.wm.flicker.testapp.ActivityOptions.ACTIVITY_EMBEDDING_PLACEHOLDER_SECONDARY_ACTIVITY_COMPONENT_NAME;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.util.ArraySet;
+import android.util.Log;
+import android.view.View;
+
+import androidx.window.extensions.embedding.ActivityEmbeddingComponent;
+import androidx.window.extensions.embedding.EmbeddingRule;
+import androidx.window.extensions.embedding.SplitPlaceholderRule;
+
+import com.android.server.wm.flicker.helpers.ActivityEmbeddingAppHelper;
+
+import java.util.Set;
+
+/** Main activity of the ActivityEmbedding test app to launch other embedding activities. */
+public class ActivityEmbeddingMainActivity extends Activity {
+ private static final String TAG = "ActivityEmbeddingMainActivity";
+ private static final float DEFAULT_SPLIT_RATIO = 0.5f;
+
+ private ActivityEmbeddingComponent mEmbeddingComponent;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_embedding_main_layout);
+
+ initializeSplitRules();
+ }
+
+ /** R.id.launch_placeholder_split_button onClick */
+ public void launchPlaceholderSplit(View view) {
+ startActivity(new Intent().setComponent(
+ ACTIVITY_EMBEDDING_PLACEHOLDER_PRIMARY_ACTIVITY_COMPONENT_NAME));
+ }
+
+ private void initializeSplitRules() {
+ mEmbeddingComponent = ActivityEmbeddingAppHelper.getActivityEmbeddingComponent();
+ if (mEmbeddingComponent == null) {
+ // Embedding not supported
+ Log.d(TAG, "ActivityEmbedding is not supported on this device");
+ finish();
+ return;
+ }
+
+ mEmbeddingComponent.setEmbeddingRules(getSplitRules());
+ }
+
+ private Set<EmbeddingRule> getSplitRules() {
+ final Set<EmbeddingRule> rules = new ArraySet<>();
+
+ final SplitPlaceholderRule placeholderRule = new SplitPlaceholderRule.Builder(
+ new Intent().setComponent(
+ ACTIVITY_EMBEDDING_PLACEHOLDER_SECONDARY_ACTIVITY_COMPONENT_NAME),
+ activity -> activity instanceof ActivityEmbeddingPlaceholderPrimaryActivity,
+ intent -> intent.getComponent().equals(
+ ACTIVITY_EMBEDDING_PLACEHOLDER_PRIMARY_ACTIVITY_COMPONENT_NAME),
+ windowMetrics -> true)
+ .setSplitRatio(DEFAULT_SPLIT_RATIO)
+ .build();
+ rules.add(placeholderRule);
+ return rules;
+ }
+}
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityEmbeddingPlaceholderPrimaryActivity.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityEmbeddingPlaceholderPrimaryActivity.java
new file mode 100644
index 000000000000..05c7a0b34c33
--- /dev/null
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityEmbeddingPlaceholderPrimaryActivity.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.testapp;
+
+import android.graphics.Color;
+
+/**
+ * Primary activity that will launch {@link ActivityEmbeddingPlaceholderSecondaryActivity} to split
+ * as placeholder based on the placeholder rule.
+ */
+public class ActivityEmbeddingPlaceholderPrimaryActivity extends ActivityEmbeddingBaseActivity {
+ @Override
+ int getBackgroundColor() {
+ return Color.BLUE;
+ }
+}
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityEmbeddingPlaceholderSecondaryActivity.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityEmbeddingPlaceholderSecondaryActivity.java
new file mode 100644
index 000000000000..a9a51cd9ad8b
--- /dev/null
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityEmbeddingPlaceholderSecondaryActivity.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.testapp;
+
+import android.graphics.Color;
+
+/**
+ * Activity to be used as the secondary placeholder activity to split with
+ * {@link ActivityEmbeddingPlaceholderPrimaryActivity}.
+ */
+public class ActivityEmbeddingPlaceholderSecondaryActivity extends ActivityEmbeddingBaseActivity {
+ @Override
+ int getBackgroundColor() {
+ return Color.GREEN;
+ }
+}
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java
index 6cda482dd30a..19fafb7d2e95 100644
--- a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java
@@ -87,4 +87,17 @@ public class ActivityOptions {
public static final ComponentName NOTIFICATION_ACTIVITY_COMPONENT_NAME =
new ComponentName(FLICKER_APP_PACKAGE,
FLICKER_APP_PACKAGE + ".NotificationActivity");
+
+ public static final String ACTIVITY_EMBEDDING_LAUNCHER_NAME = "ActivityEmbeddingMainActivity";
+ public static final ComponentName ACTIVITY_EMBEDDING_MAIN_ACTIVITY_COMPONENT_NAME =
+ new ComponentName(FLICKER_APP_PACKAGE,
+ FLICKER_APP_PACKAGE + ".ActivityEmbeddingMainActivity");
+ public static final ComponentName
+ ACTIVITY_EMBEDDING_PLACEHOLDER_PRIMARY_ACTIVITY_COMPONENT_NAME = new ComponentName(
+ FLICKER_APP_PACKAGE,
+ FLICKER_APP_PACKAGE + ".ActivityEmbeddingPlaceholderPrimaryActivity");
+ public static final ComponentName
+ ACTIVITY_EMBEDDING_PLACEHOLDER_SECONDARY_ACTIVITY_COMPONENT_NAME = new ComponentName(
+ FLICKER_APP_PACKAGE,
+ FLICKER_APP_PACKAGE + ".ActivityEmbeddingPlaceholderSecondaryActivity");
}
diff --git a/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java b/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java
index ab83997c67fc..0375f66069c3 100644
--- a/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java
+++ b/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java
@@ -66,6 +66,7 @@ import java.util.function.Consumer;
@RunWith(JUnit4.class)
public class StagedInstallInternalTest {
private static final String APK_IN_APEX_TESTAPEX_NAME = "com.android.apex.apkrollback.test";
+ private static final String REBOOTLESS_APEX_PACKAGE_NAME = "test.apex.rebootless";
private static final TestApp TEST_APEX_WITH_APK_V2 = new TestApp("TestApexWithApkV2",
APK_IN_APEX_TESTAPEX_NAME, 2, /*isApex*/true, APK_IN_APEX_TESTAPEX_NAME + "_v2.apex");
private static final TestApp APEX_WRONG_SHA_V2 = new TestApp(
@@ -594,6 +595,28 @@ public class StagedInstallInternalTest {
assertThat(InstallUtils.getInstalledVersion(packageName)).isEqualTo(1);
}
+ @Test
+ public void testVendorApex_VerifyFactory() throws Exception {
+ final PackageManager pm =
+ InstrumentationRegistry.getInstrumentation().getContext().getPackageManager();
+ PackageInfo pi = pm.getPackageInfo(REBOOTLESS_APEX_PACKAGE_NAME, PackageManager.MATCH_APEX);
+ assertThat(pi.getLongVersionCode()).isEqualTo(1);
+ assertThat(pi.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_VENDOR)
+ .isEqualTo(ApplicationInfo.PRIVATE_FLAG_VENDOR);
+ assertThat(pi.applicationInfo.sourceDir).startsWith("/vendor/apex");
+ }
+
+ @Test
+ public void testVendorApex_VerifyData() throws Exception {
+ final PackageManager pm =
+ InstrumentationRegistry.getInstrumentation().getContext().getPackageManager();
+ PackageInfo pi = pm.getPackageInfo(REBOOTLESS_APEX_PACKAGE_NAME, PackageManager.MATCH_APEX);
+ assertThat(pi.getLongVersionCode()).isEqualTo(2);
+ assertThat(pi.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_VENDOR)
+ .isEqualTo(ApplicationInfo.PRIVATE_FLAG_VENDOR);
+ assertThat(pi.applicationInfo.sourceDir).startsWith("/data/apex");
+ }
+
private IPackageManagerNative getPackageManagerNative() {
IBinder binder = ServiceManager.waitForService("package_native");
assertThat(binder).isNotNull();
diff --git a/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java b/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java
index 7e0a55ff3f3e..7b17778730eb 100644
--- a/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java
+++ b/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java
@@ -63,6 +63,8 @@ public class StagedInstallInternalTest extends BaseHostJUnit4Test {
private static final String APK_IN_APEX_TESTAPEX_NAME = "com.android.apex.apkrollback.test";
private static final String APEXD_TEST_APEX = "apex.apexd_test.apex";
private static final String FAKE_APEX_SYSTEM_SERVER_APEX = "test_com.android.server.apex";
+ private static final String REBOOTLESS_V1 = "test.rebootless_apex_v1.apex";
+ private static final String REBOOTLESS_V2 = "test.rebootless_apex_v2.apex";
private static final String TEST_VENDOR_APEX_ALLOW_LIST =
"/vendor/etc/sysconfig/test-vendor-apex-allow-list.xml";
@@ -94,6 +96,7 @@ public class StagedInstallInternalTest extends BaseHostJUnit4Test {
"/data/apex/active/" + APK_IN_APEX_TESTAPEX_NAME + "*.apex",
"/data/apex/active/" + SHIM_APEX_PACKAGE_NAME + "*.apex",
"/system/apex/test.rebootless_apex_v*.apex",
+ "/vendor/apex/test.rebootless_apex_v*.apex",
"/data/apex/active/test.apex.rebootless*.apex",
"/system/app/TestApp/TestAppAv1.apk",
TEST_VENDOR_APEX_ALLOW_LIST);
@@ -137,13 +140,17 @@ public class StagedInstallInternalTest extends BaseHostJUnit4Test {
}
private void pushTestApex(String fileName) throws Exception {
+ pushTestApex(fileName, "system");
+ }
+
+ private void pushTestApex(String fileName, String partition) throws Exception {
CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(getBuild());
final File apex = buildHelper.getTestFile(fileName);
if (!getDevice().isAdbRoot()) {
getDevice().enableAdbRoot();
}
getDevice().remountSystemWritable();
- assertTrue(getDevice().pushFile(apex, "/system/apex/" + fileName));
+ assertTrue(getDevice().pushFile(apex, "/" + partition + "/apex/" + fileName));
}
private void pushTestVendorApexAllowList(String installerPackageName) throws Exception {
@@ -497,6 +504,33 @@ public class StagedInstallInternalTest extends BaseHostJUnit4Test {
runPhase("testVendorApexCorrectInstaller_nonStaged");
}
+ /**
+ * Tests correctness of {@link android.content.pm.ApplicationInfo} for APEXes on /vendor.
+ */
+ @Test
+ @LargeTest
+ public void testVendorApex_Staged() throws Exception {
+ pushTestApex(REBOOTLESS_V1, "vendor");
+ getDevice().reboot();
+ runPhase("testVendorApex_VerifyFactory");
+ installPackage(REBOOTLESS_V2, "--staged");
+ getDevice().reboot();
+ runPhase("testVendorApex_VerifyData");
+ }
+
+ /**
+ * Tests correctness of {@link android.content.pm.ApplicationInfo} for APEXes on /vendor.
+ */
+ @Test
+ @LargeTest
+ public void testVendorApex_NonStaged() throws Exception {
+ pushTestApex(REBOOTLESS_V1, "vendor");
+ getDevice().reboot();
+ runPhase("testVendorApex_VerifyFactory");
+ installPackage(REBOOTLESS_V2, "--force-non-staged");
+ runPhase("testVendorApex_VerifyData");
+ }
+
@Test
public void testRebootlessUpdates() throws Exception {
pushTestApex("test.rebootless_apex_v1.apex");
diff --git a/tests/UsbManagerTests/lib/src/com/android/server/usblib/UsbManagerTestLib.java b/tests/UsbManagerTests/lib/src/com/android/server/usblib/UsbManagerTestLib.java
index 782439f80fc8..d133f6fbdd87 100644
--- a/tests/UsbManagerTests/lib/src/com/android/server/usblib/UsbManagerTestLib.java
+++ b/tests/UsbManagerTests/lib/src/com/android/server/usblib/UsbManagerTestLib.java
@@ -117,6 +117,7 @@ public class UsbManagerTestLib {
testGetCurrentFunctionsMock_Matched(UsbManager.FUNCTION_PTP);
testGetCurrentFunctionsMock_Matched(UsbManager.FUNCTION_MIDI);
testGetCurrentFunctionsMock_Matched(UsbManager.FUNCTION_RNDIS);
+ testGetCurrentFunctionsMock_Matched(UsbManager.FUNCTION_NCM);
}
public void testSetCurrentFunctions_shouldMatched() {
@@ -125,5 +126,6 @@ public class UsbManagerTestLib {
testSetCurrentFunctionsMock_Matched(UsbManager.FUNCTION_PTP);
testSetCurrentFunctionsMock_Matched(UsbManager.FUNCTION_MIDI);
testSetCurrentFunctionsMock_Matched(UsbManager.FUNCTION_RNDIS);
+ testSetCurrentFunctionsMock_Matched(UsbManager.FUNCTION_NCM);
}
}
diff --git a/tests/UsbTests/src/com/android/server/usb/UsbHandlerTest.java b/tests/UsbTests/src/com/android/server/usb/UsbHandlerTest.java
index 861d221238ff..86bcb7290d95 100644
--- a/tests/UsbTests/src/com/android/server/usb/UsbHandlerTest.java
+++ b/tests/UsbTests/src/com/android/server/usb/UsbHandlerTest.java
@@ -182,6 +182,14 @@ public class UsbHandlerTest {
@SmallTest
@Test
+ public void setFunctionsNcm() {
+ mUsbHandler.handleMessage(mUsbHandler.obtainMessage(MSG_SET_CURRENT_FUNCTIONS,
+ UsbManager.FUNCTION_NCM));
+ assertNotEquals(mUsbHandler.getEnabledFunctions() & UsbManager.FUNCTION_NCM, 0);
+ }
+
+ @SmallTest
+ @Test
public void setFunctionsNcmAndRndis() {
final long rndisPlusNcm = UsbManager.FUNCTION_RNDIS | UsbManager.FUNCTION_NCM;