summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/api/current.txt20
-rw-r--r--core/api/module-lib-current.txt5
-rw-r--r--core/api/system-current.txt130
-rw-r--r--core/api/test-current.txt3
-rw-r--r--core/java/android/accessibilityservice/AccessibilityService.java31
-rw-r--r--core/java/android/app/ApplicationPackageManager.java12
-rw-r--r--core/java/android/app/GameManager.java8
-rw-r--r--core/java/android/app/IGameManagerService.aidl2
-rw-r--r--core/java/android/app/SystemServiceRegistry.java16
-rw-r--r--core/java/android/app/admin/DevicePolicyManager.java24
-rw-r--r--core/java/android/app/admin/IDevicePolicyManager.aidl1
-rw-r--r--core/java/android/app/wallpapereffectsgeneration/CameraAttributes.java301
-rw-r--r--core/java/android/app/wallpapereffectsgeneration/CinematicEffectRequest.aidl (renamed from packages/ConnectivityT/framework-t/src/android/net/NetworkStateSnapshot.aidl)6
-rw-r--r--core/java/android/app/wallpapereffectsgeneration/CinematicEffectRequest.java115
-rw-r--r--core/java/android/app/wallpapereffectsgeneration/CinematicEffectResponse.aidl19
-rw-r--r--core/java/android/app/wallpapereffectsgeneration/CinematicEffectResponse.java299
-rw-r--r--core/java/android/app/wallpapereffectsgeneration/ICinematicEffectListener.aidl30
-rw-r--r--core/java/android/app/wallpapereffectsgeneration/IWallpaperEffectsGenerationManager.aidl34
-rw-r--r--core/java/android/app/wallpapereffectsgeneration/TexturedMesh.java273
-rw-r--r--core/java/android/app/wallpapereffectsgeneration/WallpaperEffectsGenerationManager.java114
-rw-r--r--core/java/android/attention/AttentionManagerInternal.java28
-rw-r--r--core/java/android/content/Context.java14
-rw-r--r--core/java/android/content/pm/IPackageManager.aidl1
-rw-r--r--core/java/android/content/pm/PackageManager.java14
-rw-r--r--core/java/android/hardware/hdmi/HdmiClient.java20
-rw-r--r--core/java/android/hardware/hdmi/HdmiControlManager.java34
-rw-r--r--core/java/android/hardware/hdmi/HdmiControlServiceWrapper.java6
-rw-r--r--core/java/android/hardware/hdmi/IHdmiControlService.aidl2
-rw-r--r--core/java/android/hardware/input/IInputManager.aidl2
-rw-r--r--core/java/android/hardware/input/InputManager.java3
-rw-r--r--core/java/android/os/GraphicsEnvironment.java2
-rw-r--r--core/java/android/os/Parcel.java407
-rw-r--r--core/java/android/os/Vibrator.java25
-rw-r--r--core/java/android/provider/Settings.java13
-rw-r--r--core/java/android/service/attention/AttentionService.java60
-rw-r--r--core/java/android/service/attention/IAttentionService.aidl3
-rw-r--r--core/java/android/service/attention/IProximityCallback.aidl10
-rw-r--r--core/java/android/service/games/GameSession.java44
-rw-r--r--core/java/android/service/games/IGameSession.aidl1
-rw-r--r--core/java/android/service/trust/ITrustAgentServiceCallback.aidl1
-rw-r--r--core/java/android/service/trust/TrustAgentService.java27
-rw-r--r--core/java/android/service/wallpapereffectsgeneration/IWallpaperEffectsGenerationService.aidl28
-rw-r--r--core/java/android/service/wallpapereffectsgeneration/WallpaperEffectsGenerationService.java142
-rw-r--r--core/java/android/view/InputMonitor.java20
-rw-r--r--core/java/com/android/internal/policy/TransitionAnimation.java25
-rw-r--r--core/res/AndroidManifest.xml21
-rw-r--r--core/res/res/anim/activity_close_enter.xml37
-rw-r--r--core/res/res/anim/activity_close_enter_legacy.xml34
-rw-r--r--core/res/res/anim/activity_close_exit.xml37
-rw-r--r--core/res/res/anim/activity_close_exit_legacy.xml44
-rw-r--r--core/res/res/anim/activity_open_enter.xml29
-rw-r--r--core/res/res/anim/activity_open_enter_legacy.xml42
-rw-r--r--core/res/res/anim/activity_open_exit.xml37
-rw-r--r--core/res/res/anim/activity_open_exit_legacy.xml45
-rw-r--r--core/res/res/values/attrs.xml16
-rw-r--r--core/res/res/values/config.xml15
-rw-r--r--core/res/res/values/public.xml5
-rw-r--r--core/res/res/values/strings.xml12
-rw-r--r--core/res/res/values/symbols.xml19
-rw-r--r--core/tests/hdmitests/src/android/hardware/hdmi/HdmiAudioSystemClientTest.java5
-rw-r--r--data/etc/com.android.settings.xml1
-rw-r--r--data/etc/privapp-permissions-platform.xml1
-rw-r--r--identity/java/android/security/identity/IdentityCredential.java6
-rw-r--r--identity/java/android/security/identity/WritableIdentityCredential.java3
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java4
-rw-r--r--media/java/android/media/BtProfileConnectionInfo.java1
-rw-r--r--packages/ConnectivityT/framework-t/src/android/net/InternalNetworkManagementException.java24
-rw-r--r--packages/SettingsLib/res/values/arrays.xml5
-rw-r--r--packages/SettingsLib/res/values/strings.xml4
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/users/AvatarPickerActivity.java27
-rw-r--r--packages/Shell/AndroidManifest.xml3
-rw-r--r--packages/SystemUI/AndroidManifest.xml7
-rw-r--r--packages/SystemUI/TEST_MAPPING6
-rw-r--r--packages/SystemUI/res/drawable/action_chip_background.xml4
-rw-r--r--packages/SystemUI/res/drawable/action_chip_container_background.xml2
-rw-r--r--packages/SystemUI/res/drawable/auth_dialog_enterprise.xml2
-rw-r--r--packages/SystemUI/res/drawable/overlay_actions_background_protection.xml (renamed from packages/SystemUI/res/drawable/screenshot_actions_background_protection.xml)2
-rw-r--r--packages/SystemUI/res/drawable/overlay_button_background.xml (renamed from packages/SystemUI/res/drawable/screenshot_button_background.xml)0
-rw-r--r--packages/SystemUI/res/layout/auth_credential_password_view.xml108
-rw-r--r--packages/SystemUI/res/layout/auth_credential_pattern_view.xml125
-rw-r--r--packages/SystemUI/res/layout/clipboard_overlay.xml14
-rw-r--r--packages/SystemUI/res/layout/long_screenshot.xml5
-rw-r--r--packages/SystemUI/res/layout/overlay_action_chip.xml (renamed from packages/SystemUI/res/layout/screenshot_action_chip.xml)26
-rw-r--r--packages/SystemUI/res/layout/screenshot.xml6
-rw-r--r--packages/SystemUI/res/layout/screenshot_static.xml16
-rw-r--r--packages/SystemUI/res/values-night/colors.xml6
-rw-r--r--packages/SystemUI/res/values-night/styles.xml4
-rw-r--r--packages/SystemUI/res/values/attrs.xml2
-rw-r--r--packages/SystemUI/res/values/colors.xml6
-rw-r--r--packages/SystemUI/res/values/dimens.xml46
-rw-r--r--packages/SystemUI/res/values/styles.xml53
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/animation/UnfoldMoveFromCenterAnimator.kt35
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/media/INearbyMediaDevicesProvider.aidl43
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/media/INearbyMediaDevicesService.aidl33
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/media/INearbyMediaDevicesUpdateCallback.aidl41
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/media/NearbyDevice.aidl19
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/media/NearbyDevice.kt (renamed from packages/SystemUI/src/com/android/systemui/media/nearby/NearbyDevice.kt)13
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/media/RangeZone.kt (renamed from packages/SystemUI/src/com/android/systemui/media/nearby/RangeZone.kt)27
-rw-r--r--packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java159
-rw-r--r--packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java44
-rw-r--r--packages/SystemUI/src/com/android/systemui/clipboardoverlay/DraggableConstraintLayout.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/KeyguardMediaController.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/dagger/MediaModule.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/nearby/MediaNearbyDevicesManager.kt51
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/nearby/NearbyMediaDevicesService.kt81
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/OverlayActionChip.java (renamed from packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotActionChip.java)23
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java77
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/SwipeDismissHandler.java21
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/StatusBarState.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateEvent.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java19
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt48
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java19
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarMoveFromCenterAnimationController.kt20
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java17
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/KeyguardMediaControllerTest.kt1
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/nearby/NearbyMediaDevicesServiceTest.kt124
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt12
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateEventTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java17
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java15
-rw-r--r--services/Android.bp2
-rw-r--r--services/accessibility/java/com/android/server/accessibility/SystemActionPerformer.java15
-rw-r--r--services/core/Android.bp1
-rw-r--r--services/core/java/com/android/server/app/GameManagerService.java104
-rw-r--r--services/core/java/com/android/server/app/GameServiceProviderInstanceImpl.java49
-rw-r--r--services/core/java/com/android/server/attention/AttentionManagerService.java257
-rw-r--r--services/core/java/com/android/server/clipboard/ClipboardService.java4
-rw-r--r--services/core/java/com/android/server/display/AutomaticBrightnessController.java27
-rw-r--r--services/core/java/com/android/server/display/DisplayPowerController.java47
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiCecConfig.java14
-rwxr-xr-xservices/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java15
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java7
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiCecStandbyModeHandler.java1
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiControlService.java27
-rw-r--r--services/core/java/com/android/server/input/GestureMonitorSpyWindow.java95
-rw-r--r--services/core/java/com/android/server/input/InputManagerService.java150
-rw-r--r--services/core/java/com/android/server/locales/LocaleManagerBackupHelper.java10
-rw-r--r--services/core/java/com/android/server/location/gnss/GnssNmeaProvider.java19
-rw-r--r--services/core/java/com/android/server/location/gnss/GnssStatusProvider.java21
-rw-r--r--services/core/java/com/android/server/location/gnss/hal/GnssNative.java57
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java30
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerServiceTestParams.java1
-rw-r--r--services/core/java/com/android/server/trust/TrustAgentWrapper.java49
-rw-r--r--services/core/java/com/android/server/trust/TrustManagerService.java114
-rw-r--r--services/core/java/com/android/server/wm/InputManagerCallback.java20
-rw-r--r--services/core/java/com/android/server/wm/InsetsPolicy.java46
-rw-r--r--services/core/java/com/android/server/wm/RootWindowContainer.java23
-rw-r--r--services/core/java/com/android/server/wm/TaskSystemBarsListenerController.java63
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerInternal.java33
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java49
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java13
-rw-r--r--services/core/jni/com_android_server_location_GnssLocationProvider.cpp92
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyData.java25
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java21
-rw-r--r--services/java/com/android/server/SystemServer.java11
-rw-r--r--services/tests/mockingservicestests/Android.bp1
-rw-r--r--services/tests/mockingservicestests/res/xml/gama_manager_service_metadata_config_disabled.xml9
-rw-r--r--services/tests/mockingservicestests/res/xml/gama_manager_service_metadata_config_enabled.xml9
-rw-r--r--services/tests/mockingservicestests/src/android/service/games/GameSessionTest.java36
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java87
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/app/GameServiceProviderInstanceImplTest.java92
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt18
-rw-r--r--services/tests/servicestests/src/com/android/server/attention/AttentionManagerServiceTest.java135
-rw-r--r--services/tests/servicestests/src/com/android/server/display/AutomaticBrightnessControllerTest.java49
-rw-r--r--services/tests/servicestests/src/com/android/server/hdmi/FakeHdmiCecConfig.java11
-rw-r--r--services/tests/servicestests/src/com/android/server/hdmi/HdmiCecConfigTest.java3
-rw-r--r--services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java109
-rw-r--r--services/wallpapereffectsgeneration/Android.bp22
-rw-r--r--services/wallpapereffectsgeneration/java/com/android/server/wallpapereffectsgeneration/RemoteWallpaperEffectsGenerationService.java113
-rw-r--r--services/wallpapereffectsgeneration/java/com/android/server/wallpapereffectsgeneration/WallpaperEffectsGenerationManagerService.java185
-rw-r--r--services/wallpapereffectsgeneration/java/com/android/server/wallpapereffectsgeneration/WallpaperEffectsGenerationManagerServiceShellCommand.java85
-rw-r--r--services/wallpapereffectsgeneration/java/com/android/server/wallpapereffectsgeneration/WallpaperEffectsGenerationPerUserService.java274
-rw-r--r--telephony/java/android/telephony/CarrierConfigManager.java28
179 files changed, 6319 insertions, 785 deletions
diff --git a/core/api/current.txt b/core/api/current.txt
index c29f3ae9052c..74594d07a8b8 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -326,6 +326,9 @@ package android {
field public static final int allowClearUserData = 16842757; // 0x1010005
field public static final int allowClickWhenDisabled = 16844312; // 0x1010618
field public static final int allowEmbedded = 16843765; // 0x10103f5
+ field public static final int allowGameAngleDriver;
+ field public static final int allowGameDownscaling;
+ field public static final int allowGameFpsOverride;
field public static final int allowNativeHeapPointerTagging = 16844306; // 0x1010612
field public static final int allowParallelSyncs = 16843570; // 0x1010332
field public static final int allowSingleTap = 16843353; // 0x1010259
@@ -1435,10 +1438,12 @@ package android {
field public static final int summaryOn = 16843247; // 0x10101ef
field public static final int supportedTypes;
field public static final int supportsAssist = 16844016; // 0x10104f0
+ field public static final int supportsBatteryGameMode;
field public static final int supportsInlineSuggestions = 16844301; // 0x101060d
field public static final int supportsLaunchVoiceAssistFromKeyguard = 16844017; // 0x10104f1
field public static final int supportsLocalInteraction = 16844047; // 0x101050f
field public static final int supportsMultipleDisplays = 16844182; // 0x1010596
+ field public static final int supportsPerformanceGameMode;
field public static final int supportsPictureInPicture = 16844023; // 0x10104f7
field public static final int supportsRtl = 16843695; // 0x10103af
field public static final int supportsStylusHandwriting;
@@ -3130,6 +3135,11 @@ package android.accessibilityservice {
field public static final int GLOBAL_ACTION_ACCESSIBILITY_SHORTCUT = 13; // 0xd
field public static final int GLOBAL_ACTION_BACK = 1; // 0x1
field public static final int GLOBAL_ACTION_DISMISS_NOTIFICATION_SHADE = 15; // 0xf
+ field public static final int GLOBAL_ACTION_DPAD_CENTER = 20; // 0x14
+ field public static final int GLOBAL_ACTION_DPAD_DOWN = 17; // 0x11
+ field public static final int GLOBAL_ACTION_DPAD_LEFT = 18; // 0x12
+ field public static final int GLOBAL_ACTION_DPAD_RIGHT = 19; // 0x13
+ field public static final int GLOBAL_ACTION_DPAD_UP = 16; // 0x10
field public static final int GLOBAL_ACTION_HOME = 2; // 0x2
field public static final int GLOBAL_ACTION_KEYCODE_HEADSETHOOK = 10; // 0xa
field public static final int GLOBAL_ACTION_LOCK_SCREEN = 8; // 0x8
@@ -31425,6 +31435,9 @@ package android.os {
method @Nullable public byte[] createByteArray();
method @Nullable public char[] createCharArray();
method @Nullable public double[] createDoubleArray();
+ method @Nullable public <T> T createFixedArray(@NonNull Class<T>, @NonNull int...);
+ method @Nullable public <T, S extends android.os.IInterface> T createFixedArray(@NonNull Class<T>, @NonNull java.util.function.Function<android.os.IBinder,S>, @NonNull int...);
+ method @Nullable public <T, S extends android.os.Parcelable> T createFixedArray(@NonNull Class<T>, @NonNull android.os.Parcelable.Creator<S>, @NonNull int...);
method @Nullable public float[] createFloatArray();
method @Nullable public int[] createIntArray();
method @Nullable public <T extends android.os.IInterface> T[] createInterfaceArray(@NonNull java.util.function.IntFunction<T[]>, @NonNull java.util.function.Function<android.os.IBinder,T>);
@@ -31466,6 +31479,9 @@ package android.os {
method public void readException();
method public void readException(int, String);
method public android.os.ParcelFileDescriptor readFileDescriptor();
+ method public <T> void readFixedArray(@NonNull T);
+ method public <T, S extends android.os.IInterface> void readFixedArray(@NonNull T, @NonNull java.util.function.Function<android.os.IBinder,S>);
+ method public <T, S extends android.os.Parcelable> void readFixedArray(@NonNull T, @NonNull android.os.Parcelable.Creator<S>);
method public float readFloat();
method public void readFloatArray(@NonNull float[]);
method @Deprecated @Nullable public java.util.HashMap readHashMap(@Nullable ClassLoader);
@@ -31526,6 +31542,7 @@ package android.os {
method public void writeDoubleArray(@Nullable double[]);
method public void writeException(@NonNull Exception);
method public void writeFileDescriptor(@NonNull java.io.FileDescriptor);
+ method public <T> void writeFixedArray(@Nullable T, int, @NonNull int...);
method public void writeFloat(float);
method public void writeFloatArray(@Nullable float[]);
method public void writeInt(int);
@@ -41221,6 +41238,7 @@ package android.telephony {
field public static final String KEY_IMS_CONFERENCE_SIZE_LIMIT_INT = "ims_conference_size_limit_int";
field public static final String KEY_IMS_DTMF_TONE_DELAY_INT = "ims_dtmf_tone_delay_int";
field public static final String KEY_IS_IMS_CONFERENCE_SIZE_ENFORCED_BOOL = "is_ims_conference_size_enforced_bool";
+ field public static final String KEY_IS_OPPORTUNISTIC_SUBSCRIPTION_BOOL = "is_opportunistic_subscription_bool";
field public static final String KEY_LTE_ENABLED_BOOL = "lte_enabled_bool";
field public static final String KEY_LTE_RSRQ_THRESHOLDS_INT_ARRAY = "lte_rsrq_thresholds_int_array";
field public static final String KEY_LTE_RSSNR_THRESHOLDS_INT_ARRAY = "lte_rssnr_thresholds_int_array";
@@ -41305,6 +41323,7 @@ package android.telephony {
field public static final String KEY_SIM_NETWORK_UNLOCK_ALLOW_DISMISS_BOOL = "sim_network_unlock_allow_dismiss_bool";
field public static final String KEY_SMDP_SERVER_ADDRESS_STRING = "smdp_server_address_string";
field public static final String KEY_SMS_REQUIRES_DESTINATION_NUMBER_CONVERSION_BOOL = "sms_requires_destination_number_conversion_bool";
+ field public static final String KEY_SUBSCRIPTION_GROUP_UUID_STRING = "subscription_group_uuid_string";
field public static final String KEY_SUPPORTS_CALL_COMPOSER_BOOL = "supports_call_composer_bool";
field public static final String KEY_SUPPORTS_DEVICE_TO_DEVICE_COMMUNICATION_USING_DTMF_BOOL = "supports_device_to_device_communication_using_dtmf_bool";
field public static final String KEY_SUPPORTS_DEVICE_TO_DEVICE_COMMUNICATION_USING_RTP_BOOL = "supports_device_to_device_communication_using_rtp_bool";
@@ -41348,6 +41367,7 @@ package android.telephony {
field public static final String KEY_WFC_EMERGENCY_ADDRESS_CARRIER_APP_STRING = "wfc_emergency_address_carrier_app_string";
field public static final String KEY_WORLD_MODE_ENABLED_BOOL = "world_mode_enabled_bool";
field public static final String KEY_WORLD_PHONE_BOOL = "world_phone_bool";
+ field public static final String REMOVE_GROUP_UUID_STRING = "00000000-0000-0000-0000-000000000000";
field public static final int SERVICE_CLASS_NONE = 0; // 0x0
field public static final int SERVICE_CLASS_VOICE = 1; // 0x1
field public static final int USSD_OVER_CS_ONLY = 2; // 0x2
diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt
index 6cde547e6571..6e7bc765c157 100644
--- a/core/api/module-lib-current.txt
+++ b/core/api/module-lib-current.txt
@@ -78,9 +78,9 @@ package android.app {
package android.app.admin {
public class DevicePolicyManager {
- method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public void acknowledgeNewUserDisclaimer();
+ method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}) public void acknowledgeNewUserDisclaimer();
method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}) public android.os.UserHandle getLogoutUser();
- method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public int logoutUser();
+ method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}) public int logoutUser();
field public static final String ACTION_SHOW_NEW_USER_DISCLAIMER = "android.app.action.SHOW_NEW_USER_DISCLAIMER";
}
@@ -141,6 +141,7 @@ package android.content.pm {
public abstract class PackageManager {
method @NonNull public String getPermissionControllerPackageName();
+ method @NonNull public String getSupplementalProcessPackageName();
}
}
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 49a1d629c718..fd716f341540 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -76,6 +76,7 @@ package android {
field public static final String BIND_TRANSLATION_SERVICE = "android.permission.BIND_TRANSLATION_SERVICE";
field public static final String BIND_TRUST_AGENT = "android.permission.BIND_TRUST_AGENT";
field public static final String BIND_TV_REMOTE_SERVICE = "android.permission.BIND_TV_REMOTE_SERVICE";
+ field public static final String BIND_WALLPAPER_EFFECTS_GENERATION_SERVICE = "android.permission.BIND_WALLPAPER_EFFECTS_GENERATION_SERVICE";
field public static final String BLUETOOTH_MAP = "android.permission.BLUETOOTH_MAP";
field public static final String BRICK = "android.permission.BRICK";
field public static final String BRIGHTNESS_SLIDER_USAGE = "android.permission.BRIGHTNESS_SLIDER_USAGE";
@@ -191,6 +192,7 @@ package android {
field public static final String MANAGE_USB = "android.permission.MANAGE_USB";
field public static final String MANAGE_USERS = "android.permission.MANAGE_USERS";
field public static final String MANAGE_USER_OEM_UNLOCK_STATE = "android.permission.MANAGE_USER_OEM_UNLOCK_STATE";
+ field public static final String MANAGE_WALLPAPER_EFFECTS_GENERATION = "android.permission.MANAGE_WALLPAPER_EFFECTS_GENERATION";
field public static final String MANAGE_WEAK_ESCROW_TOKEN = "android.permission.MANAGE_WEAK_ESCROW_TOKEN";
field public static final String MANAGE_WIFI_AUTO_JOIN = "android.permission.MANAGE_WIFI_AUTO_JOIN";
field public static final String MANAGE_WIFI_COUNTRY_CODE = "android.permission.MANAGE_WIFI_COUNTRY_CODE";
@@ -2554,6 +2556,107 @@ package android.app.usage {
}
+package android.app.wallpapereffectsgeneration {
+
+ public final class CameraAttributes implements android.os.Parcelable {
+ method public int describeContents();
+ method @NonNull public float[] getAnchorPointInOutputUvSpace();
+ method @NonNull public float[] getAnchorPointInWorldSpace();
+ method public float getCameraOrbitPitchDegrees();
+ method public float getCameraOrbitYawDegrees();
+ method public float getDollyDistanceInWorldSpace();
+ method public float getFrustumFarInWorldSpace();
+ method public float getFrustumNearInWorldSpace();
+ method public float getVerticalFovDegrees();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.app.wallpapereffectsgeneration.CameraAttributes> CREATOR;
+ }
+
+ public static final class CameraAttributes.Builder {
+ ctor public CameraAttributes.Builder(@NonNull float[], @NonNull float[]);
+ method @NonNull public android.app.wallpapereffectsgeneration.CameraAttributes build();
+ method @NonNull public android.app.wallpapereffectsgeneration.CameraAttributes.Builder setCameraOrbitPitchDegrees(@FloatRange(from=-90.0F, to=90.0f) float);
+ method @NonNull public android.app.wallpapereffectsgeneration.CameraAttributes.Builder setCameraOrbitYawDegrees(@FloatRange(from=-180.0F, to=180.0f) float);
+ method @NonNull public android.app.wallpapereffectsgeneration.CameraAttributes.Builder setDollyDistanceInWorldSpace(float);
+ method @NonNull public android.app.wallpapereffectsgeneration.CameraAttributes.Builder setFrustumFarInWorldSpace(@FloatRange(from=0.0f) float);
+ method @NonNull public android.app.wallpapereffectsgeneration.CameraAttributes.Builder setFrustumNearInWorldSpace(@FloatRange(from=0.0f) float);
+ method @NonNull public android.app.wallpapereffectsgeneration.CameraAttributes.Builder setVerticalFovDegrees(@FloatRange(from=0.0f, to=180.0f, fromInclusive=false) float);
+ }
+
+ public final class CinematicEffectRequest implements android.os.Parcelable {
+ ctor public CinematicEffectRequest(@NonNull String, @NonNull android.graphics.Bitmap);
+ method public int describeContents();
+ method @NonNull public android.graphics.Bitmap getBitmap();
+ method @NonNull public String getTaskId();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.app.wallpapereffectsgeneration.CinematicEffectRequest> CREATOR;
+ }
+
+ public final class CinematicEffectResponse implements android.os.Parcelable {
+ method public int describeContents();
+ method @Nullable public android.app.wallpapereffectsgeneration.CameraAttributes getEndKeyFrame();
+ method public int getImageContentType();
+ method @Nullable public android.app.wallpapereffectsgeneration.CameraAttributes getStartKeyFrame();
+ method public int getStatusCode();
+ method @NonNull public String getTaskId();
+ method @NonNull public java.util.List<android.app.wallpapereffectsgeneration.TexturedMesh> getTexturedMeshes();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field public static final int CINEMATIC_EFFECT_STATUS_ERROR = 2; // 0x2
+ field public static final int CINEMATIC_EFFECT_STATUS_NOT_READY = 3; // 0x3
+ field public static final int CINEMATIC_EFFECT_STATUS_OK = 1; // 0x1
+ field public static final int CINEMATIC_EFFECT_STATUS_PENDING = 4; // 0x4
+ field public static final int CINEMATIC_EFFECT_STATUS_TOO_MANY_REQUESTS = 5; // 0x5
+ field public static final int CINEMATIC_EFFECT_STATUS_UNKNOWN = 0; // 0x0
+ field @NonNull public static final android.os.Parcelable.Creator<android.app.wallpapereffectsgeneration.CinematicEffectResponse> CREATOR;
+ field public static final int IMAGE_CONTENT_TYPE_LANDSCAPE = 2; // 0x2
+ field public static final int IMAGE_CONTENT_TYPE_OTHER = 3; // 0x3
+ field public static final int IMAGE_CONTENT_TYPE_PEOPLE_PORTRAIT = 1; // 0x1
+ field public static final int IMAGE_CONTENT_TYPE_UNKNOWN = 0; // 0x0
+ }
+
+ public static final class CinematicEffectResponse.Builder {
+ ctor public CinematicEffectResponse.Builder(int, @NonNull String);
+ method @NonNull public android.app.wallpapereffectsgeneration.CinematicEffectResponse build();
+ method @NonNull public android.app.wallpapereffectsgeneration.CinematicEffectResponse.Builder setEndKeyFrame(@Nullable android.app.wallpapereffectsgeneration.CameraAttributes);
+ method @NonNull public android.app.wallpapereffectsgeneration.CinematicEffectResponse.Builder setImageContentType(int);
+ method @NonNull public android.app.wallpapereffectsgeneration.CinematicEffectResponse.Builder setStartKeyFrame(@Nullable android.app.wallpapereffectsgeneration.CameraAttributes);
+ method @NonNull public android.app.wallpapereffectsgeneration.CinematicEffectResponse.Builder setTexturedMeshes(@NonNull java.util.List<android.app.wallpapereffectsgeneration.TexturedMesh>);
+ }
+
+ public final class TexturedMesh implements android.os.Parcelable {
+ method public int describeContents();
+ method @NonNull public android.graphics.Bitmap getBitmap();
+ method @NonNull public int[] getIndices();
+ method @NonNull public int getIndicesLayoutType();
+ method @NonNull public float[] getVertices();
+ method @NonNull public int getVerticesLayoutType();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.app.wallpapereffectsgeneration.TexturedMesh> CREATOR;
+ field public static final int INDICES_LAYOUT_TRIANGLES = 1; // 0x1
+ field public static final int INDICES_LAYOUT_UNDEFINED = 0; // 0x0
+ field public static final int VERTICES_LAYOUT_POSITION3_UV2 = 1; // 0x1
+ field public static final int VERTICES_LAYOUT_UNDEFINED = 0; // 0x0
+ }
+
+ public static final class TexturedMesh.Builder {
+ ctor public TexturedMesh.Builder(@NonNull android.graphics.Bitmap);
+ method @NonNull public android.app.wallpapereffectsgeneration.TexturedMesh build();
+ method @NonNull public android.app.wallpapereffectsgeneration.TexturedMesh.Builder setIndices(@NonNull int[]);
+ method @NonNull public android.app.wallpapereffectsgeneration.TexturedMesh.Builder setIndicesLayoutType(int);
+ method @NonNull public android.app.wallpapereffectsgeneration.TexturedMesh.Builder setVertices(@NonNull float[]);
+ method @NonNull public android.app.wallpapereffectsgeneration.TexturedMesh.Builder setVerticesLayoutType(int);
+ }
+
+ public final class WallpaperEffectsGenerationManager {
+ method @RequiresPermission(android.Manifest.permission.MANAGE_WALLPAPER_EFFECTS_GENERATION) public void generateCinematicEffect(@NonNull android.app.wallpapereffectsgeneration.CinematicEffectRequest, @NonNull java.util.concurrent.Executor, @NonNull android.app.wallpapereffectsgeneration.WallpaperEffectsGenerationManager.CinematicEffectListener);
+ }
+
+ public static interface WallpaperEffectsGenerationManager.CinematicEffectListener {
+ method public void onCinematicEffectGenerated(@NonNull android.app.wallpapereffectsgeneration.CinematicEffectResponse);
+ }
+
+}
+
package android.apphibernation {
public class AppHibernationManager {
@@ -2742,6 +2845,7 @@ package android.content {
field public static final String UI_TRANSLATION_SERVICE = "ui_translation";
field public static final String UWB_SERVICE = "uwb";
field public static final String VR_SERVICE = "vrmanager";
+ field public static final String WALLPAPER_EFFECTS_GENERATION_SERVICE = "wallpaper_effects_generation";
field public static final String WIFI_NL80211_SERVICE = "wifinl80211";
field @Deprecated public static final String WIFI_RTT_SERVICE = "rttmanager";
field public static final String WIFI_SCANNING_SERVICE = "wifiscanner";
@@ -3713,6 +3817,7 @@ package android.hardware.hdmi {
method public void sendKeyEvent(int, boolean);
method public void sendVendorCommand(int, byte[], boolean);
method public void setVendorCommandListener(@NonNull android.hardware.hdmi.HdmiControlManager.VendorCommandListener);
+ method public void setVendorCommandListener(@NonNull android.hardware.hdmi.HdmiControlManager.VendorCommandListener, int);
}
public static interface HdmiClient.OnDeviceSelectedListener {
@@ -10294,6 +10399,8 @@ package android.provider {
}
public static final class Settings.Secure extends android.provider.Settings.NameValueTable {
+ method public static int getIntForUser(@NonNull android.content.ContentResolver, @NonNull String, int, int);
+ method @Nullable public static String getStringForUser(@NonNull android.content.ContentResolver, @NonNull String, int);
method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public static boolean putString(@NonNull android.content.ContentResolver, @NonNull String, @Nullable String, @Nullable String, boolean);
method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public static void resetToDefaults(@NonNull android.content.ContentResolver, @Nullable String);
field @Deprecated public static final String ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED = "accessibility_display_magnification_navbar_enabled";
@@ -10645,6 +10752,8 @@ package android.service.attention {
method @Nullable public final android.os.IBinder onBind(@NonNull android.content.Intent);
method public abstract void onCancelAttentionCheck(@NonNull android.service.attention.AttentionService.AttentionCallback);
method public abstract void onCheckAttention(@NonNull android.service.attention.AttentionService.AttentionCallback);
+ method public void onStartProximityUpdates(@NonNull android.service.attention.AttentionService.ProximityCallback);
+ method public void onStopProximityUpdates();
field public static final int ATTENTION_FAILURE_CAMERA_PERMISSION_ABSENT = 6; // 0x6
field public static final int ATTENTION_FAILURE_CANCELLED = 3; // 0x3
field public static final int ATTENTION_FAILURE_PREEMPTED = 4; // 0x4
@@ -10652,6 +10761,7 @@ package android.service.attention {
field public static final int ATTENTION_FAILURE_UNKNOWN = 2; // 0x2
field public static final int ATTENTION_SUCCESS_ABSENT = 0; // 0x0
field public static final int ATTENTION_SUCCESS_PRESENT = 1; // 0x1
+ field public static final double PROXIMITY_UNKNOWN = -1.0;
field public static final String SERVICE_INTERFACE = "android.service.attention.AttentionService";
}
@@ -10660,6 +10770,10 @@ package android.service.attention {
method public void onSuccess(int, long);
}
+ public static final class AttentionService.ProximityCallback {
+ method public void onProximityUpdate(double);
+ }
+
}
package android.service.autofill {
@@ -11083,6 +11197,7 @@ package android.service.games {
method public void onCreate();
method public void onDestroy();
method public void onGameTaskFocusChanged(boolean);
+ method public void onTransientSystemBarVisibilityFromRevealGestureChanged(boolean);
method @RequiresPermission(android.Manifest.permission.MANAGE_GAME_ACTIVITY) public final boolean restartGame();
method public void setTaskOverlayView(@NonNull android.view.View, @NonNull android.view.ViewGroup.LayoutParams);
method public void takeScreenshot(@NonNull java.util.concurrent.Executor, @NonNull android.service.games.GameSession.ScreenshotCallback);
@@ -11512,6 +11627,7 @@ package android.service.trust {
method @Deprecated public final void grantTrust(CharSequence, long, boolean);
method public final void grantTrust(CharSequence, long, int);
method public final void isEscrowTokenActive(long, android.os.UserHandle);
+ method public final void lockUser();
method public final android.os.IBinder onBind(android.content.Intent);
method public boolean onConfigure(java.util.List<android.os.PersistableBundle>);
method public void onDeviceLocked();
@@ -11522,13 +11638,16 @@ package android.service.trust {
method public void onEscrowTokenStateReceived(long, int);
method public void onTrustTimeout();
method public void onUnlockAttempt(boolean);
+ method public void onUserRequestedUnlock();
method public final void removeEscrowToken(long, android.os.UserHandle);
method public final void revokeTrust();
method public final void setManagingTrust(boolean);
method public final void showKeyguardErrorMessage(@NonNull CharSequence);
method public final void unlockUserWithToken(long, byte[], android.os.UserHandle);
field public static final int FLAG_GRANT_TRUST_DISMISS_KEYGUARD = 2; // 0x2
+ field public static final int FLAG_GRANT_TRUST_DISPLAY_MESSAGE = 8; // 0x8
field public static final int FLAG_GRANT_TRUST_INITIATED_BY_USER = 1; // 0x1
+ field public static final int FLAG_GRANT_TRUST_TEMPORARY_AND_RENEWABLE = 4; // 0x4
field public static final String SERVICE_INTERFACE = "android.service.trust.TrustAgentService";
field public static final int TOKEN_STATE_ACTIVE = 1; // 0x1
field public static final int TOKEN_STATE_INACTIVE = 0; // 0x0
@@ -11704,6 +11823,17 @@ package android.service.wallpaper {
}
+package android.service.wallpapereffectsgeneration {
+
+ public abstract class WallpaperEffectsGenerationService extends android.app.Service {
+ ctor public WallpaperEffectsGenerationService();
+ method @NonNull public final android.os.IBinder onBind(@NonNull android.content.Intent);
+ method public abstract void onGenerateCinematicEffect(@NonNull android.app.wallpapereffectsgeneration.CinematicEffectRequest);
+ method public final void returnCinematicEffectResponse(@NonNull android.app.wallpapereffectsgeneration.CinematicEffectResponse);
+ }
+
+}
+
package android.service.watchdog {
public abstract class ExplicitHealthCheckService extends android.app.Service {
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 52a180b3c9e0..e2a78c6414d2 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -278,6 +278,7 @@ package android.app {
}
public final class GameManager {
+ method @RequiresPermission(android.Manifest.permission.MANAGE_GAME_MODE) public boolean isAngleEnabled(@NonNull String);
method public void setGameServiceProvider(@Nullable String);
}
@@ -497,6 +498,7 @@ package android.app.admin {
method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_DEVICE_ADMINS) public java.util.Set<java.lang.String> getPolicyExemptApps();
method public boolean isCurrentInputMethodSetByOwner();
method public boolean isFactoryResetProtectionPolicySupported();
+ method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}) public boolean isNewUserDisclaimerAcknowledged();
method @RequiresPermission(anyOf={android.Manifest.permission.MARK_DEVICE_ORGANIZATION_OWNED, android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS}, conditional=true) public void markProfileOwnerOnOrganizationOwnedDevice(@NonNull android.content.ComponentName);
method @NonNull public static String operationSafetyReasonToString(int);
method @NonNull public static String operationToString(int);
@@ -800,6 +802,7 @@ package android.content.pm {
method @NonNull public String getPermissionControllerPackageName();
method @NonNull public abstract String getServicesSystemSharedLibraryPackageName();
method @NonNull public abstract String getSharedSystemSharedLibraryPackageName();
+ method @NonNull public String getSupplementalProcessPackageName();
method @Nullable public String getSystemTextClassifierPackageName();
method @Nullable public String getWellbeingPackageName();
method public void holdLock(android.os.IBinder, int);
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index 6b0aef84f14b..42d2d28ae928 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -571,6 +571,31 @@ public abstract class AccessibilityService extends Service {
*/
public static final int GLOBAL_ACTION_DISMISS_NOTIFICATION_SHADE = 15;
+ /**
+ * Action to trigger dpad up keyevent.
+ */
+ public static final int GLOBAL_ACTION_DPAD_UP = 16;
+
+ /**
+ * Action to trigger dpad down keyevent.
+ */
+ public static final int GLOBAL_ACTION_DPAD_DOWN = 17;
+
+ /**
+ * Action to trigger dpad left keyevent.
+ */
+ public static final int GLOBAL_ACTION_DPAD_LEFT = 18;
+
+ /**
+ * Action to trigger dpad right keyevent.
+ */
+ public static final int GLOBAL_ACTION_DPAD_RIGHT = 19;
+
+ /**
+ * Action to trigger dpad center keyevent.
+ */
+ public static final int GLOBAL_ACTION_DPAD_CENTER = 20;
+
private static final String LOG_TAG = "AccessibilityService";
/**
@@ -2328,10 +2353,16 @@ public abstract class AccessibilityService extends Service {
* @param action The action to perform.
* @return Whether the action was successfully performed.
*
+ * Perform actions using ids like the id constants referenced below:
* @see #GLOBAL_ACTION_BACK
* @see #GLOBAL_ACTION_HOME
* @see #GLOBAL_ACTION_NOTIFICATIONS
* @see #GLOBAL_ACTION_RECENTS
+ * @see #GLOBAL_ACTION_DPAD_UP
+ * @see #GLOBAL_ACTION_DPAD_DOWN
+ * @see #GLOBAL_ACTION_DPAD_LEFT
+ * @see #GLOBAL_ACTION_DPAD_RIGHT
+ * @see #GLOBAL_ACTION_DPAD_CENTER
*/
public final boolean performGlobalAction(int action) {
IAccessibilityServiceConnection connection =
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index b1956effb093..20ffa254a9bf 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -863,6 +863,18 @@ public class ApplicationPackageManager extends PackageManager {
}
}
+ /**
+ * @hide
+ */
+ @Override
+ public String getSupplementalProcessPackageName() {
+ try {
+ return mPM.getSupplementalProcessPackageName();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
@Override
public boolean addPermission(PermissionInfo info) {
return getPermissionManager().addPermission(info, false);
diff --git a/core/java/android/app/GameManager.java b/core/java/android/app/GameManager.java
index 289b3486b7fe..040399ecb83b 100644
--- a/core/java/android/app/GameManager.java
+++ b/core/java/android/app/GameManager.java
@@ -181,14 +181,18 @@ public final class GameManager {
/**
* Returns if ANGLE is enabled for a given package and user ID.
* <p>
+ * ANGLE (Almost Native Graphics Layer Engine) can translate OpenGL ES commands to Vulkan
+ * commands. Enabling ANGLE may improve the performance and/or reduce the power consumption of
+ * applications.
* The caller must have {@link android.Manifest.permission#MANAGE_GAME_MODE}.
*
* @hide
*/
+ @TestApi
@RequiresPermission(Manifest.permission.MANAGE_GAME_MODE)
- public @GameMode boolean getAngleEnabled(@NonNull String packageName) {
+ public @GameMode boolean isAngleEnabled(@NonNull String packageName) {
try {
- return mService.getAngleEnabled(packageName, mContext.getUserId());
+ return mService.isAngleEnabled(packageName, mContext.getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/app/IGameManagerService.aidl b/core/java/android/app/IGameManagerService.aidl
index 3ea0767661bb..7035ac078334 100644
--- a/core/java/android/app/IGameManagerService.aidl
+++ b/core/java/android/app/IGameManagerService.aidl
@@ -26,7 +26,7 @@ interface IGameManagerService {
int getGameMode(String packageName, int userId);
void setGameMode(String packageName, int gameMode, int userId);
int[] getAvailableGameModes(String packageName);
- boolean getAngleEnabled(String packageName, int userId);
+ boolean isAngleEnabled(String packageName, int userId);
void setGameState(String packageName, in GameState gameState, int userId);
GameModeInfo getGameModeInfo(String packageName, int userId);
void setGameServiceProvider(String packageName);
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index bbdd7050cb07..79180cbc57fd 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -51,6 +51,8 @@ import android.app.usage.IUsageStatsManager;
import android.app.usage.NetworkStatsManager;
import android.app.usage.StorageStatsManager;
import android.app.usage.UsageStatsManager;
+import android.app.wallpapereffectsgeneration.IWallpaperEffectsGenerationManager;
+import android.app.wallpapereffectsgeneration.WallpaperEffectsGenerationManager;
import android.apphibernation.AppHibernationManager;
import android.appwidget.AppWidgetManager;
import android.bluetooth.BluetoothFrameworkInitializer;
@@ -1297,6 +1299,20 @@ public final class SystemServiceRegistry {
}
});
+ registerService(Context.WALLPAPER_EFFECTS_GENERATION_SERVICE,
+ WallpaperEffectsGenerationManager.class,
+ new CachedServiceFetcher<WallpaperEffectsGenerationManager>() {
+ @Override
+ public WallpaperEffectsGenerationManager createService(ContextImpl ctx)
+ throws ServiceNotFoundException {
+ IBinder b = ServiceManager.getService(
+ Context.WALLPAPER_EFFECTS_GENERATION_SERVICE);
+ return b == null ? null :
+ new WallpaperEffectsGenerationManager(
+ IWallpaperEffectsGenerationManager.Stub.asInterface(b));
+ }
+ });
+
registerService(Context.VR_SERVICE, VrManager.class, new CachedServiceFetcher<VrManager>() {
@Override
public VrManager createService(ContextImpl ctx) throws ServiceNotFoundException {
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index a4227a4d3074..83265800c04f 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -3556,7 +3556,8 @@ public class DevicePolicyManager {
*
* @hide
*/
- @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
+ @RequiresPermission(anyOf = {android.Manifest.permission.MANAGE_USERS,
+ android.Manifest.permission.INTERACT_ACROSS_USERS})
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public void acknowledgeNewUserDisclaimer() {
if (mService != null) {
@@ -3569,6 +3570,25 @@ public class DevicePolicyManager {
}
/**
+ * Checks whether the new managed user disclaimer was viewed by the current user.
+ *
+ * @hide
+ */
+ @RequiresPermission(anyOf = {android.Manifest.permission.MANAGE_USERS,
+ android.Manifest.permission.INTERACT_ACROSS_USERS})
+ @TestApi
+ public boolean isNewUserDisclaimerAcknowledged() {
+ if (mService != null) {
+ try {
+ return mService.isNewUserDisclaimerAcknowledged();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ return false;
+ }
+
+ /**
* Return true if the given administrator component is currently active (enabled) in the system.
*
* @param admin The administrator component to check for.
@@ -10146,7 +10166,7 @@ public class DevicePolicyManager {
* @hide
*/
@RequiresPermission(anyOf = {android.Manifest.permission.MANAGE_USERS,
- android.Manifest.permission.CREATE_USERS})
+ android.Manifest.permission.INTERACT_ACROSS_USERS})
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public @UserOperationResult int logoutUser() {
// TODO(b/214336184): add CTS test
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 927ee0c20eaf..a7a51f8f6caa 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -272,6 +272,7 @@ interface IDevicePolicyManager {
int getLogoutUserId();
List<UserHandle> getSecondaryUsers(in ComponentName who);
void acknowledgeNewUserDisclaimer();
+ boolean isNewUserDisclaimerAcknowledged();
void enableSystemApp(in ComponentName admin, in String callerPackage, in String packageName);
int enableSystemAppWithIntent(in ComponentName admin, in String callerPackage, in Intent intent);
diff --git a/core/java/android/app/wallpapereffectsgeneration/CameraAttributes.java b/core/java/android/app/wallpapereffectsgeneration/CameraAttributes.java
new file mode 100644
index 000000000000..dfbc7a4c3276
--- /dev/null
+++ b/core/java/android/app/wallpapereffectsgeneration/CameraAttributes.java
@@ -0,0 +1,301 @@
+/*
+ * 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.app.wallpapereffectsgeneration;
+
+import android.annotation.FloatRange;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Representing the position and other parameters of camera of a single frame.
+ *
+ * @hide
+ */
+@SystemApi
+public final class CameraAttributes implements Parcelable {
+ /**
+ * The location of the anchor within the 3D scene.
+ * Expecting 3 floats representing the x, y, z coordinates
+ * of the anchor point.
+ */
+ @NonNull
+ private float[] mAnchorPointInWorldSpace;
+ /**
+ * Where the anchor point should project to in the output image.
+ * Expecting 2 floats representing the u,v coordinates of the
+ * anchor point.
+ */
+ @NonNull
+ private float[] mAnchorPointInOutputUvSpace;
+ /**
+ * Specifies the amount of yaw orbit rotation the camera should perform
+ * around the anchor point in world space.
+ */
+ private float mCameraOrbitYawDegrees;
+ /**
+ * Specifies the amount of pitch orbit rotation the camera should perform
+ * around the anchor point in world space.
+ */
+ private float mCameraOrbitPitchDegrees;
+ /**
+ * Specifies by how much the camera should be placed towards the anchor
+ * point in world space, which is also called dolly distance.
+ */
+ private float mDollyDistanceInWorldSpace;
+ /**
+ * Specifies the vertical fov degrees of the virtual image.
+ */
+ private float mVerticalFovDegrees;
+ /**
+ * The frustum of near plane.
+ */
+ private float mFrustumNearInWorldSpace;
+ /**
+ * The frustum of far plane.
+ */
+ private float mFrustumFarInWorldSpace;
+
+ private CameraAttributes(Parcel in) {
+ this.mCameraOrbitYawDegrees = in.readFloat();
+ this.mCameraOrbitPitchDegrees = in.readFloat();
+ this.mDollyDistanceInWorldSpace = in.readFloat();
+ this.mVerticalFovDegrees = in.readFloat();
+ this.mFrustumNearInWorldSpace = in.readFloat();
+ this.mFrustumFarInWorldSpace = in.readFloat();
+ this.mAnchorPointInWorldSpace = in.createFloatArray();
+ this.mAnchorPointInOutputUvSpace = in.createFloatArray();
+ }
+
+ private CameraAttributes(float[] anchorPointInWorldSpace, float[] anchorPointInOutputUvSpace,
+ float cameraOrbitYawDegrees, float cameraOrbitPitchDegrees,
+ float dollyDistanceInWorldSpace,
+ float verticalFovDegrees, float frustumNearInWorldSpace, float frustumFarInWorldSpace) {
+ mAnchorPointInWorldSpace = anchorPointInWorldSpace;
+ mAnchorPointInOutputUvSpace = anchorPointInOutputUvSpace;
+ mCameraOrbitYawDegrees = cameraOrbitYawDegrees;
+ mCameraOrbitPitchDegrees = cameraOrbitPitchDegrees;
+ mDollyDistanceInWorldSpace = dollyDistanceInWorldSpace;
+ mVerticalFovDegrees = verticalFovDegrees;
+ mFrustumNearInWorldSpace = frustumNearInWorldSpace;
+ mFrustumFarInWorldSpace = frustumFarInWorldSpace;
+ }
+
+ /**
+ * Get the location of the anchor within the 3D scene. The response float array contains
+ * 3 floats representing the x, y, z coordinates
+ */
+ @NonNull
+ public float[] getAnchorPointInWorldSpace() {
+ return mAnchorPointInWorldSpace;
+ }
+
+ /**
+ * Get where the anchor point should project to in the output image. The response float
+ * array contains 2 floats representing the u,v coordinates of the anchor point.
+ */
+ @NonNull
+ public float[] getAnchorPointInOutputUvSpace() {
+ return mAnchorPointInOutputUvSpace;
+ }
+
+ /**
+ * Get the camera yaw orbit rotation.
+ */
+ public float getCameraOrbitYawDegrees() {
+ return mCameraOrbitYawDegrees;
+ }
+
+ /**
+ * Get the camera pitch orbit rotation.
+ */
+ public float getCameraOrbitPitchDegrees() {
+ return mCameraOrbitPitchDegrees;
+ }
+
+ /**
+ * Get how many units the camera should be placed towards the anchor point in world space.
+ */
+ public float getDollyDistanceInWorldSpace() {
+ return mDollyDistanceInWorldSpace;
+ }
+
+ /**
+ * Get the camera vertical fov degrees.
+ */
+ public float getVerticalFovDegrees() {
+ return mVerticalFovDegrees;
+ }
+
+ /**
+ * Get the frustum in near plane.
+ */
+ public float getFrustumNearInWorldSpace() {
+ return mFrustumNearInWorldSpace;
+ }
+
+ /**
+ * Get the frustum in far plane.
+ */
+ public float getFrustumFarInWorldSpace() {
+ return mFrustumFarInWorldSpace;
+ }
+
+ @NonNull
+ public static final Creator<CameraAttributes> CREATOR = new Creator<CameraAttributes>() {
+ @Override
+ public CameraAttributes createFromParcel(Parcel in) {
+ return new CameraAttributes(in);
+ }
+
+ @Override
+ public CameraAttributes[] newArray(int size) {
+ return new CameraAttributes[size];
+ }
+ };
+
+ @Override
+ public void writeToParcel(@NonNull Parcel out, int flags) {
+ out.writeFloat(mCameraOrbitYawDegrees);
+ out.writeFloat(mCameraOrbitPitchDegrees);
+ out.writeFloat(mDollyDistanceInWorldSpace);
+ out.writeFloat(mVerticalFovDegrees);
+ out.writeFloat(mFrustumNearInWorldSpace);
+ out.writeFloat(mFrustumFarInWorldSpace);
+ out.writeFloatArray(mAnchorPointInWorldSpace);
+ out.writeFloatArray(mAnchorPointInOutputUvSpace);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ /**
+ * Builder for {@link CameraAttributes}.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final class Builder {
+ @NonNull
+ private float[] mAnchorPointInWorldSpace;
+ @NonNull
+ private float[] mAnchorPointInOutputUvSpace;
+ private float mCameraOrbitYawDegrees;
+ private float mCameraOrbitPitchDegrees;
+ private float mDollyDistanceInWorldSpace;
+ private float mVerticalFovDegrees;
+ private float mFrustumNearInWorldSpace;
+ private float mFrustumFarInWorldSpace;
+
+ /**
+ * Constructor with anchor point in world space and anchor point in output image
+ * space.
+ *
+ * @param anchorPointInWorldSpace the location of the anchor within the 3D scene. The
+ * float array contains 3 floats representing the x, y, z coordinates.
+ * @param anchorPointInOutputUvSpace where the anchor point should project to in the
+ * output image. The float array contains 2 floats representing the u,v coordinates
+ * of the anchor point.
+ *
+ * @hide
+ */
+ @SystemApi
+ public Builder(@NonNull float[] anchorPointInWorldSpace,
+ @NonNull float[] anchorPointInOutputUvSpace) {
+ mAnchorPointInWorldSpace = anchorPointInWorldSpace;
+ mAnchorPointInOutputUvSpace = anchorPointInOutputUvSpace;
+ }
+
+ /**
+ * Sets the camera orbit yaw rotation.
+ */
+ @NonNull
+ public Builder setCameraOrbitYawDegrees(
+ @FloatRange(from = -180.0f, to = 180.0f) float cameraOrbitYawDegrees) {
+ mCameraOrbitYawDegrees = cameraOrbitYawDegrees;
+ return this;
+ }
+
+ /**
+ * Sets the camera orbit pitch rotation.
+ */
+ @NonNull
+ public Builder setCameraOrbitPitchDegrees(
+ @FloatRange(from = -90.0f, to = 90.0f) float cameraOrbitPitchDegrees) {
+ mCameraOrbitPitchDegrees = cameraOrbitPitchDegrees;
+ return this;
+ }
+
+ /**
+ * Sets the camera dolly distance.
+ */
+ @NonNull
+ public Builder setDollyDistanceInWorldSpace(float dollyDistanceInWorldSpace) {
+ mDollyDistanceInWorldSpace = dollyDistanceInWorldSpace;
+ return this;
+ }
+
+ /**
+ * Sets the camera vertical fov degree.
+ */
+ @NonNull
+ public Builder setVerticalFovDegrees(
+ @FloatRange(from = 0.0f, to = 180.0f, fromInclusive = false)
+ float verticalFovDegrees) {
+ mVerticalFovDegrees = verticalFovDegrees;
+ return this;
+ }
+
+ /**
+ * Sets the frustum in near plane.
+ */
+ @NonNull
+ public Builder setFrustumNearInWorldSpace(
+ @FloatRange(from = 0.0f) float frustumNearInWorldSpace) {
+ mFrustumNearInWorldSpace = frustumNearInWorldSpace;
+ return this;
+ }
+
+ /**
+ * Sets the frustum in far plane.
+ */
+ @NonNull
+ public Builder setFrustumFarInWorldSpace(
+ @FloatRange(from = 0.0f) float frustumFarInWorldSpace) {
+ mFrustumFarInWorldSpace = frustumFarInWorldSpace;
+ return this;
+ }
+
+ /**
+ * Builds a new {@link CameraAttributes} instance.
+ */
+ @NonNull
+ public CameraAttributes build() {
+ return new CameraAttributes(mAnchorPointInWorldSpace,
+ mAnchorPointInOutputUvSpace,
+ mCameraOrbitYawDegrees,
+ mCameraOrbitPitchDegrees,
+ mDollyDistanceInWorldSpace,
+ mVerticalFovDegrees,
+ mFrustumNearInWorldSpace,
+ mFrustumFarInWorldSpace);
+ }
+ }
+}
diff --git a/packages/ConnectivityT/framework-t/src/android/net/NetworkStateSnapshot.aidl b/core/java/android/app/wallpapereffectsgeneration/CinematicEffectRequest.aidl
index cb602d7927ce..234774645956 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/NetworkStateSnapshot.aidl
+++ b/core/java/android/app/wallpapereffectsgeneration/CinematicEffectRequest.aidl
@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2021, 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.
@@ -14,6 +14,6 @@
* limitations under the License.
*/
-package android.net;
+package android.app.wallpapereffectsgeneration;
-parcelable NetworkStateSnapshot;
+parcelable CinematicEffectRequest; \ No newline at end of file
diff --git a/core/java/android/app/wallpapereffectsgeneration/CinematicEffectRequest.java b/core/java/android/app/wallpapereffectsgeneration/CinematicEffectRequest.java
new file mode 100644
index 000000000000..f2e33131baa2
--- /dev/null
+++ b/core/java/android/app/wallpapereffectsgeneration/CinematicEffectRequest.java
@@ -0,0 +1,115 @@
+/*
+ * 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.app.wallpapereffectsgeneration;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.graphics.Bitmap;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Objects;
+
+/**
+ * A {@link CinematicEffectRequest} is the data class having all the information
+ * passed to wallpaper effects generation service.
+ *
+ * @hide
+ */
+@SystemApi
+public final class CinematicEffectRequest implements Parcelable {
+ /**
+ * Unique id of a cienmatic effect generation task.
+ */
+ @NonNull
+ private String mTaskId;
+
+ /**
+ * The bitmap to generate cinematic effect from.
+ */
+ @NonNull
+ private Bitmap mBitmap;
+
+ private CinematicEffectRequest(Parcel in) {
+ this.mTaskId = in.readString();
+ this.mBitmap = Bitmap.CREATOR.createFromParcel(in);
+ }
+
+ /**
+ * Constructor with task id and bitmap.
+ */
+ public CinematicEffectRequest(@NonNull String taskId, @NonNull Bitmap bitmap) {
+ mTaskId = taskId;
+ mBitmap = bitmap;
+ }
+
+ /**
+ * Returns the task id.
+ */
+ @NonNull
+ public String getTaskId() {
+ return mTaskId;
+ }
+
+ /**
+ * Returns the bitmap of this request.
+ */
+ @NonNull
+ public Bitmap getBitmap() {
+ return mBitmap;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ CinematicEffectRequest that = (CinematicEffectRequest) o;
+ return mTaskId.equals(that.mTaskId);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mTaskId);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel out, int flags) {
+ out.writeString(mTaskId);
+ mBitmap.writeToParcel(out, flags);
+ }
+
+ @NonNull
+ public static final Creator<CinematicEffectRequest> CREATOR =
+ new Creator<CinematicEffectRequest>() {
+ @Override
+ public CinematicEffectRequest createFromParcel(Parcel in) {
+ return new CinematicEffectRequest(in);
+ }
+
+ @Override
+ public CinematicEffectRequest[] newArray(int size) {
+ return new CinematicEffectRequest[size];
+ }
+ };
+}
diff --git a/core/java/android/app/wallpapereffectsgeneration/CinematicEffectResponse.aidl b/core/java/android/app/wallpapereffectsgeneration/CinematicEffectResponse.aidl
new file mode 100644
index 000000000000..1bd1e1e4bada
--- /dev/null
+++ b/core/java/android/app/wallpapereffectsgeneration/CinematicEffectResponse.aidl
@@ -0,0 +1,19 @@
+/**
+ * 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.app.wallpapereffectsgeneration;
+
+ parcelable CinematicEffectResponse; \ No newline at end of file
diff --git a/core/java/android/app/wallpapereffectsgeneration/CinematicEffectResponse.java b/core/java/android/app/wallpapereffectsgeneration/CinematicEffectResponse.java
new file mode 100644
index 000000000000..1254794964dd
--- /dev/null
+++ b/core/java/android/app/wallpapereffectsgeneration/CinematicEffectResponse.java
@@ -0,0 +1,299 @@
+/*
+ * 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.app.wallpapereffectsgeneration;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * A {@link CinematicEffectResponse} include textured meshes
+ * and camera attributes of key frames.
+ *
+ * @hide
+ */
+@SystemApi
+public final class CinematicEffectResponse implements Parcelable {
+ /** @hide */
+ @IntDef(prefix = {"CINEMATIC_EFFECT_STATUS_"},
+ value = {CINEMATIC_EFFECT_STATUS_UNKNOWN,
+ CINEMATIC_EFFECT_STATUS_OK,
+ CINEMATIC_EFFECT_STATUS_ERROR,
+ CINEMATIC_EFFECT_STATUS_NOT_READY,
+ CINEMATIC_EFFECT_STATUS_PENDING,
+ CINEMATIC_EFFECT_STATUS_TOO_MANY_REQUESTS})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface CinematicEffectStatusCode {}
+
+ /** Cinematic effect generation unknown status. */
+ public static final int CINEMATIC_EFFECT_STATUS_UNKNOWN = 0;
+ /** Cinematic effect generation success. */
+ public static final int CINEMATIC_EFFECT_STATUS_OK = 1;
+ /** Cinematic effect generation failure. */
+ public static final int CINEMATIC_EFFECT_STATUS_ERROR = 2;
+ /** Service not ready for cinematic effect generation. */
+ public static final int CINEMATIC_EFFECT_STATUS_NOT_READY = 3;
+ /** Cienmatic effect generation process is pending. */
+ public static final int CINEMATIC_EFFECT_STATUS_PENDING = 4;
+ /** Too manay requests for server to handle. */
+ public static final int CINEMATIC_EFFECT_STATUS_TOO_MANY_REQUESTS = 5;
+
+ /** @hide */
+ @IntDef(prefix = {"IMAGE_CONTENT_TYPE_"},
+ value = {IMAGE_CONTENT_TYPE_UNKNOWN,
+ IMAGE_CONTENT_TYPE_PEOPLE_PORTRAIT,
+ IMAGE_CONTENT_TYPE_LANDSCAPE,
+ IMAGE_CONTENT_TYPE_OTHER
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ImageContentType {}
+
+ /** Image content unknown. */
+ public static final int IMAGE_CONTENT_TYPE_UNKNOWN = 0;
+ /** Image content is people portrait. */
+ public static final int IMAGE_CONTENT_TYPE_PEOPLE_PORTRAIT = 1;
+ /** Image content is landscape. */
+ public static final int IMAGE_CONTENT_TYPE_LANDSCAPE = 2;
+ /** Image content is doesn't belong to other types. */
+ public static final int IMAGE_CONTENT_TYPE_OTHER = 3;
+
+
+ @CinematicEffectStatusCode
+ private int mStatusCode;
+
+ /** The id of the cinematic effect generation task. */
+ @NonNull
+ private String mTaskId;
+
+ @ImageContentType
+ private int mImageContentType;
+
+ /** The textured mesh required to render cinematic effect. */
+ @NonNull
+ private List<TexturedMesh> mTexturedMeshes;
+
+ /** The start camera position for animation. */
+ @Nullable
+ private CameraAttributes mStartKeyFrame;
+
+ /** The end camera position for animation. */
+ @Nullable
+ private CameraAttributes mEndKeyFrame;
+
+ private CinematicEffectResponse(Parcel in) {
+ mStatusCode = in.readInt();
+ mTaskId = in.readString();
+ mImageContentType = in.readInt();
+ mTexturedMeshes = new ArrayList<TexturedMesh>();
+ in.readTypedList(mTexturedMeshes, TexturedMesh.CREATOR);
+ mStartKeyFrame = in.readTypedObject(CameraAttributes.CREATOR);
+ mEndKeyFrame = in.readTypedObject(CameraAttributes.CREATOR);
+ }
+
+ private CinematicEffectResponse(@CinematicEffectStatusCode int statusCode,
+ String taskId,
+ @ImageContentType int imageContentType,
+ List<TexturedMesh> texturedMeshes,
+ CameraAttributes startKeyFrame,
+ CameraAttributes endKeyFrame) {
+ mStatusCode = statusCode;
+ mTaskId = taskId;
+ mImageContentType = imageContentType;
+ mStartKeyFrame = startKeyFrame;
+ mEndKeyFrame = endKeyFrame;
+ mTexturedMeshes = texturedMeshes;
+ }
+
+ /** Gets the cinematic effect generation status code. */
+ @CinematicEffectStatusCode
+ public int getStatusCode() {
+ return mStatusCode;
+ }
+
+ /** Get the task id. */
+ @NonNull
+ public String getTaskId() {
+ return mTaskId;
+ }
+
+ /**
+ * Get the image content type, which briefly classifies what's
+ * the content of image, like people portrait, landscape etc.
+ */
+ @ImageContentType
+ public int getImageContentType() {
+ return mImageContentType;
+ }
+
+ /** Get the textured meshes. */
+ @NonNull
+ public List<TexturedMesh> getTexturedMeshes() {
+ return mTexturedMeshes;
+ }
+
+ /**
+ * Get the camera attributes (position info and other parameters, see docs of
+ * {@link CameraAttributes}) of the start key frame on the animation path.
+ */
+ @Nullable
+ public CameraAttributes getStartKeyFrame() {
+ return mStartKeyFrame;
+ }
+
+ /**
+ * Get the camera attributes (position info and other parameters, see docs of
+ * {@link CameraAttributes}) of the end key frame on the animation path.
+ */
+ @Nullable
+ public CameraAttributes getEndKeyFrame() {
+ return mEndKeyFrame;
+ }
+
+ @NonNull
+ public static final Creator<CinematicEffectResponse> CREATOR =
+ new Creator<CinematicEffectResponse>() {
+ @Override
+ public CinematicEffectResponse createFromParcel(Parcel in) {
+ return new CinematicEffectResponse(in);
+ }
+
+ @Override
+ public CinematicEffectResponse[] newArray(int size) {
+ return new CinematicEffectResponse[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel out, int flags) {
+ out.writeInt(mStatusCode);
+ out.writeString(mTaskId);
+ out.writeInt(mImageContentType);
+ out.writeTypedList(mTexturedMeshes, flags);
+ out.writeTypedObject(mStartKeyFrame, flags);
+ out.writeTypedObject(mEndKeyFrame, flags);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ CinematicEffectResponse that = (CinematicEffectResponse) o;
+ return mTaskId.equals(that.mTaskId);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mTaskId);
+ }
+ /**
+ * Builder of {@link CinematicEffectResponse}
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final class Builder {
+ @CinematicEffectStatusCode
+ private int mStatusCode;
+ @NonNull
+ private String mTaskId;
+ @ImageContentType
+ private int mImageContentType;
+ @NonNull
+ private List<TexturedMesh> mTexturedMeshes;
+ @Nullable
+ private CameraAttributes mStartKeyFrame;
+ @Nullable
+ private CameraAttributes mEndKeyFrame;
+
+ /**
+ * Constructor with task id and status code.
+ *
+ * @hide
+ */
+ @SystemApi
+ public Builder(@CinematicEffectStatusCode int statusCode, @NonNull String taskId) {
+ mStatusCode = statusCode;
+ mTaskId = taskId;
+ }
+
+ /**
+ * Sets the image content type.
+ */
+ @NonNull
+ public Builder setImageContentType(@ImageContentType int imageContentType) {
+ mImageContentType = imageContentType;
+ return this;
+ }
+
+
+ /**
+ * Sets the textured meshes.
+ */
+ @NonNull
+ public Builder setTexturedMeshes(@NonNull List<TexturedMesh> texturedMeshes) {
+ mTexturedMeshes = texturedMeshes;
+ return this;
+ }
+
+ /**
+ * Sets start key frame.
+ */
+ @NonNull
+ public Builder setStartKeyFrame(@Nullable CameraAttributes startKeyFrame) {
+ mStartKeyFrame = startKeyFrame;
+ return this;
+ }
+
+ /**
+ * Sets end key frame.
+ */
+ @NonNull
+ public Builder setEndKeyFrame(@Nullable CameraAttributes endKeyFrame) {
+ mEndKeyFrame = endKeyFrame;
+ return this;
+ }
+
+ /**
+ * Builds a {@link CinematicEffectResponse} instance.
+ */
+ @NonNull
+ public CinematicEffectResponse build() {
+ if (mTexturedMeshes == null) {
+ // Place holder because build doesn't allow list to be nullable.
+ mTexturedMeshes = new ArrayList<>(0);
+ }
+ return new CinematicEffectResponse(mStatusCode, mTaskId, mImageContentType,
+ mTexturedMeshes, mStartKeyFrame, mEndKeyFrame);
+ }
+ }
+}
diff --git a/core/java/android/app/wallpapereffectsgeneration/ICinematicEffectListener.aidl b/core/java/android/app/wallpapereffectsgeneration/ICinematicEffectListener.aidl
new file mode 100644
index 000000000000..c1a698d6be0e
--- /dev/null
+++ b/core/java/android/app/wallpapereffectsgeneration/ICinematicEffectListener.aidl
@@ -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 android.app.wallpapereffectsgeneration;
+
+import android.app.wallpapereffectsgeneration.CinematicEffectResponse;
+
+
+/**
+ * Callback used by system server to notify invoker of {@link WallpaperEffectsGenerationMAnager}
+ * of the cinematic effect generation result.
+ *
+ * @hide
+ */
+oneway interface ICinematicEffectListener {
+ void onCinematicEffectGenerated(in CinematicEffectResponse response);
+} \ No newline at end of file
diff --git a/core/java/android/app/wallpapereffectsgeneration/IWallpaperEffectsGenerationManager.aidl b/core/java/android/app/wallpapereffectsgeneration/IWallpaperEffectsGenerationManager.aidl
new file mode 100644
index 000000000000..706a89c043b9
--- /dev/null
+++ b/core/java/android/app/wallpapereffectsgeneration/IWallpaperEffectsGenerationManager.aidl
@@ -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 android.app.wallpapereffectsgeneration;
+
+import android.app.wallpapereffectsgeneration.CinematicEffectRequest;
+import android.app.wallpapereffectsgeneration.CinematicEffectResponse;
+import android.app.wallpapereffectsgeneration.ICinematicEffectListener;
+
+/**
+ * Used by {@link android.app.wallpapereffectsgeneration.WallpaperEffectsGenerationManager}
+ * to to generate effects.
+ *
+ * @hide
+ */
+oneway interface IWallpaperEffectsGenerationManager {
+ void generateCinematicEffect(in CinematicEffectRequest request,
+ in ICinematicEffectListener listener);
+
+ void returnCinematicEffectResponse(in CinematicEffectResponse response);
+} \ No newline at end of file
diff --git a/core/java/android/app/wallpapereffectsgeneration/TexturedMesh.java b/core/java/android/app/wallpapereffectsgeneration/TexturedMesh.java
new file mode 100644
index 000000000000..630de45e3506
--- /dev/null
+++ b/core/java/android/app/wallpapereffectsgeneration/TexturedMesh.java
@@ -0,0 +1,273 @@
+/*
+ * 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.app.wallpapereffectsgeneration;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.graphics.Bitmap;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * The textured mesh representation, including a texture (bitmap) to sample from when rendering,
+ * and a mesh consisting of primitives such as triangles. The mesh is represented by an indices
+ * array describing the set of primitives in the mesh, and a vertices array that the indices
+ * refer to.
+ *
+ * @hide
+ */
+@SystemApi
+public final class TexturedMesh implements Parcelable {
+ /**
+ * The texture to sample from when rendering mesh.
+ */
+ @NonNull
+ private Bitmap mBitmap;
+
+ /**
+ * The set of primitives as pointers into the vertices.
+ */
+ @NonNull
+ private int[] mIndices;
+
+ /**
+ * The specific vertices that the indices refer to.
+ */
+ @NonNull
+ private float[] mVertices;
+
+ /** @hide */
+ @IntDef(prefix = {"INDICES_LAYOUT_"}, value = {
+ INDICES_LAYOUT_UNDEFINED,
+ INDICES_LAYOUT_TRIANGLES})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface IndicesLayoutType {
+ }
+
+ /** Undefined indices layout */
+ public static final int INDICES_LAYOUT_UNDEFINED = 0;
+ /**
+ * Indices layout is triangle. Vertices are grouped into 3 and each
+ * group forms a triangle.
+ */
+ public static final int INDICES_LAYOUT_TRIANGLES = 1;
+
+ @IndicesLayoutType
+ private int mIndicesLayoutType;
+
+ /** @hide */
+ @IntDef(prefix = {"VERTICES_LAYOUT_"}, value = {
+ VERTICES_LAYOUT_UNDEFINED,
+ VERTICES_LAYOUT_POSITION3_UV2})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface VerticesLayoutType {
+ }
+
+ /**
+ * Undefined vertices layout.
+ */
+ public static final int VERTICES_LAYOUT_UNDEFINED = 0;
+ /**
+ * The vertices array uses 5 numbers to represent a point, in the format
+ * of [x1, y1, z1, u1, v1, x2, y2, z2, u2, v2, ...].
+ */
+ public static final int VERTICES_LAYOUT_POSITION3_UV2 = 1;
+
+ @VerticesLayoutType
+ private int mVerticesLayoutType;
+
+ private TexturedMesh(Parcel in) {
+ this.mIndicesLayoutType = in.readInt();
+ this.mVerticesLayoutType = in.readInt();
+ this.mBitmap = in.readTypedObject(Bitmap.CREATOR);
+ Parcel data = Parcel.obtain();
+ try {
+ byte[] bytes = in.readBlob();
+ data.unmarshall(bytes, 0, bytes.length);
+ data.setDataPosition(0);
+ this.mIndices = data.createIntArray();
+ this.mVertices = data.createFloatArray();
+ } finally {
+ data.recycle();
+ }
+ }
+
+ private TexturedMesh(@NonNull Bitmap bitmap, @NonNull int[] indices,
+ @NonNull float[] vertices, @IndicesLayoutType int indicesLayoutType,
+ @VerticesLayoutType int verticesLayoutType) {
+ mBitmap = bitmap;
+ mIndices = indices;
+ mVertices = vertices;
+ mIndicesLayoutType = indicesLayoutType;
+ mVerticesLayoutType = verticesLayoutType;
+ }
+
+ /** Get the bitmap, which is the texture to sample from when rendering. */
+ @NonNull
+ public Bitmap getBitmap() {
+ return mBitmap;
+ }
+
+ /**
+ * Get the indices as pointers to the vertices array. Depending on the getIndicesLayoutType(),
+ * the primitives may have different shapes. For example, with INDICES_LAYOUT_TRIANGLES,
+ * indices 0, 1, 2 forms a triangle, indices 3, 4, 5 form another triangle.
+ */
+ @NonNull
+ public int[] getIndices() {
+ return mIndices;
+ }
+
+ /**
+ * Get the vertices that the index array refers to. Depending on the getVerticesLayoutType()
+ * result, the vertices array can represent different per-vertex coordinates. For example,
+ * with VERTICES_LAYOUT_POSITION3_UV2 type, vertices are in the format of
+ * [x1, y1, z1, u1, v1, x2, y2, z2, u2, v2, ...].
+ */
+ @NonNull
+ public float[] getVertices() {
+ return mVertices;
+ }
+
+ /** Get the indices layout type. */
+ @IndicesLayoutType
+ @NonNull
+ public int getIndicesLayoutType() {
+ return mIndicesLayoutType;
+ }
+
+ /** Get the indices layout type. */
+ @VerticesLayoutType
+ @NonNull
+ public int getVerticesLayoutType() {
+ return mVerticesLayoutType;
+ }
+
+ @NonNull
+ public static final Creator<TexturedMesh> CREATOR = new Creator<TexturedMesh>() {
+ @Override
+ public TexturedMesh createFromParcel(Parcel in) {
+ return new TexturedMesh(in);
+ }
+
+ @Override
+ public TexturedMesh[] newArray(int size) {
+ return new TexturedMesh[size];
+ }
+ };
+
+ @Override
+ public void writeToParcel(@NonNull Parcel out, int flags) {
+ out.writeInt(mIndicesLayoutType);
+ out.writeInt(mVerticesLayoutType);
+ out.writeTypedObject(mBitmap, flags);
+
+ // Indices and vertices can reach 5MB. Write the data as a Blob,
+ // which will be written to ashmem if too large.
+ Parcel data = Parcel.obtain();
+ try {
+ data.writeIntArray(mIndices);
+ data.writeFloatArray(mVertices);
+ out.writeBlob(data.marshall());
+ } finally {
+ data.recycle();
+ }
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ /**
+ * A builder for {@link TexturedMesh}
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final class Builder {
+ private Bitmap mBitmap;
+ private int[] mIndices;
+ private float[] mVertices;
+ @IndicesLayoutType
+ private int mIndicesLayoutType;
+ @VerticesLayoutType
+ private int mVerticesLayouttype;
+
+ /**
+ * Constructor with bitmap.
+ *
+ * @hide
+ */
+ @SystemApi
+ public Builder(@NonNull Bitmap bitmap) {
+ mBitmap = bitmap;
+ }
+
+ /**
+ * Set the required indices. The indices should represent the primitives. For example,
+ * with INDICES_LAYOUT_TRIANGLES, indices 0, 1, 2 forms a triangle, indices 3, 4, 5
+ * form another triangle.
+ */
+ @NonNull
+ public Builder setIndices(@NonNull int[] indices) {
+ mIndices = indices;
+ return this;
+ }
+
+ /**
+ * Set the required vertices. The vertices array should represent per-vertex coordinates.
+ * For example, with VERTICES_LAYOUT_POSITION3_UV2 type, vertices are in the format of
+ * [x1, y1, z1, u1, v1, x2, y2, z2, u2, v2, ...].
+ *
+ */
+ @NonNull
+ public Builder setVertices(@NonNull float[] vertices) {
+ mVertices = vertices;
+ return this;
+ }
+
+ /**
+ * Set the required indices layout type.
+ */
+ @NonNull
+ public Builder setIndicesLayoutType(@IndicesLayoutType int indicesLayoutType) {
+ mIndicesLayoutType = indicesLayoutType;
+ return this;
+ }
+
+ /**
+ * Set the required vertices layout type.
+ */
+ @NonNull
+ public Builder setVerticesLayoutType(@VerticesLayoutType int verticesLayoutype) {
+ mVerticesLayouttype = verticesLayoutype;
+ return this;
+ }
+
+ /** Builds a TexturedMesh based on the given parameters. */
+ @NonNull
+ public TexturedMesh build() {
+ return new TexturedMesh(mBitmap, mIndices, mVertices, mIndicesLayoutType,
+ mVerticesLayouttype);
+ }
+ }
+}
diff --git a/core/java/android/app/wallpapereffectsgeneration/WallpaperEffectsGenerationManager.java b/core/java/android/app/wallpapereffectsgeneration/WallpaperEffectsGenerationManager.java
new file mode 100644
index 000000000000..5a1d27daa20b
--- /dev/null
+++ b/core/java/android/app/wallpapereffectsgeneration/WallpaperEffectsGenerationManager.java
@@ -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 android.app.wallpapereffectsgeneration;
+
+import android.annotation.CallbackExecutor;
+import android.annotation.NonNull;
+import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
+import android.annotation.SystemService;
+import android.content.Context;
+import android.os.RemoteException;
+
+import java.util.concurrent.Executor;
+
+/**
+ * A {@link WallpaperEffectsGenerationManager} is the class that passes wallpaper effects
+ * generation requests to wallpaper effect generation service. For example, create a cinematic
+ * and render a cinematic live wallpaper with the response.
+ *
+ * Usage:
+ * <pre>{@code
+ * mWallpaperEffectsGenerationManager =
+ * context.getSystemService(WallpaperEffectsGenerationManager.class);
+ * mWallpaperEffectsGenerationManager.
+ * generateCinematicEffect(cinematicEffectRequest, response->{
+ * // proceed cinematic effect response.
+ * });
+ * }</pre>
+ *
+ * @hide
+ */
+@SystemApi
+@SystemService(Context.WALLPAPER_EFFECTS_GENERATION_SERVICE)
+public final class WallpaperEffectsGenerationManager {
+ /**
+ * Interface for the cinematic effect listener.
+ */
+ public interface CinematicEffectListener {
+ /**
+ * Async call when the cinematic effect response is generated.
+ * Client needs to check the status code of {@link CinematicEffectResponse}
+ * to determine if the effect generation is successful.
+ *
+ * @param response The generated cinematic effect response.
+ */
+ void onCinematicEffectGenerated(@NonNull CinematicEffectResponse response);
+ }
+
+ private final IWallpaperEffectsGenerationManager mService;
+
+ /** @hide */
+ public WallpaperEffectsGenerationManager(
+ @NonNull IWallpaperEffectsGenerationManager service) {
+ mService = service;
+ }
+
+ /**
+ * Execute a {@link android.app.wallpapereffectsgeneration.CinematicEffectRequest} from
+ * the given parameters to the wallpaper effects generation service. After the cinematic
+ * effect response is ready, the given listener is invoked by the system with the response.
+ * The listener may never receive a callback if unexpected error happened when proceeding
+ * request.
+ *
+ * @param request request to generate cinematic effect.
+ * @param executor where the listener is invoked.
+ * @param listener listener invoked when the cinematic effect response is available.
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.MANAGE_WALLPAPER_EFFECTS_GENERATION)
+ public void generateCinematicEffect(@NonNull CinematicEffectRequest request,
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull CinematicEffectListener listener) {
+ try {
+ mService.generateCinematicEffect(request,
+ new CinematicEffectListenerWrapper(listener, executor));
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ private static final class CinematicEffectListenerWrapper
+ extends ICinematicEffectListener.Stub {
+ @NonNull
+ private final CinematicEffectListener mListener;
+ @NonNull
+ private final Executor mExecutor;
+
+ CinematicEffectListenerWrapper(@NonNull CinematicEffectListener listener,
+ @NonNull Executor executor) {
+ mListener = listener;
+ mExecutor = executor;
+ }
+
+ @Override
+ public void onCinematicEffectGenerated(CinematicEffectResponse response) {
+ mExecutor.execute(() -> mListener.onCinematicEffectGenerated(response));
+ }
+ }
+}
diff --git a/core/java/android/attention/AttentionManagerInternal.java b/core/java/android/attention/AttentionManagerInternal.java
index 941e9e2ecce5..4e00da1b8c10 100644
--- a/core/java/android/attention/AttentionManagerInternal.java
+++ b/core/java/android/attention/AttentionManagerInternal.java
@@ -46,6 +46,25 @@ public abstract class AttentionManagerInternal {
*/
public abstract void cancelAttentionCheck(AttentionCallbackInternal callback);
+ /**
+ * Requests the continuous updates of proximity signal via the provided callback,
+ * until the given callback is unregistered. Currently, AttentionManagerService only
+ * anticipates one client and updates one client at a time. If a new client wants to
+ * onboard to receiving Proximity updates, please make a feature request to make proximity
+ * feature multi-client before depending on this feature.
+ *
+ * @param callback a callback that receives the proximity updates
+ * @return {@code true} if the registration should succeed.
+ */
+ public abstract boolean onStartProximityUpdates(ProximityCallbackInternal callback);
+
+ /**
+ * Requests to stop providing continuous updates until the callback is registered.
+ *
+ * @param callback a callback that was used in {@link #onStartProximityUpdates}
+ */
+ public abstract void onStopProximityUpdates(ProximityCallbackInternal callback);
+
/** Internal interface for attention callback. */
public abstract static class AttentionCallbackInternal {
/**
@@ -64,4 +83,13 @@ public abstract class AttentionManagerInternal {
*/
public abstract void onFailure(int error);
}
+
+ /** Internal interface for proximity callback. */
+ public abstract static class ProximityCallbackInternal {
+ /**
+ * @param distance the estimated distance of the user (in meter)
+ * The distance will be PROXIMITY_UNKNOWN if the proximity sensing was inconclusive.
+ */
+ public abstract void onProximityUpdate(double distance);
+ }
}
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index a0864d6459d3..52681630dab0 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -5031,6 +5031,20 @@ public abstract class Context {
public static final String SOUND_TRIGGER_MIDDLEWARE_SERVICE = "soundtrigger_middleware";
/**
+ * Used for getting the wallpaper effects generation service.
+ *
+ * <p><b>NOTE: </b> this service is optional; callers of
+ * {@code Context.getSystemServiceName(WALLPAPER_EFFECTS_GENERATION_SERVICE)} should check for
+ * {@code null}.
+ *
+ * @hide
+ * @see #getSystemService(String)
+ */
+ @SystemApi
+ public static final String WALLPAPER_EFFECTS_GENERATION_SERVICE =
+ "wallpaper_effects_generation";
+
+ /**
* Used to access {@link MusicRecognitionManagerService}.
*
* @hide
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 1c82b38c5007..30aed8bc4de7 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -653,6 +653,7 @@ interface IPackageManager {
@UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553)
String getPermissionControllerPackageName();
+ String getSupplementalProcessPackageName();
ParceledListSlice getInstantApps(int userId);
byte[] getInstantAppCookie(String packageName, int userId);
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index e5c31d7c0a8a..aa647000ee2d 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -5691,6 +5691,20 @@ public abstract class PackageManager {
}
/**
+ * Returns the package name of the component implementing supplemental process service.
+ *
+ * @return the package name of the component implementing supplemental process service
+ *
+ * @hide
+ */
+ @NonNull
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ @TestApi
+ public String getSupplementalProcessPackageName() {
+ throw new RuntimeException("Not implemented. Must override in a subclass.");
+ }
+
+ /**
* Add a new dynamic permission to the system. For this to work, your
* package must have defined a permission tree through the
* {@link android.R.styleable#AndroidManifestPermissionTree
diff --git a/core/java/android/hardware/hdmi/HdmiClient.java b/core/java/android/hardware/hdmi/HdmiClient.java
index cee6a5b16a3c..b96e4f88eb93 100644
--- a/core/java/android/hardware/hdmi/HdmiClient.java
+++ b/core/java/android/hardware/hdmi/HdmiClient.java
@@ -21,6 +21,8 @@ import java.util.concurrent.Executor;
public abstract class HdmiClient {
private static final String TAG = "HdmiClient";
+ private static final int UNKNOWN_VENDOR_ID = 0xFFFFFF;
+
/* package */ final IHdmiControlService mService;
private IHdmiVendorCommandListener mIHdmiVendorCommandListener;
@@ -156,11 +158,25 @@ public abstract class HdmiClient {
}
/**
- * Sets a listener used to receive incoming vendor-specific command.
+ * Sets a listener used to receive incoming vendor-specific command. This listener will only
+ * receive {@code <Vendor Command>} but will not receive any {@code <Vendor Command with ID>}
+ * messages.
*
* @param listener listener object
*/
public void setVendorCommandListener(@NonNull VendorCommandListener listener) {
+ // Set the vendor ID to INVALID_VENDOR_ID.
+ setVendorCommandListener(listener, UNKNOWN_VENDOR_ID);
+ }
+
+ /**
+ * Sets a listener used to receive incoming vendor-specific command.
+ *
+ * @param listener listener object
+ * @param vendorId The listener is interested in {@code <Vendor Command with ID>} received with
+ * this vendorId and all {@code <Vendor Command>} messages.
+ */
+ public void setVendorCommandListener(@NonNull VendorCommandListener listener, int vendorId) {
if (listener == null) {
throw new IllegalArgumentException("listener cannot be null");
}
@@ -169,7 +185,7 @@ public abstract class HdmiClient {
}
try {
IHdmiVendorCommandListener wrappedListener = getListenerWrapper(listener);
- mService.addVendorCommandListener(wrappedListener, getDeviceType());
+ mService.addVendorCommandListener(wrappedListener, vendorId);
mIHdmiVendorCommandListener = wrappedListener;
} catch (RemoteException e) {
Log.e(TAG, "failed to set vendor command listener: ", e);
diff --git a/core/java/android/hardware/hdmi/HdmiControlManager.java b/core/java/android/hardware/hdmi/HdmiControlManager.java
index ec55e121bf74..9235ba15019c 100644
--- a/core/java/android/hardware/hdmi/HdmiControlManager.java
+++ b/core/java/android/hardware/hdmi/HdmiControlManager.java
@@ -564,6 +564,32 @@ public final class HdmiControlManager {
@Retention(RetentionPolicy.SOURCE)
public @interface TvSendStandbyOnSleep {}
+ // -- Whether a playback device should act on an incoming {@code <Set Menu Language>} message.
+ /**
+ * Confirmation dialog should be shown upon receiving the CEC message.
+ *
+ * @see HdmiControlManager#CEC_SETTING_NAME_SET_MENU_LANGUAGE
+ * @hide
+ */
+ public static final int SET_MENU_LANGUAGE_ENABLED = 1;
+ /**
+ * The message should be ignored.
+ *
+ * @see HdmiControlManager#CEC_SETTING_NAME_SET_MENU_LANGUAGE
+ * @hide
+ */
+ public static final int SET_MENU_LANGUAGE_DISABLED = 0;
+ /**
+ * @see HdmiControlManager#CEC_SETTING_NAME_SET_MENU_LANGUAGE
+ * @hide
+ */
+ @IntDef(prefix = { "SET_MENU_LANGUAGE_" }, value = {
+ SET_MENU_LANGUAGE_ENABLED,
+ SET_MENU_LANGUAGE_DISABLED
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface SetMenuLanguage {}
+
// -- The RC profile of a TV panel.
/**
* RC profile none.
@@ -818,6 +844,13 @@ public final class HdmiControlManager {
public static final String CEC_SETTING_NAME_TV_SEND_STANDBY_ON_SLEEP =
"tv_send_standby_on_sleep";
/**
+ * Name of a setting deciding whether {@code <Set Menu Language>} message should be
+ * handled by the framework or ignored.
+ *
+ * @hide
+ */
+ public static final String CEC_SETTING_NAME_SET_MENU_LANGUAGE = "set_menu_language";
+ /**
* Name of a setting representing the RC profile of a TV panel.
*
* @hide
@@ -983,6 +1016,7 @@ public final class HdmiControlManager {
CEC_SETTING_NAME_VOLUME_CONTROL_MODE,
CEC_SETTING_NAME_TV_WAKE_ON_ONE_TOUCH_PLAY,
CEC_SETTING_NAME_TV_SEND_STANDBY_ON_SLEEP,
+ CEC_SETTING_NAME_SET_MENU_LANGUAGE,
CEC_SETTING_NAME_RC_PROFILE_TV,
CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_ROOT_MENU,
CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_SETUP_MENU,
diff --git a/core/java/android/hardware/hdmi/HdmiControlServiceWrapper.java b/core/java/android/hardware/hdmi/HdmiControlServiceWrapper.java
index 16adee9907ed..818554dd8143 100644
--- a/core/java/android/hardware/hdmi/HdmiControlServiceWrapper.java
+++ b/core/java/android/hardware/hdmi/HdmiControlServiceWrapper.java
@@ -221,8 +221,8 @@ public final class HdmiControlServiceWrapper {
}
@Override
- public void addVendorCommandListener(IHdmiVendorCommandListener listener, int deviceType) {
- HdmiControlServiceWrapper.this.addVendorCommandListener(listener, deviceType);
+ public void addVendorCommandListener(IHdmiVendorCommandListener listener, int vendorId) {
+ HdmiControlServiceWrapper.this.addVendorCommandListener(listener, vendorId);
}
@Override
@@ -481,7 +481,7 @@ public final class HdmiControlServiceWrapper {
boolean hasVendorId) {}
/** @hide */
- public void addVendorCommandListener(IHdmiVendorCommandListener listener, int deviceType) {}
+ public void addVendorCommandListener(IHdmiVendorCommandListener listener, int vendorId) {}
/** @hide */
public void sendStandby(int deviceType, int deviceId) {}
diff --git a/core/java/android/hardware/hdmi/IHdmiControlService.aidl b/core/java/android/hardware/hdmi/IHdmiControlService.aidl
index 6613397c8c0f..35dd9ed5bbcc 100644
--- a/core/java/android/hardware/hdmi/IHdmiControlService.aidl
+++ b/core/java/android/hardware/hdmi/IHdmiControlService.aidl
@@ -76,7 +76,7 @@ interface IHdmiControlService {
void askRemoteDeviceToBecomeActiveSource(int physicalAddress);
void sendVendorCommand(int deviceType, int targetAddress, in byte[] params,
boolean hasVendorId);
- void addVendorCommandListener(IHdmiVendorCommandListener listener, int deviceType);
+ void addVendorCommandListener(IHdmiVendorCommandListener listener, int vendorId);
void sendStandby(int deviceType, int deviceId);
void setHdmiRecordListener(IHdmiRecordListener callback);
void startOneTouchRecord(int recorderAddress, in byte[] recordSource);
diff --git a/core/java/android/hardware/input/IInputManager.aidl b/core/java/android/hardware/input/IInputManager.aidl
index 27403ec4fe59..e1ffd4a6761d 100644
--- a/core/java/android/hardware/input/IInputManager.aidl
+++ b/core/java/android/hardware/input/IInputManager.aidl
@@ -112,7 +112,7 @@ interface IInputManager {
oneway void requestPointerCapture(IBinder inputChannelToken, boolean enabled);
/** Create an input monitor for gestures. */
- InputMonitor monitorGestureInput(String name, int displayId);
+ InputMonitor monitorGestureInput(IBinder token, String name, int displayId);
// Add a runtime association between the input port and the display port. This overrides any
// static associations.
diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java
index 979e9dd6a1f6..2fd79cf980c7 100644
--- a/core/java/android/hardware/input/InputManager.java
+++ b/core/java/android/hardware/input/InputManager.java
@@ -35,6 +35,7 @@ import android.hardware.lights.Light;
import android.hardware.lights.LightState;
import android.hardware.lights.LightsManager;
import android.hardware.lights.LightsRequest;
+import android.os.Binder;
import android.os.BlockUntrustedTouchesMode;
import android.os.Build;
import android.os.CombinedVibration;
@@ -1211,7 +1212,7 @@ public final class InputManager {
*/
public InputMonitor monitorGestureInput(String name, int displayId) {
try {
- return mIm.monitorGestureInput(name, displayId);
+ return mIm.monitorGestureInput(new Binder(), name, displayId);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
diff --git a/core/java/android/os/GraphicsEnvironment.java b/core/java/android/os/GraphicsEnvironment.java
index aa4b83a5c361..0c3514fce76e 100644
--- a/core/java/android/os/GraphicsEnvironment.java
+++ b/core/java/android/os/GraphicsEnvironment.java
@@ -165,7 +165,7 @@ public class GraphicsEnvironment {
private boolean isAngleEnabledByGameMode(Context context, String packageName) {
try {
final boolean gameModeEnabledAngle =
- (mGameManager != null) && mGameManager.getAngleEnabled(packageName);
+ (mGameManager != null) && mGameManager.isAngleEnabled(packageName);
Log.v(TAG, "ANGLE GameManagerService for " + packageName + ": " + gameModeEnabledAngle);
return gameModeEnabledAngle;
} catch (SecurityException e) {
diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java
index 3bc3ec83bde5..321b3643b45b 100644
--- a/core/java/android/os/Parcel.java
+++ b/core/java/android/os/Parcel.java
@@ -2088,6 +2088,102 @@ public final class Parcel {
}
/**
+ * Flatten a homogeneous multi-dimensional array with fixed-size. This delegates to other
+ * APIs to write a one-dimensional array. Use {@link #readFixedArray(Object)} or
+ * {@link #createFixedArray(Class, int[])} with the same dimensions to unmarshal.
+ *
+ * @param val The array to be written.
+ * @param parcelableFlags Contextual flags as per
+ * {@link Parcelable#writeToParcel(Parcel, int) Parcelable.writeToParcel()}.
+ * Used only if val is an array of Parcelable objects.
+ * @param dimensions an array of int representing length of each dimension. The array should be
+ * sized with the exact size of dimensions.
+ *
+ * @see #readFixedArray
+ * @see #createFixedArray
+ * @see #writeBooleanArray
+ * @see #writeByteArray
+ * @see #writeCharArray
+ * @see #writeIntArray
+ * @see #writeLongArray
+ * @see #writeFloatArray
+ * @see #writeDoubleArray
+ * @see #writeBinderArray
+ * @see #writeInterfaceArray
+ * @see #writeTypedArray
+ * @throws BadParcelableException If the array's component type is not supported or if its
+ * size doesn't match with the given dimensions.
+ */
+ public <T> void writeFixedArray(@Nullable T val, int parcelableFlags,
+ @NonNull int... dimensions) {
+ if (val == null) {
+ writeInt(-1);
+ return;
+ }
+ writeFixedArrayInternal(val, parcelableFlags, /*index=*/0, dimensions);
+ }
+
+ private <T> void writeFixedArrayInternal(T val, int parcelableFlags, int index,
+ int[] dimensions) {
+ if (index >= dimensions.length) {
+ throw new BadParcelableException("Array has more dimensions than expected: "
+ + dimensions.length);
+ }
+
+ int length = dimensions[index];
+
+ // val should be an array of length N
+ if (val == null) {
+ throw new BadParcelableException("Non-null array shouldn't have a null array.");
+ }
+ if (!val.getClass().isArray()) {
+ throw new BadParcelableException("Not an array: " + val);
+ }
+ if (Array.getLength(val) != length) {
+ throw new BadParcelableException("bad length: expected " + length + ", but got "
+ + Array.getLength(val));
+ }
+
+ // Delegates to other writers if this is a one-dimensional array.
+ // Otherwise, write component arrays with recursive calls.
+
+ final Class<?> componentType = val.getClass().getComponentType();
+ if (!componentType.isArray() && index + 1 != dimensions.length) {
+ throw new BadParcelableException("Array has fewer dimensions than expected: "
+ + dimensions.length);
+ }
+ if (componentType == boolean.class) {
+ writeBooleanArray((boolean[]) val);
+ } else if (componentType == byte.class) {
+ writeByteArray((byte[]) val);
+ } else if (componentType == char.class) {
+ writeCharArray((char[]) val);
+ } else if (componentType == int.class) {
+ writeIntArray((int[]) val);
+ } else if (componentType == long.class) {
+ writeLongArray((long[]) val);
+ } else if (componentType == float.class) {
+ writeFloatArray((float[]) val);
+ } else if (componentType == double.class) {
+ writeDoubleArray((double[]) val);
+ } else if (componentType == IBinder.class) {
+ writeBinderArray((IBinder[]) val);
+ } else if (IInterface.class.isAssignableFrom(componentType)) {
+ writeInterfaceArray((IInterface[]) val);
+ } else if (Parcelable.class.isAssignableFrom(componentType)) {
+ writeTypedArray((Parcelable[]) val, parcelableFlags);
+ } else if (componentType.isArray()) {
+ writeInt(length);
+ for (int i = 0; i < length; i++) {
+ writeFixedArrayInternal(Array.get(val, i), parcelableFlags, index + 1,
+ dimensions);
+ }
+ } else {
+ throw new BadParcelableException("unknown type for fixed-size array: " + componentType);
+ }
+ }
+
+ /**
* Flatten a generic object in to a parcel. The given Object value may
* currently be one of the following types:
*
@@ -3788,6 +3884,317 @@ public final class Parcel {
}
/**
+ * Read a new multi-dimensional array from a parcel. If you want to read Parcelable or
+ * IInterface values, use {@link #readFixedArray(Object, Parcelable.Creator)} or
+ * {@link #readFixedArray(Object, Function)}.
+ * @param val the destination array to hold the read values.
+ *
+ * @see #writeTypedArray
+ * @see #readBooleanArray
+ * @see #readByteArray
+ * @see #readCharArray
+ * @see #readIntArray
+ * @see #readLongArray
+ * @see #readFloatArray
+ * @see #readDoubleArray
+ * @see #readBinderArray
+ * @see #readInterfaceArray
+ * @see #readTypedArray
+ */
+ public <T> void readFixedArray(@NonNull T val) {
+ Class<?> componentType = val.getClass().getComponentType();
+ if (componentType == boolean.class) {
+ readBooleanArray((boolean[]) val);
+ } else if (componentType == byte.class) {
+ readByteArray((byte[]) val);
+ } else if (componentType == char.class) {
+ readCharArray((char[]) val);
+ } else if (componentType == int.class) {
+ readIntArray((int[]) val);
+ } else if (componentType == long.class) {
+ readLongArray((long[]) val);
+ } else if (componentType == float.class) {
+ readFloatArray((float[]) val);
+ } else if (componentType == double.class) {
+ readDoubleArray((double[]) val);
+ } else if (componentType == IBinder.class) {
+ readBinderArray((IBinder[]) val);
+ } else if (componentType.isArray()) {
+ int length = readInt();
+ if (length != Array.getLength(val)) {
+ throw new BadParcelableException("Bad length: expected " + Array.getLength(val)
+ + ", but got " + length);
+ }
+ for (int i = 0; i < length; i++) {
+ readFixedArray(Array.get(val, i));
+ }
+ } else {
+ throw new BadParcelableException("Unknown type for fixed-size array: " + componentType);
+ }
+ }
+
+ /**
+ * Read a new multi-dimensional array of typed interfaces from a parcel.
+ * If you want to read Parcelable values, use
+ * {@link #readFixedArray(Object, Parcelable.Creator)}. For values of other types, use
+ * {@link #readFixedArray(Object)}.
+ * @param val the destination array to hold the read values.
+ */
+ public <T, S extends IInterface> void readFixedArray(@NonNull T val,
+ @NonNull Function<IBinder, S> asInterface) {
+ Class<?> componentType = val.getClass().getComponentType();
+ if (IInterface.class.isAssignableFrom(componentType)) {
+ readInterfaceArray((S[]) val, asInterface);
+ } else if (componentType.isArray()) {
+ int length = readInt();
+ if (length != Array.getLength(val)) {
+ throw new BadParcelableException("Bad length: expected " + Array.getLength(val)
+ + ", but got " + length);
+ }
+ for (int i = 0; i < length; i++) {
+ readFixedArray(Array.get(val, i), asInterface);
+ }
+ } else {
+ throw new BadParcelableException("Unknown type for fixed-size array: " + componentType);
+ }
+ }
+
+ /**
+ * Read a new multi-dimensional array of typed parcelables from a parcel.
+ * If you want to read IInterface values, use
+ * {@link #readFixedArray(Object, Function)}. For values of other types, use
+ * {@link #readFixedArray(Object)}.
+ * @param val the destination array to hold the read values.
+ */
+ public <T, S extends Parcelable> void readFixedArray(@NonNull T val,
+ @NonNull Parcelable.Creator<S> c) {
+ Class<?> componentType = val.getClass().getComponentType();
+ if (Parcelable.class.isAssignableFrom(componentType)) {
+ readTypedArray((S[]) val, c);
+ } else if (componentType.isArray()) {
+ int length = readInt();
+ if (length != Array.getLength(val)) {
+ throw new BadParcelableException("Bad length: expected " + Array.getLength(val)
+ + ", but got " + length);
+ }
+ for (int i = 0; i < length; i++) {
+ readFixedArray(Array.get(val, i), c);
+ }
+ } else {
+ throw new BadParcelableException("Unknown type for fixed-size array: " + componentType);
+ }
+ }
+
+ private void ensureClassHasExpectedDimensions(@NonNull Class<?> cls, int numDimension) {
+ if (numDimension <= 0) {
+ throw new BadParcelableException("Fixed-size array should have dimensions.");
+ }
+
+ for (int i = 0; i < numDimension; i++) {
+ if (!cls.isArray()) {
+ throw new BadParcelableException("Array has fewer dimensions than expected: "
+ + numDimension);
+ }
+ cls = cls.getComponentType();
+ }
+ if (cls.isArray()) {
+ throw new BadParcelableException("Array has more dimensions than expected: "
+ + numDimension);
+ }
+ }
+
+ /**
+ * Read and return a new multi-dimensional array from a parcel. Returns null if the
+ * previously written array object is null. If you want to read Parcelable or
+ * IInterface values, use {@link #createFixedArray(Class, Parcelable.Creator, int[])} or
+ * {@link #createFixedArray(Class, Function, int[])}.
+ * @param cls the Class object for the target array type. (e.g. int[][].class)
+ * @param dimensions an array of int representing length of each dimension.
+ *
+ * @see #writeTypedArray
+ * @see #createBooleanArray
+ * @see #createByteArray
+ * @see #createCharArray
+ * @see #createIntArray
+ * @see #createLongArray
+ * @see #createFloatArray
+ * @see #createDoubleArray
+ * @see #createBinderArray
+ * @see #createInterfaceArray
+ * @see #createTypedArray
+ */
+ @Nullable
+ public <T> T createFixedArray(@NonNull Class<T> cls, @NonNull int... dimensions) {
+ // Check if type matches with dimensions
+ // If type is one-dimensional array, delegate to other creators
+ // Otherwise, create an multi-dimensional array at once and then fill it with readFixedArray
+
+ ensureClassHasExpectedDimensions(cls, dimensions.length);
+
+ T val = null;
+ final Class<?> componentType = cls.getComponentType();
+ if (componentType == boolean.class) {
+ val = (T) createBooleanArray();
+ } else if (componentType == byte.class) {
+ val = (T) createByteArray();
+ } else if (componentType == char.class) {
+ val = (T) createCharArray();
+ } else if (componentType == int.class) {
+ val = (T) createIntArray();
+ } else if (componentType == long.class) {
+ val = (T) createLongArray();
+ } else if (componentType == float.class) {
+ val = (T) createFloatArray();
+ } else if (componentType == double.class) {
+ val = (T) createDoubleArray();
+ } else if (componentType == IBinder.class) {
+ val = (T) createBinderArray();
+ } else if (componentType.isArray()) {
+ int length = readInt();
+ if (length < 0) {
+ return null;
+ }
+ if (length != dimensions[0]) {
+ throw new BadParcelableException("Bad length: expected " + dimensions[0]
+ + ", but got " + length);
+ }
+
+ // Create a multi-dimensional array with an innermost component type and dimensions
+ Class<?> innermost = componentType.getComponentType();
+ while (innermost.isArray()) {
+ innermost = innermost.getComponentType();
+ }
+ val = (T) Array.newInstance(innermost, dimensions);
+ for (int i = 0; i < length; i++) {
+ readFixedArray(Array.get(val, i));
+ }
+ return val;
+ } else {
+ throw new BadParcelableException("Unknown type for fixed-size array: " + componentType);
+ }
+
+ // Check if val is null (which is OK) or has the expected size.
+ // This check doesn't have to be multi-dimensional because multi-dimensional arrays
+ // are created with expected dimensions.
+ if (val != null && Array.getLength(val) != dimensions[0]) {
+ throw new BadParcelableException("Bad length: expected " + dimensions[0] + ", but got "
+ + Array.getLength(val));
+ }
+ return val;
+ }
+
+ /**
+ * Read and return a new multi-dimensional array of typed interfaces from a parcel.
+ * Returns null if the previously written array object is null. If you want to read
+ * Parcelable values, use {@link #createFixedArray(Class, Parcelable.Creator, int[])}.
+ * For values of other types use {@link #createFixedArray(Class, int[])}.
+ * @param cls the Class object for the target array type. (e.g. IFoo[][].class)
+ * @param dimensions an array of int representing length of each dimension.
+ */
+ @Nullable
+ public <T, S extends IInterface> T createFixedArray(@NonNull Class<T> cls,
+ @NonNull Function<IBinder, S> asInterface, @NonNull int... dimensions) {
+ // Check if type matches with dimensions
+ // If type is one-dimensional array, delegate to other creators
+ // Otherwise, create an multi-dimensional array at once and then fill it with readFixedArray
+
+ ensureClassHasExpectedDimensions(cls, dimensions.length);
+
+ T val = null;
+ final Class<?> componentType = cls.getComponentType();
+ if (IInterface.class.isAssignableFrom(componentType)) {
+ val = (T) createInterfaceArray(n -> (S[]) Array.newInstance(componentType, n),
+ asInterface);
+ } else if (componentType.isArray()) {
+ int length = readInt();
+ if (length < 0) {
+ return null;
+ }
+ if (length != dimensions[0]) {
+ throw new BadParcelableException("Bad length: expected " + dimensions[0]
+ + ", but got " + length);
+ }
+
+ // Create a multi-dimensional array with an innermost component type and dimensions
+ Class<?> innermost = componentType.getComponentType();
+ while (innermost.isArray()) {
+ innermost = innermost.getComponentType();
+ }
+ val = (T) Array.newInstance(innermost, dimensions);
+ for (int i = 0; i < length; i++) {
+ readFixedArray(Array.get(val, i), asInterface);
+ }
+ return val;
+ } else {
+ throw new BadParcelableException("Unknown type for fixed-size array: " + componentType);
+ }
+
+ // Check if val is null (which is OK) or has the expected size.
+ // This check doesn't have to be multi-dimensional because multi-dimensional arrays
+ // are created with expected dimensions.
+ if (val != null && Array.getLength(val) != dimensions[0]) {
+ throw new BadParcelableException("Bad length: expected " + dimensions[0] + ", but got "
+ + Array.getLength(val));
+ }
+ return val;
+ }
+
+ /**
+ * Read and return a new multi-dimensional array of typed parcelables from a parcel.
+ * Returns null if the previously written array object is null. If you want to read
+ * IInterface values, use {@link #createFixedArray(Class, Function, int[])}.
+ * For values of other types use {@link #createFixedArray(Class, int[])}.
+ * @param cls the Class object for the target array type. (e.g. Foo[][].class)
+ * @param dimensions an array of int representing length of each dimension.
+ */
+ @Nullable
+ public <T, S extends Parcelable> T createFixedArray(@NonNull Class<T> cls,
+ @NonNull Parcelable.Creator<S> c, @NonNull int... dimensions) {
+ // Check if type matches with dimensions
+ // If type is one-dimensional array, delegate to other creators
+ // Otherwise, create an multi-dimensional array at once and then fill it with readFixedArray
+
+ ensureClassHasExpectedDimensions(cls, dimensions.length);
+
+ T val = null;
+ final Class<?> componentType = cls.getComponentType();
+ if (Parcelable.class.isAssignableFrom(componentType)) {
+ val = (T) createTypedArray(c);
+ } else if (componentType.isArray()) {
+ int length = readInt();
+ if (length < 0) {
+ return null;
+ }
+ if (length != dimensions[0]) {
+ throw new BadParcelableException("Bad length: expected " + dimensions[0]
+ + ", but got " + length);
+ }
+
+ // Create a multi-dimensional array with an innermost component type and dimensions
+ Class<?> innermost = componentType.getComponentType();
+ while (innermost.isArray()) {
+ innermost = innermost.getComponentType();
+ }
+ val = (T) Array.newInstance(innermost, dimensions);
+ for (int i = 0; i < length; i++) {
+ readFixedArray(Array.get(val, i), c);
+ }
+ return val;
+ } else {
+ throw new BadParcelableException("Unknown type for fixed-size array: " + componentType);
+ }
+
+ // Check if val is null (which is OK) or has the expected size.
+ // This check doesn't have to be multi-dimensional because multi-dimensional arrays
+ // are created with expected dimensions.
+ if (val != null && Array.getLength(val) != dimensions[0]) {
+ throw new BadParcelableException("Bad length: expected " + dimensions[0] + ", but got "
+ + Array.getLength(val));
+ }
+ return val;
+ }
+
+ /**
* Write a heterogeneous array of Parcelable objects into the Parcel.
* Each object in the array is written along with its class name, so
* that the correct class can later be instantiated. As a result, this
diff --git a/core/java/android/os/Vibrator.java b/core/java/android/os/Vibrator.java
index 8f5086021530..78f1cb12ded6 100644
--- a/core/java/android/os/Vibrator.java
+++ b/core/java/android/os/Vibrator.java
@@ -546,18 +546,22 @@ public abstract class Vibrator {
@VibrationEffectSupport
public final int areAllEffectsSupported(
@NonNull @VibrationEffect.EffectType int... effectIds) {
- int support = VIBRATION_EFFECT_SUPPORT_YES;
- for (int supported : areEffectsSupported(effectIds)) {
- if (supported == VIBRATION_EFFECT_SUPPORT_NO) {
- return VIBRATION_EFFECT_SUPPORT_NO;
- } else if (supported == VIBRATION_EFFECT_SUPPORT_UNKNOWN) {
- support = VIBRATION_EFFECT_SUPPORT_UNKNOWN;
+ VibratorInfo info = getInfo();
+ int allSupported = VIBRATION_EFFECT_SUPPORT_YES;
+ for (int effectId : effectIds) {
+ switch (info.isEffectSupported(effectId)) {
+ case VIBRATION_EFFECT_SUPPORT_NO:
+ return VIBRATION_EFFECT_SUPPORT_NO;
+ case VIBRATION_EFFECT_SUPPORT_YES:
+ continue;
+ default: // VIBRATION_EFFECT_SUPPORT_UNKNOWN
+ allSupported = VIBRATION_EFFECT_SUPPORT_UNKNOWN;
+ break;
}
}
- return support;
+ return allSupported;
}
-
/**
* Query whether the vibrator supports the given primitives.
*
@@ -598,8 +602,9 @@ public abstract class Vibrator {
*/
public final boolean areAllPrimitivesSupported(
@NonNull @VibrationEffect.Composition.PrimitiveType int... primitiveIds) {
- for (boolean supported : arePrimitivesSupported(primitiveIds)) {
- if (!supported) {
+ VibratorInfo info = getInfo();
+ for (int primitiveId : primitiveIds) {
+ if (!info.isPrimitiveSupported(primitiveId)) {
return false;
}
}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index c4fe1a44d161..ee6f9c033271 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -6094,9 +6094,11 @@ public final class Settings {
}
/** @hide */
- @UnsupportedAppUsage
- public static String getStringForUser(ContentResolver resolver, String name,
- int userHandle) {
+ @SystemApi
+ @Nullable
+ @SuppressLint("VisiblySynchronized")
+ public static String getStringForUser(@NonNull ContentResolver resolver,
+ @NonNull String name, int userHandle) {
if (MOVED_TO_GLOBAL.contains(name)) {
Log.w(TAG, "Setting " + name + " has moved from android.provider.Settings.Secure"
+ " to android.provider.Settings.Global.");
@@ -6328,8 +6330,9 @@ public final class Settings {
}
/** @hide */
- @UnsupportedAppUsage
- public static int getIntForUser(ContentResolver cr, String name, int def, int userHandle) {
+ @SystemApi
+ public static int getIntForUser(@NonNull ContentResolver cr, @NonNull String name,
+ int def, int userHandle) {
String v = getStringForUser(cr, name, userHandle);
return parseIntSettingWithDefault(v, def);
}
diff --git a/core/java/android/service/attention/AttentionService.java b/core/java/android/service/attention/AttentionService.java
index 49ab5db74b87..f5c59b597c3a 100644
--- a/core/java/android/service/attention/AttentionService.java
+++ b/core/java/android/service/attention/AttentionService.java
@@ -24,11 +24,14 @@ import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
+import android.util.Slog;
import com.android.internal.util.Preconditions;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.lang.ref.WeakReference;
+import java.util.Objects;
/**
@@ -51,6 +54,7 @@ import java.lang.annotation.RetentionPolicy;
*/
@SystemApi
public abstract class AttentionService extends Service {
+ private static final String LOG_TAG = "AttentionService";
/**
* The {@link Intent} that must be declared as handled by the service. To be supported, the
* service must also require the {@link android.Manifest.permission#BIND_ATTENTION_SERVICE}
@@ -80,6 +84,9 @@ public abstract class AttentionService extends Service {
/** Camera permission is not granted. */
public static final int ATTENTION_FAILURE_CAMERA_PERMISSION_ABSENT = 6;
+ /** Users’ proximity is unknown (proximity sensing was inconclusive and is unsupported). */
+ public static final double PROXIMITY_UNKNOWN = -1;
+
/**
* Result codes for when attention check was successful.
*
@@ -118,6 +125,20 @@ public abstract class AttentionService extends Service {
Preconditions.checkNotNull(callback);
AttentionService.this.onCancelAttentionCheck(new AttentionCallback(callback));
}
+
+ /** {@inheritDoc} */
+ @Override
+ public void onStartProximityUpdates(IProximityCallback callback) {
+ Objects.requireNonNull(callback);
+ AttentionService.this.onStartProximityUpdates(new ProximityCallback(callback));
+
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void onStopProximityUpdates() {
+ AttentionService.this.onStopProximityUpdates();
+ }
};
@Nullable
@@ -143,6 +164,23 @@ public abstract class AttentionService extends Service {
*/
public abstract void onCancelAttentionCheck(@NonNull AttentionCallback callback);
+ /**
+ * Requests the continuous updates of proximity signal via the provided callback,
+ * until the given callback is unregistered.
+ *
+ * @param callback the callback to return the result to
+ */
+ public void onStartProximityUpdates(@NonNull ProximityCallback callback) {
+ Slog.w(LOG_TAG, "Override this method.");
+ }
+
+ /**
+ * Requests to stop providing continuous updates until the callback is registered.
+ */
+ public void onStopProximityUpdates() {
+ Slog.w(LOG_TAG, "Override this method.");
+ }
+
/** Callbacks for AttentionService results. */
public static final class AttentionCallback {
@NonNull private final IAttentionCallback mCallback;
@@ -174,4 +212,26 @@ public abstract class AttentionService extends Service {
}
}
}
+
+ /** Callbacks for ProximityCallback results. */
+ public static final class ProximityCallback {
+ @NonNull private final WeakReference<IProximityCallback> mCallback;
+
+ private ProximityCallback(@NonNull IProximityCallback callback) {
+ mCallback = new WeakReference<>(callback);
+ }
+
+ /**
+ * @param distance the estimated distance of the user (in meter)
+ * The distance will be PROXIMITY_UNKNOWN if the proximity sensing was inconclusive.
+ *
+ */
+ public void onProximityUpdate(double distance) {
+ try {
+ mCallback.get().onProximityUpdate(distance);
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ }
+ }
}
diff --git a/core/java/android/service/attention/IAttentionService.aidl b/core/java/android/service/attention/IAttentionService.aidl
index 99e79973cfd2..8bb881ba1708 100644
--- a/core/java/android/service/attention/IAttentionService.aidl
+++ b/core/java/android/service/attention/IAttentionService.aidl
@@ -17,6 +17,7 @@
package android.service.attention;
import android.service.attention.IAttentionCallback;
+import android.service.attention.IProximityCallback;
/**
* Interface for a concrete implementation to provide to the AttentionManagerService.
@@ -26,4 +27,6 @@ import android.service.attention.IAttentionCallback;
oneway interface IAttentionService {
void checkAttention(IAttentionCallback callback);
void cancelAttentionCheck(IAttentionCallback callback);
+ void onStartProximityUpdates(IProximityCallback callback);
+ void onStopProximityUpdates();
} \ No newline at end of file
diff --git a/core/java/android/service/attention/IProximityCallback.aidl b/core/java/android/service/attention/IProximityCallback.aidl
new file mode 100644
index 000000000000..9ecf9bc28e84
--- /dev/null
+++ b/core/java/android/service/attention/IProximityCallback.aidl
@@ -0,0 +1,10 @@
+package android.service.attention;
+
+/**
+ * Callback for onStartProximityUpdates request.
+ *
+ * @hide
+ */
+oneway interface IProximityCallback {
+ void onProximityUpdate(double distance);
+}
diff --git a/core/java/android/service/games/GameSession.java b/core/java/android/service/games/GameSession.java
index 9590933cf2da..e33f1801129b 100644
--- a/core/java/android/service/games/GameSession.java
+++ b/core/java/android/service/games/GameSession.java
@@ -84,6 +84,15 @@ public abstract class GameSession {
}
@Override
+ public void onTransientSystemBarVisibilityFromRevealGestureChanged(
+ boolean visibleDueToGesture) {
+ Handler.getMain().executeOrSendMessage(PooledLambda.obtainMessage(
+ GameSession::dispatchTransientSystemBarVisibilityFromRevealGestureChanged,
+ GameSession.this,
+ visibleDueToGesture));
+ }
+
+ @Override
public void onTaskFocusChanged(boolean focused) {
Handler.getMain().executeOrSendMessage(PooledLambda.obtainMessage(
GameSession::moveToState, GameSession.this,
@@ -109,6 +118,7 @@ public abstract class GameSession {
}
private LifecycleState mLifecycleState = LifecycleState.INITIALIZED;
+ private boolean mAreTransientInsetsVisibleDueToGesture = false;
private IGameSessionController mGameSessionController;
private int mTaskId;
private GameSessionRootView mGameSessionRootView;
@@ -138,11 +148,23 @@ public abstract class GameSession {
}
@Hide
- void doDestroy() {
+ private void doDestroy() {
mSurfaceControlViewHost.release();
moveToState(LifecycleState.DESTROYED);
}
+ /** @hide */
+ @VisibleForTesting
+ @MainThread
+ public void dispatchTransientSystemBarVisibilityFromRevealGestureChanged(
+ boolean visibleDueToGesture) {
+ boolean didValueChange = mAreTransientInsetsVisibleDueToGesture != visibleDueToGesture;
+ mAreTransientInsetsVisibleDueToGesture = visibleDueToGesture;
+ if (didValueChange) {
+ onTransientSystemBarVisibilityFromRevealGestureChanged(visibleDueToGesture);
+ }
+ }
+
/**
* @hide
*/
@@ -252,7 +274,23 @@ public abstract class GameSession {
*
* @param focused True if the game task is focused, false if the game task is unfocused.
*/
- public void onGameTaskFocusChanged(boolean focused) {}
+ public void onGameTaskFocusChanged(boolean focused) {
+ }
+
+ /**
+ * Called when the visibility of the transient system bars changed due to the user performing
+ * the reveal gesture. The reveal gesture is defined as a swipe to reveal the transient system
+ * bars that originates from the system bars.
+ *
+ * @param visibleDueToGesture if the transient bars triggered by the reveal gesture are visible.
+ * This is {@code true} when the transient system bars become visible
+ * due to user performing the reveal gesture. This is {@code false}
+ * when the transient system bars are hidden or become permanently
+ * visible.
+ */
+ public void onTransientSystemBarVisibilityFromRevealGestureChanged(
+ boolean visibleDueToGesture) {
+ }
/**
* Sets the task overlay content to an explicit view. This view is placed directly into the game
@@ -344,12 +382,14 @@ public abstract class GameSession {
/**
* Called when taking the screenshot failed.
+ *
* @param statusCode Indicates the reason for failure.
*/
void onFailure(@ScreenshotFailureStatus int statusCode);
/**
* Called when taking the screenshot succeeded.
+ *
* @param bitmap The screenshot.
*/
void onSuccess(@NonNull Bitmap bitmap);
diff --git a/core/java/android/service/games/IGameSession.aidl b/core/java/android/service/games/IGameSession.aidl
index 71da6302b63d..49c36c6a301c 100644
--- a/core/java/android/service/games/IGameSession.aidl
+++ b/core/java/android/service/games/IGameSession.aidl
@@ -21,5 +21,6 @@ package android.service.games;
*/
oneway interface IGameSession {
void onDestroyed();
+ void onTransientSystemBarVisibilityFromRevealGestureChanged(boolean visibleDueToGesture);
void onTaskFocusChanged(boolean focused);
}
diff --git a/core/java/android/service/trust/ITrustAgentServiceCallback.aidl b/core/java/android/service/trust/ITrustAgentServiceCallback.aidl
index 220e498df8a8..6b11e7463abc 100644
--- a/core/java/android/service/trust/ITrustAgentServiceCallback.aidl
+++ b/core/java/android/service/trust/ITrustAgentServiceCallback.aidl
@@ -26,6 +26,7 @@ import android.os.UserHandle;
oneway interface ITrustAgentServiceCallback {
void grantTrust(CharSequence message, long durationMs, int flags);
void revokeTrust();
+ void lockUser();
void setManagingTrust(boolean managingTrust);
void onConfigureCompleted(boolean result, IBinder token);
void addEscrowToken(in byte[] token, int userId);
diff --git a/core/java/android/service/trust/TrustAgentService.java b/core/java/android/service/trust/TrustAgentService.java
index fba61cfd801e..8f6e1e00c3f4 100644
--- a/core/java/android/service/trust/TrustAgentService.java
+++ b/core/java/android/service/trust/TrustAgentService.java
@@ -119,16 +119,15 @@ public class TrustAgentService extends Service {
* automatically remove trust after some conditions are met (detailed below) with the option for
* the agent to renew the trust again later.
*
- * <p>After this is called, the agent will grant trust until the platform thinks an active user
- * is no longer using that trust. For example, if the user dismisses keyguard, the platform will
- * remove trust (this does not automatically lock the device).
+ * <p>After this is called, the agent will grant trust until the platform thinks an active
+ * user is no longer using that trust. This can happen for any reason as determined by the
+ * platform. For example, if the user dismisses keyguard, the platform will remove trust;
+ * since this does not automatically lock the device, this results in the device locking the
+ * next time the screen turns off.
*
* <p>When the platform internally removes the agent's trust in this manner, an agent can
* re-grant it (via a call to grantTrust) without the user having to unlock the device through
* another method (e.g. PIN). This renewable state only persists for a limited time.
- *
- * TODO(b/213631675): Remove @hide
- * @hide
*/
public static final int FLAG_GRANT_TRUST_TEMPORARY_AND_RENEWABLE = 1 << 2;
@@ -139,9 +138,6 @@ public class TrustAgentService extends Service {
* Without this flag, the message passed to {@code grantTrust} is only used for debugging
* purposes. With the flag, it may be displayed to the user as the reason why the device is
* unlocked.
- *
- * TODO(b/213911325): Remove @hide
- * @hide
*/
public static final int FLAG_GRANT_TRUST_DISPLAY_MESSAGE = 1 << 3;
@@ -309,9 +305,6 @@ public class TrustAgentService extends Service {
* {@link #grantTrust(CharSequence, long, int)}.
*
* @see #FLAG_GRANT_TRUST_TEMPORARY_AND_RENEWABLE
- *
- * TODO(b/213631672): Add CTS tests
- * @hide
*/
public void onUserRequestedUnlock() {
}
@@ -624,11 +617,15 @@ public class TrustAgentService extends Service {
*
* If the user has no auth method specified, then keyguard will still be shown but can be
* dismissed normally.
- *
- * TODO(b/213631675): Implement & make public
- * @hide
*/
public final void lockUser() {
+ if (mCallback != null) {
+ try {
+ mCallback.lockUser();
+ } catch (RemoteException e) {
+ onError("calling lockUser");
+ }
+ }
}
/**
diff --git a/core/java/android/service/wallpapereffectsgeneration/IWallpaperEffectsGenerationService.aidl b/core/java/android/service/wallpapereffectsgeneration/IWallpaperEffectsGenerationService.aidl
new file mode 100644
index 000000000000..ca75d2ed35ed
--- /dev/null
+++ b/core/java/android/service/wallpapereffectsgeneration/IWallpaperEffectsGenerationService.aidl
@@ -0,0 +1,28 @@
+
+/*
+ * 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.service.wallpapereffectsgeneration;
+
+import android.app.wallpapereffectsgeneration.CinematicEffectRequest;
+/**
+ * Interface from the system to WallpaperEffectsGeneration service.
+ *
+ * @hide
+ */
+oneway interface IWallpaperEffectsGenerationService {
+ void onGenerateCinematicEffect(in CinematicEffectRequest request);
+} \ No newline at end of file
diff --git a/core/java/android/service/wallpapereffectsgeneration/WallpaperEffectsGenerationService.java b/core/java/android/service/wallpapereffectsgeneration/WallpaperEffectsGenerationService.java
new file mode 100644
index 000000000000..18b654ec8f04
--- /dev/null
+++ b/core/java/android/service/wallpapereffectsgeneration/WallpaperEffectsGenerationService.java
@@ -0,0 +1,142 @@
+/*
+ * 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.service.wallpapereffectsgeneration;
+
+import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
+
+import android.annotation.CallSuper;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.app.Service;
+import android.app.wallpapereffectsgeneration.CinematicEffectRequest;
+import android.app.wallpapereffectsgeneration.CinematicEffectResponse;
+import android.app.wallpapereffectsgeneration.IWallpaperEffectsGenerationManager;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.Log;
+import android.util.Slog;
+
+/**
+ * A service for handling wallpaper effects generation tasks. It must implement
+ * (onGenerateCinematicEffect} method to generate response and call returnCinematicEffectResponse
+ * to send the response.
+ *
+ * <p>To extend this service, you must declare the service in your manifest file with the
+ * {@link android.Manifest.permission#BIND_WALLPAPER_EFFECTS_GENERATION} permission and includes
+ * an intent filter with the {@link #SERVICE_INTERFACE} action. For example: </p>
+ * <pre>
+ * <application>
+ * <service android:name=".CtsWallpaperEffectsGenerationService"
+ * android:exported="true"
+ * android:label="CtsWallpaperEffectsGenerationService"
+ * android:permission="android.permission.BIND_WALLPAPER_EFFECTS_GENERATION_SERVICE">
+ * <intent-filter>
+ * <action android:name="android.service.wallpapereffectsgeneration.WallpaperEffectsGenerationService"
+ />
+ * </intent-filter>
+ * </service>
+ * <uses-library android:name="android.test.runner"/>
+ * </application>
+ * </pre>
+ *
+ * @hide
+ */
+@SystemApi
+public abstract class WallpaperEffectsGenerationService extends Service {
+ /**
+ * The {@link Intent} that must be declared as handled by the service.
+ *
+ * <p>The service must also require the
+ * {@link android.permission#MANAGE_WALLPAPER_EFFECTS_GENERATION}
+ * permission.
+ *
+ * @hide
+ */
+ public static final String SERVICE_INTERFACE =
+ "android.service.wallpapereffectsgeneration.WallpaperEffectsGenerationService";
+ private static final boolean DEBUG = false;
+ private static final String TAG = "WallpaperEffectsGenerationService";
+ private Handler mHandler;
+ private IWallpaperEffectsGenerationManager mService;
+
+ private final IWallpaperEffectsGenerationService mInterface =
+ new IWallpaperEffectsGenerationService.Stub() {
+ @Override
+ public void onGenerateCinematicEffect(CinematicEffectRequest request) {
+ mHandler.sendMessage(
+ obtainMessage(
+ WallpaperEffectsGenerationService::onGenerateCinematicEffect,
+ WallpaperEffectsGenerationService.this, request));
+ }
+ };
+
+ /**
+ * Called when the OS receives a request for generating cinematic effect. On receiving the
+ * request, it extract cinematic information from the input and call
+ * {@link #returnCinematicEffectResponse} with the textured mesh
+ * and metadata wrapped in CinematicEffectResponse.
+ *
+ * @param request the cinematic effect request passed from the client.
+ */
+ public abstract void onGenerateCinematicEffect(@NonNull CinematicEffectRequest request);
+
+ /**
+ * Returns the cinematic effect response. Must be called when cinematic effect
+ * response is generated and ready to be sent back. Otherwise the response won't be
+ * returned.
+ *
+ * @param response the cinematic effect response returned from service provider.
+ */
+ public final void returnCinematicEffectResponse(@NonNull CinematicEffectResponse response) {
+ try {
+ mService.returnCinematicEffectResponse(response);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ @CallSuper
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ if (DEBUG) {
+ Log.d(TAG, "onCreate WallpaperEffectsGenerationService");
+ }
+ mHandler = new Handler(Looper.getMainLooper(), null, true);
+ IBinder b = ServiceManager.getService(Context.WALLPAPER_EFFECTS_GENERATION_SERVICE);
+ mService = IWallpaperEffectsGenerationManager.Stub.asInterface(b);
+ }
+
+ @NonNull
+ @Override
+ public final IBinder onBind(@NonNull Intent intent) {
+ if (DEBUG) {
+ Log.d(TAG, "onBind WallpaperEffectsGenerationService");
+ }
+ if (SERVICE_INTERFACE.equals(intent.getAction())) {
+ return mInterface.asBinder();
+ }
+ Slog.w(TAG,
+ "Tried to bind to wrong intent (should be " + SERVICE_INTERFACE + ": " + intent);
+ return null;
+ }
+}
diff --git a/core/java/android/view/InputMonitor.java b/core/java/android/view/InputMonitor.java
index ad1f201ba3c1..8801fe0b47c8 100644
--- a/core/java/android/view/InputMonitor.java
+++ b/core/java/android/view/InputMonitor.java
@@ -79,13 +79,17 @@ public final class InputMonitor implements Parcelable {
- // Code below generated by codegen v1.0.7.
+ // Code below generated by codegen v1.0.23.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
//
// To regenerate run:
// $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/view/InputMonitor.java
+ //
+ // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+ // Settings > Editor > Code Style > Formatter Control
+ //@formatter:off
@DataClass.Generated.Member
@@ -126,7 +130,7 @@ public final class InputMonitor implements Parcelable {
@Override
@DataClass.Generated.Member
- public void writeToParcel(Parcel dest, int flags) {
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
// You can override field parcelling by defining methods like:
// void parcelFieldName(Parcel dest, int flags) { ... }
@@ -141,7 +145,7 @@ public final class InputMonitor implements Parcelable {
/** @hide */
@SuppressWarnings({"unchecked", "RedundantCast"})
@DataClass.Generated.Member
- /* package-private */ InputMonitor(Parcel in) {
+ /* package-private */ InputMonitor(@NonNull Parcel in) {
// You can override field unparcelling by defining methods like:
// static FieldType unparcelFieldName(Parcel in) { ... }
@@ -167,17 +171,21 @@ public final class InputMonitor implements Parcelable {
}
@Override
- public InputMonitor createFromParcel(Parcel in) {
+ public InputMonitor createFromParcel(@NonNull Parcel in) {
return new InputMonitor(in);
}
};
@DataClass.Generated(
- time = 1571177265149L,
- codegenVersion = "1.0.7",
+ time = 1637697281750L,
+ codegenVersion = "1.0.23",
sourceFile = "frameworks/base/core/java/android/view/InputMonitor.java",
inputSignatures = "private static final java.lang.String TAG\nprivate static final boolean DEBUG\nprivate final @android.annotation.NonNull android.view.InputChannel mInputChannel\nprivate final @android.annotation.NonNull android.view.IInputMonitorHost mHost\npublic void pilferPointers()\npublic void dispose()\nclass InputMonitor extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true)")
@Deprecated
private void __metadata() {}
+
+ //@formatter:on
+ // End of generated code
+
}
diff --git a/core/java/com/android/internal/policy/TransitionAnimation.java b/core/java/com/android/internal/policy/TransitionAnimation.java
index ece6f2f3571b..37c96e71a0a8 100644
--- a/core/java/com/android/internal/policy/TransitionAnimation.java
+++ b/core/java/com/android/internal/policy/TransitionAnimation.java
@@ -98,6 +98,10 @@ public class TransitionAnimation {
private static final String DEFAULT_PACKAGE = "android";
+ // TODO (b/215515255): remove once we full migrate to shell transitions
+ private static final boolean SHELL_TRANSITIONS_ENABLED =
+ SystemProperties.getBoolean("persist.debug.shell_transit", false);
+
private final Context mContext;
private final String mTag;
@@ -252,6 +256,9 @@ public class TransitionAnimation {
resId = ent.array.getResourceId(animAttr, 0);
}
}
+ if (!SHELL_TRANSITIONS_ENABLED) {
+ resId = updateToLegacyIfNeeded(resId);
+ }
resId = updateToTranslucentAnimIfNeeded(resId, transit);
if (ResourceId.isValid(resId)) {
return loadAnimationSafely(context, resId, mTag);
@@ -259,6 +266,24 @@ public class TransitionAnimation {
return null;
}
+ /**
+ * Replace animations that are not compatible with the legacy transition system with ones that
+ * are compatible with it.
+ * TODO (b/215515255): remove once we full migrate to shell transitions
+ */
+ private int updateToLegacyIfNeeded(int anim) {
+ if (anim == R.anim.activity_open_enter) {
+ return R.anim.activity_open_enter_legacy;
+ } else if (anim == R.anim.activity_open_exit) {
+ return R.anim.activity_open_exit_legacy;
+ } else if (anim == R.anim.activity_close_enter) {
+ return R.anim.activity_close_enter_legacy;
+ } else if (anim == R.anim.activity_close_exit) {
+ return R.anim.activity_close_exit_legacy;
+ }
+ return anim;
+ }
+
/** Load animation by attribute Id from a specific AnimationStyle resource. */
@Nullable
public Animation loadAnimationAttr(String packageName, int animStyleResId, int animAttr,
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 66d5e88423e6..85504ceae791 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -4125,6 +4125,16 @@
<permission android:name="android.permission.BIND_CONTENT_SUGGESTIONS_SERVICE"
android:protectionLevel="signature" />
+ <!-- Must be required by a
+ android.service.wallpapereffectsgeneration.WallpaperEffectsGenerationService,
+ to ensure that only the system can bind to it.
+ @SystemApi @hide This is not a third-party API (intended for OEMs and system apps).
+ <p>Protection level: signature
+ -->
+ <permission android:name="android.permission.BIND_WALLPAPER_EFFECTS_GENERATION_SERVICE"
+ android:protectionLevel="signature" />
+
+
<!-- Must be declared by a android.service.musicrecognition.MusicRecognitionService,
to ensure that only the system can bind to it.
@SystemApi @hide This is not a third-party API (intended for OEMs and system apps).
@@ -5824,6 +5834,13 @@
<permission android:name="android.permission.MANAGE_SMARTSPACE"
android:protectionLevel="signature" />
+ <!-- @SystemApi Allows an application to manage the wallpaper effects
+ generation service.
+ @hide <p>Not for use by third-party applications.</p> -->
+ <permission android:name="android.permission.MANAGE_WALLPAPER_EFFECTS_GENERATION"
+ android:protectionLevel="signature" />
+
+
<!-- Allows an app to set the theme overlay in /vendor/overlay
being used.
@hide <p>Not for use by third-party applications.</p> -->
@@ -5923,6 +5940,10 @@
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.READ_CLIPBOARD_IN_BACKGROUND"
android:protectionLevel="signature" />
+ <!-- @hide Permission that suppresses the notification when the clipboard is accessed.
+ <p>Not for use by third-party applications. -->
+ <permission android:name="android.permission.SUPPRESS_CLIPBOARD_ACCESS_NOTIFICATION"
+ android:protectionLevel="signature" />
<!-- @SystemApi Allows modifying accessibility state.
@hide -->
diff --git a/core/res/res/anim/activity_close_enter.xml b/core/res/res/anim/activity_close_enter.xml
index 9fa7c5498ea6..0fefb5113dfc 100644
--- a/core/res/res/anim/activity_close_enter.xml
+++ b/core/res/res/anim/activity_close_enter.xml
@@ -19,16 +19,37 @@
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="false">
- <scale
- android:fromXScale="1.1"
- android:toXScale="1"
- android:fromYScale="1.1"
- android:toYScale="1"
- android:pivotX="50%"
- android:pivotY="50%"
+
+ <alpha
+ android:fromAlpha="1.0"
+ android:toAlpha="1.0"
android:fillEnabled="true"
android:fillBefore="true"
android:fillAfter="true"
+ android:interpolator="@interpolator/linear"
+ android:startOffset="0"
+ android:duration="450" />
+
+ <translate
+ android:fromXDelta="-10%"
+ android:toXDelta="0"
+ android:fillEnabled="true"
+ android:fillBefore="true"
+ android:fillAfter="true"
+ android:interpolator="@interpolator/fast_out_extra_slow_in"
+ android:startOffset="0"
+ android:duration="450" />
+
+ <extend
+ android:fromExtendLeft="0"
+ android:fromExtendTop="0"
+ android:fromExtendRight="10%"
+ android:fromExtendBottom="0"
+ android:toExtendLeft="0"
+ android:toExtendTop="0"
+ android:toExtendRight="10%"
+ android:toExtendBottom="0"
android:interpolator="@interpolator/fast_out_extra_slow_in"
- android:duration="400"/>
+ android:startOffset="0"
+ android:duration="450" />
</set> \ No newline at end of file
diff --git a/core/res/res/anim/activity_close_enter_legacy.xml b/core/res/res/anim/activity_close_enter_legacy.xml
new file mode 100644
index 000000000000..9fa7c5498ea6
--- /dev/null
+++ b/core/res/res/anim/activity_close_enter_legacy.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2009, 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.
+*/
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shareInterpolator="false">
+ <scale
+ android:fromXScale="1.1"
+ android:toXScale="1"
+ android:fromYScale="1.1"
+ android:toYScale="1"
+ android:pivotX="50%"
+ android:pivotY="50%"
+ android:fillEnabled="true"
+ android:fillBefore="true"
+ android:fillAfter="true"
+ android:interpolator="@interpolator/fast_out_extra_slow_in"
+ android:duration="400"/>
+</set> \ No newline at end of file
diff --git a/core/res/res/anim/activity_close_exit.xml b/core/res/res/anim/activity_close_exit.xml
index 1599ae8cb19f..f807c26dda20 100644
--- a/core/res/res/anim/activity_close_exit.xml
+++ b/core/res/res/anim/activity_close_exit.xml
@@ -18,27 +18,38 @@
-->
<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:shareInterpolator="false"
- android:zAdjustment="top">
+ android:shareInterpolator="false">
+
<alpha
- android:fromAlpha="1"
+ android:fromAlpha="1.0"
android:toAlpha="0.0"
android:fillEnabled="true"
android:fillBefore="true"
android:fillAfter="true"
android:interpolator="@interpolator/linear"
- android:startOffset="33"
- android:duration="50"/>
- <scale
- android:fromXScale="1"
- android:toXScale="0.9"
- android:fromYScale="1"
- android:toYScale="0.9"
- android:pivotX="50%"
- android:pivotY="50%"
+ android:startOffset="35"
+ android:duration="83" />
+
+ <translate
+ android:fromXDelta="0"
+ android:toXDelta="10%"
android:fillEnabled="true"
android:fillBefore="true"
android:fillAfter="true"
android:interpolator="@interpolator/fast_out_extra_slow_in"
- android:duration="400"/>
+ android:startOffset="0"
+ android:duration="450" />
+
+ <extend
+ android:fromExtendLeft="10%"
+ android:fromExtendTop="0"
+ android:fromExtendRight="0"
+ android:fromExtendBottom="0"
+ android:toExtendLeft="10%"
+ android:toExtendTop="0"
+ android:toExtendRight="0"
+ android:toExtendBottom="0"
+ android:interpolator="@interpolator/fast_out_extra_slow_in"
+ android:startOffset="0"
+ android:duration="450" />
</set>
diff --git a/core/res/res/anim/activity_close_exit_legacy.xml b/core/res/res/anim/activity_close_exit_legacy.xml
new file mode 100644
index 000000000000..1599ae8cb19f
--- /dev/null
+++ b/core/res/res/anim/activity_close_exit_legacy.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2009, 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.
+*/
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shareInterpolator="false"
+ android:zAdjustment="top">
+ <alpha
+ android:fromAlpha="1"
+ android:toAlpha="0.0"
+ android:fillEnabled="true"
+ android:fillBefore="true"
+ android:fillAfter="true"
+ android:interpolator="@interpolator/linear"
+ android:startOffset="33"
+ android:duration="50"/>
+ <scale
+ android:fromXScale="1"
+ android:toXScale="0.9"
+ android:fromYScale="1"
+ android:toYScale="0.9"
+ android:pivotX="50%"
+ android:pivotY="50%"
+ android:fillEnabled="true"
+ android:fillBefore="true"
+ android:fillAfter="true"
+ android:interpolator="@interpolator/fast_out_extra_slow_in"
+ android:duration="400"/>
+</set>
diff --git a/core/res/res/anim/activity_open_enter.xml b/core/res/res/anim/activity_open_enter.xml
index 38d3e8ed06ce..1674dab3040a 100644
--- a/core/res/res/anim/activity_open_enter.xml
+++ b/core/res/res/anim/activity_open_enter.xml
@@ -18,6 +18,7 @@
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="false">
+
<alpha
android:fromAlpha="0"
android:toAlpha="1.0"
@@ -26,17 +27,27 @@
android:fillAfter="true"
android:interpolator="@interpolator/linear"
android:startOffset="50"
- android:duration="50"/>
- <scale
- android:fromXScale="0.85"
- android:toXScale="1"
- android:fromYScale="0.85"
- android:toYScale="1"
- android:pivotX="50%"
- android:pivotY="50%"
+ android:duration="83" />
+
+ <translate
+ android:fromXDelta="10%"
+ android:toXDelta="0"
android:fillEnabled="true"
android:fillBefore="true"
android:fillAfter="true"
android:interpolator="@interpolator/fast_out_extra_slow_in"
- android:duration="400"/>
+ android:duration="450" />
+
+ <extend
+ android:fromExtendLeft="10%"
+ android:fromExtendTop="0"
+ android:fromExtendRight="0"
+ android:fromExtendBottom="0"
+ android:toExtendLeft="10%"
+ android:toExtendTop="0"
+ android:toExtendRight="0"
+ android:toExtendBottom="0"
+ android:interpolator="@interpolator/fast_out_extra_slow_in"
+ android:startOffset="0"
+ android:duration="450" />
</set>
diff --git a/core/res/res/anim/activity_open_enter_legacy.xml b/core/res/res/anim/activity_open_enter_legacy.xml
new file mode 100644
index 000000000000..38d3e8ed06ce
--- /dev/null
+++ b/core/res/res/anim/activity_open_enter_legacy.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+/*
+** Copyright 2009, 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.
+*/
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shareInterpolator="false">
+ <alpha
+ android:fromAlpha="0"
+ android:toAlpha="1.0"
+ android:fillEnabled="true"
+ android:fillBefore="true"
+ android:fillAfter="true"
+ android:interpolator="@interpolator/linear"
+ android:startOffset="50"
+ android:duration="50"/>
+ <scale
+ android:fromXScale="0.85"
+ android:toXScale="1"
+ android:fromYScale="0.85"
+ android:toYScale="1"
+ android:pivotX="50%"
+ android:pivotY="50%"
+ android:fillEnabled="true"
+ android:fillBefore="true"
+ android:fillAfter="true"
+ android:interpolator="@interpolator/fast_out_extra_slow_in"
+ android:duration="400"/>
+</set>
diff --git a/core/res/res/anim/activity_open_exit.xml b/core/res/res/anim/activity_open_exit.xml
index 3865d2149f42..372f2c8e09f6 100644
--- a/core/res/res/anim/activity_open_exit.xml
+++ b/core/res/res/anim/activity_open_exit.xml
@@ -19,27 +19,36 @@
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="false">
- <!-- Fade out, over a black surface, which simulates a black scrim -->
<alpha
- android:fromAlpha="1"
- android:toAlpha="0.4"
+ android:fromAlpha="1.0"
+ android:toAlpha="1.0"
android:fillEnabled="true"
android:fillBefore="true"
android:fillAfter="true"
- android:interpolator="@interpolator/linear"
- android:startOffset="83"
- android:duration="167"/>
+ android:interpolator="@interpolator/standard_accelerate"
+ android:startOffset="0"
+ android:duration="450" />
- <scale
- android:fromXScale="1"
- android:toXScale="1.05"
- android:fromYScale="1"
- android:toYScale="1.05"
- android:pivotX="50%"
- android:pivotY="50%"
+ <translate
+ android:fromXDelta="0"
+ android:toXDelta="-10%"
android:fillEnabled="true"
android:fillBefore="true"
android:fillAfter="true"
android:interpolator="@interpolator/fast_out_extra_slow_in"
- android:duration="400"/>
+ android:startOffset="0"
+ android:duration="450" />
+
+ <extend
+ android:fromExtendLeft="0"
+ android:fromExtendTop="0"
+ android:fromExtendRight="10%"
+ android:fromExtendBottom="0"
+ android:toExtendLeft="0"
+ android:toExtendTop="0"
+ android:toExtendRight="10%"
+ android:toExtendBottom="0"
+ android:interpolator="@interpolator/fast_out_extra_slow_in"
+ android:startOffset="0"
+ android:duration="450" />
</set> \ No newline at end of file
diff --git a/core/res/res/anim/activity_open_exit_legacy.xml b/core/res/res/anim/activity_open_exit_legacy.xml
new file mode 100644
index 000000000000..3865d2149f42
--- /dev/null
+++ b/core/res/res/anim/activity_open_exit_legacy.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+/*
+** Copyright 2009, 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.
+*/
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shareInterpolator="false">
+
+ <!-- Fade out, over a black surface, which simulates a black scrim -->
+ <alpha
+ android:fromAlpha="1"
+ android:toAlpha="0.4"
+ android:fillEnabled="true"
+ android:fillBefore="true"
+ android:fillAfter="true"
+ android:interpolator="@interpolator/linear"
+ android:startOffset="83"
+ android:duration="167"/>
+
+ <scale
+ android:fromXScale="1"
+ android:toXScale="1.05"
+ android:fromYScale="1"
+ android:toYScale="1.05"
+ android:pivotX="50%"
+ android:pivotY="50%"
+ android:fillEnabled="true"
+ android:fillBefore="true"
+ android:fillAfter="true"
+ android:interpolator="@interpolator/fast_out_extra_slow_in"
+ android:duration="400"/>
+</set> \ No newline at end of file
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 04e29890568a..afe0f1bf0001 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -8875,6 +8875,22 @@
<attr name="gameSessionService" format="string" />
</declare-styleable>
+ <!-- Use <code>game-mode-config</code> as the root tag of the XML resource that
+ describes a GameModeConfig.
+ Described here are the attributes that can be included in that tag. -->
+ <declare-styleable name="GameModeConfig">
+ <!-- Set true to opt in BATTERY mode. -->
+ <attr name="supportsBatteryGameMode" format="boolean" />
+ <!-- Set true to opt in PERFORMANCE mode. -->
+ <attr name="supportsPerformanceGameMode" format="boolean" />
+ <!-- Set true to enable ANGLE. -->
+ <attr name="allowGameAngleDriver" format="boolean" />
+ <!-- Set true to allow resolution downscaling intervention. -->
+ <attr name="allowGameDownscaling" format="boolean" />
+ <!-- Set true to allow FPS override intervention. -->
+ <attr name="allowGameFpsOverride" format="boolean" />
+ </declare-styleable>
+
<!-- Use <code>voice-enrollment-application</code>
as the root tag of the XML resource that escribes the supported keyphrases (hotwords)
by the enrollment application.
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index a06b2cb28037..902d5e0b9f32 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -4173,6 +4173,15 @@
<string name="config_defaultMusicRecognitionService" translatable="false"></string>
+ <!-- The package name for the system's wallpaper effects generation service.
+ This service returns wallpaper effects results.
+ This service must be trusted, as it can be activated without explicit consent of the user.
+ If no service with the specified name exists on the device, wallpaper effects
+ generation service will be disabled.
+ Example: "com.android.intelligence/.WallpaperEffectsGenerationService"
+-->
+ <string name="config_defaultWallpaperEffectsGenerationService" translatable="false"></string>
+
<!-- The package name for the default retail demo app.
This package must be trusted, as it has the permissions to query the usage stats on the
device.
@@ -5267,6 +5276,12 @@
<bool name="config_cecTvSendStandbyOnSleepDisabled_allowed">true</bool>
<bool name="config_cecTvSendStandbyOnSleepDisabled_default">false</bool>
+ <bool name="config_cecSetMenuLanguage_userConfigurable">true</bool>
+ <bool name="config_cecSetMenuLanguageEnabled_allowed">true</bool>
+ <bool name="config_cecSetMenuLanguageEnabled_default">true</bool>
+ <bool name="config_cecSetMenuLanguageDisabled_allowed">true</bool>
+ <bool name="config_cecSetMenuLanguageDisabled_default">false</bool>
+
<bool name="config_cecRcProfileTv_userConfigurable">true</bool>
<bool name="config_cecRcProfileTvNone_allowed">true</bool>
<bool name="config_cecRcProfileTvNone_default">true</bool>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 047c04b3596c..d57f5ba8179b 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -3255,6 +3255,11 @@
<public name="showClockAndComplications" />
<!-- @hide @SystemApi -->
<public name="gameSessionService" />
+ <public name="supportsBatteryGameMode" />
+ <public name="supportsPerformanceGameMode" />
+ <public name="allowGameAngleDriver" />
+ <public name="allowGameDownscaling" />
+ <public name="allowGameFpsOverride" />
<public name="localeConfig" />
<public name="showBackground" />
<public name="inheritKeyStoreKeys" />
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 610c6a69822c..2e4b783a6dca 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -5857,6 +5857,8 @@
<string name="accessibility_system_action_lock_screen_label">Lock Screen</string>
<!-- Label for taking screenshot action [CHAR LIMIT=NONE] -->
<string name="accessibility_system_action_screenshot_label">Screenshot</string>
+ <!-- Label for headset hook action [CHAR LIMIT=NONE] -->
+ <string name="accessibility_system_action_headset_hook_label">Headset Hook</string>
<!-- Label for triggering on-screen accessibility shortcut action [CHAR LIMIT=NONE] -->
<string name="accessibility_system_action_on_screen_a11y_shortcut_label">On-screen Accessibility Shortcut</string>
<!-- Label for showing on-screen accessibility shortcut chooser action [CHAR LIMIT=NONE] -->
@@ -5865,6 +5867,16 @@
<string name="accessibility_system_action_hardware_a11y_shortcut_label">Accessibility Shortcut</string>
<!-- Label for dismissing the notification shade [CHAR LIMIT=NONE] -->
<string name="accessibility_system_action_dismiss_notification_shade">Dismiss Notification Shade</string>
+ <!-- Label for Dpad up action [CHAR LIMIT=NONE] -->
+ <string name="accessibility_system_action_dpad_up_label">Dpad Up</string>
+ <!-- Label for Dpad down action [CHAR LIMIT=NONE] -->
+ <string name="accessibility_system_action_dpad_down_label">Dpad Down</string>
+ <!-- Label for Dpad left action [CHAR LIMIT=NONE] -->
+ <string name="accessibility_system_action_dpad_left_label">Dpad Left</string>
+ <!-- Label for Dpad right action [CHAR LIMIT=NONE] -->
+ <string name="accessibility_system_action_dpad_right_label">Dpad Right</string>
+ <!-- Label for Dpad center action [CHAR LIMIT=NONE] -->
+ <string name="accessibility_system_action_dpad_center_label">Dpad Center</string>
<!-- Accessibility description of caption view -->
<string name="accessibility_freeform_caption">Caption bar of <xliff:g id="app_name">%1$s</xliff:g>.</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 4c1cc4dc8f70..30a196395b35 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1697,7 +1697,13 @@
<java-symbol type="anim" name="activity_translucent_open_enter" />
<java-symbol type="anim" name="activity_translucent_close_exit" />
<java-symbol type="anim" name="activity_open_enter" />
+ <java-symbol type="anim" name="activity_open_exit" />
+ <java-symbol type="anim" name="activity_close_enter" />
<java-symbol type="anim" name="activity_close_exit" />
+ <java-symbol type="anim" name="activity_open_enter_legacy" />
+ <java-symbol type="anim" name="activity_open_exit_legacy" />
+ <java-symbol type="anim" name="activity_close_enter_legacy" />
+ <java-symbol type="anim" name="activity_close_exit_legacy" />
<java-symbol type="anim" name="task_fragment_close_enter" />
<java-symbol type="anim" name="task_fragment_close_exit" />
<java-symbol type="anim" name="task_fragment_open_enter" />
@@ -3673,6 +3679,7 @@
<java-symbol type="string" name="config_defaultContentSuggestionsService" />
<java-symbol type="string" name="config_defaultSearchUiService" />
<java-symbol type="string" name="config_defaultSmartspaceService" />
+ <java-symbol type="string" name="config_defaultWallpaperEffectsGenerationService" />
<java-symbol type="string" name="config_defaultMusicRecognitionService" />
<java-symbol type="string" name="config_defaultAttentionService" />
<java-symbol type="string" name="config_defaultRotationResolverService" />
@@ -4129,10 +4136,16 @@
<java-symbol type="string" name="accessibility_system_action_quick_settings_label" />
<java-symbol type="string" name="accessibility_system_action_recents_label" />
<java-symbol type="string" name="accessibility_system_action_screenshot_label" />
+ <java-symbol type="string" name="accessibility_system_action_headset_hook_label" />
<java-symbol type="string" name="accessibility_system_action_on_screen_a11y_shortcut_label" />
<java-symbol type="string" name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" />
<java-symbol type="string" name="accessibility_system_action_hardware_a11y_shortcut_label" />
<java-symbol type="string" name="accessibility_system_action_dismiss_notification_shade" />
+ <java-symbol type="string" name="accessibility_system_action_dpad_up_label" />
+ <java-symbol type="string" name="accessibility_system_action_dpad_down_label" />
+ <java-symbol type="string" name="accessibility_system_action_dpad_left_label" />
+ <java-symbol type="string" name="accessibility_system_action_dpad_right_label" />
+ <java-symbol type="string" name="accessibility_system_action_dpad_center_label" />
<java-symbol type="string" name="accessibility_freeform_caption" />
@@ -4453,6 +4466,12 @@
<java-symbol type="bool" name="config_cecTvSendStandbyOnSleepDisabled_allowed" />
<java-symbol type="bool" name="config_cecTvSendStandbyOnSleepDisabled_default" />
+ <java-symbol type="bool" name="config_cecSetMenuLanguage_userConfigurable" />
+ <java-symbol type="bool" name="config_cecSetMenuLanguageEnabled_allowed" />
+ <java-symbol type="bool" name="config_cecSetMenuLanguageEnabled_default" />
+ <java-symbol type="bool" name="config_cecSetMenuLanguageDisabled_allowed" />
+ <java-symbol type="bool" name="config_cecSetMenuLanguageDisabled_default" />
+
<java-symbol type="bool" name="config_cecRcProfileTv_userConfigurable" />
<java-symbol type="bool" name="config_cecRcProfileTvNone_allowed" />
<java-symbol type="bool" name="config_cecRcProfileTvNone_default" />
diff --git a/core/tests/hdmitests/src/android/hardware/hdmi/HdmiAudioSystemClientTest.java b/core/tests/hdmitests/src/android/hardware/hdmi/HdmiAudioSystemClientTest.java
index f04a9f735881..e16a2f8e8560 100644
--- a/core/tests/hdmitests/src/android/hardware/hdmi/HdmiAudioSystemClientTest.java
+++ b/core/tests/hdmitests/src/android/hardware/hdmi/HdmiAudioSystemClientTest.java
@@ -288,9 +288,8 @@ public class HdmiAudioSystemClientTest {
}
@Override
- public void addVendorCommandListener(final IHdmiVendorCommandListener listener,
- final int deviceType) {
- }
+ public void addVendorCommandListener(
+ final IHdmiVendorCommandListener listener, final int vendorId) {}
@Override
public void sendVendorCommand(final int deviceType, final int targetAddress,
diff --git a/data/etc/com.android.settings.xml b/data/etc/com.android.settings.xml
index ddcab6eb76c8..5dcc5998850b 100644
--- a/data/etc/com.android.settings.xml
+++ b/data/etc/com.android.settings.xml
@@ -61,5 +61,6 @@
<permission name="android.permission.READ_DREAM_SUPPRESSION"/>
<permission name="android.permission.RESTART_WIFI_SUBSYSTEM"/>
<permission name="android.permission.READ_SAFETY_CENTER_STATUS" />
+ <permission name="android.permission.SEND_SAFETY_CENTER_UPDATE" />
</privapp-permissions>
</permissions>
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index b3dcc34d6e93..d0026016ecf4 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -581,6 +581,7 @@ applications that come with the platform
<permission name="android.permission.INSTALL_DYNAMIC_SYSTEM"/>
<permission name="android.permission.BIND_CELL_BROADCAST_SERVICE"/>
<permission name="android.permission.READ_SAFETY_CENTER_STATUS" />
+ <permission name="android.permission.SEND_SAFETY_CENTER_UPDATE" />
</privapp-permissions>
<privapp-permissions package="com.android.bips">
diff --git a/identity/java/android/security/identity/IdentityCredential.java b/identity/java/android/security/identity/IdentityCredential.java
index cdf746fc9900..f440b693a5b3 100644
--- a/identity/java/android/security/identity/IdentityCredential.java
+++ b/identity/java/android/security/identity/IdentityCredential.java
@@ -454,7 +454,8 @@ public abstract class IdentityCredential {
* @param challenge is a non-empty byte array whose contents should be unique, fresh and
* provided by the issuing authority. The value provided is embedded in the
* generated CBOR and enables the issuing authority to verify that the
- * returned proof is fresh.
+ * returned proof is fresh. Implementations are required to support
+ * challenges at least 32 bytes of length.
* @return the COSE_Sign1 data structure above
*/
public @NonNull byte[] proveOwnership(@NonNull byte[] challenge) {
@@ -485,7 +486,8 @@ public abstract class IdentityCredential {
* @param challenge is a non-empty byte array whose contents should be unique, fresh and
* provided by the issuing authority. The value provided is embedded in the
* generated CBOR and enables the issuing authority to verify that the
- * returned proof is fresh.
+ * returned proof is fresh. Implementations are required to support
+ * challenges at least 32 bytes of length.
* @return the COSE_Sign1 data structure above
*/
public @NonNull byte[] delete(@NonNull byte[] challenge) {
diff --git a/identity/java/android/security/identity/WritableIdentityCredential.java b/identity/java/android/security/identity/WritableIdentityCredential.java
index 305d0ead0652..6d569648f2c6 100644
--- a/identity/java/android/security/identity/WritableIdentityCredential.java
+++ b/identity/java/android/security/identity/WritableIdentityCredential.java
@@ -59,7 +59,8 @@ public abstract class WritableIdentityCredential {
* @param challenge is a non-empty byte array whose contents should be unique, fresh and
* provided by the issuing authority. The value provided is embedded in the
* attestation extension and enables the issuing authority to verify that the
- * attestation certificate is fresh.
+ * attestation certificate is fresh. Implementations are required to support
+ * challenges at least 32 bytes of length.
* @return the X.509 certificate for this credential's CredentialKey.
*/
public abstract @NonNull Collection<X509Certificate> getCredentialKeyCertificateChain(
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
index 17005ea7d500..6b0d7f5fa461 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
@@ -867,6 +867,10 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
}
private void fadeExistingPip(boolean show) {
+ if (mLeash == null || !mLeash.isValid()) {
+ Log.w(TAG, "Invalid leash on fadeExistingPip: " + mLeash);
+ return;
+ }
final float alphaStart = show ? 0 : 1;
final float alphaEnd = show ? 1 : 0;
mPipAnimationController
diff --git a/media/java/android/media/BtProfileConnectionInfo.java b/media/java/android/media/BtProfileConnectionInfo.java
index 86dc6e0f09c5..88b9777e911d 100644
--- a/media/java/android/media/BtProfileConnectionInfo.java
+++ b/media/java/android/media/BtProfileConnectionInfo.java
@@ -27,6 +27,7 @@ import android.os.Parcelable;
*/
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public final class BtProfileConnectionInfo implements Parcelable {
+
private final int mProfile;
private final boolean mSupprNoisy;
private final int mVolume;
diff --git a/packages/ConnectivityT/framework-t/src/android/net/InternalNetworkManagementException.java b/packages/ConnectivityT/framework-t/src/android/net/InternalNetworkManagementException.java
index 7f4e403f2259..798e9c3b52b5 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/InternalNetworkManagementException.java
+++ b/packages/ConnectivityT/framework-t/src/android/net/InternalNetworkManagementException.java
@@ -20,22 +20,34 @@ import android.annotation.NonNull;
import android.os.Parcel;
import android.os.Parcelable;
+import java.util.Objects;
+
/** @hide */
public final class InternalNetworkManagementException
extends RuntimeException implements Parcelable {
/* @hide */
- public InternalNetworkManagementException(@NonNull final Throwable t) {
- super(t);
+ public InternalNetworkManagementException(@NonNull final String errorMessage) {
+ super(errorMessage);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(getMessage());
}
- private InternalNetworkManagementException(@NonNull final Parcel source) {
- super(source.readString());
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) return true;
+ if (obj == null || getClass() != obj.getClass()) return false;
+ final InternalNetworkManagementException that = (InternalNetworkManagementException) obj;
+
+ return Objects.equals(getMessage(), that.getMessage());
}
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
- dest.writeString(getCause().getMessage());
+ dest.writeString(getMessage());
}
@Override
@@ -53,7 +65,7 @@ public final class InternalNetworkManagementException
@Override
public InternalNetworkManagementException createFromParcel(@NonNull Parcel source) {
- return new InternalNetworkManagementException(source);
+ return new InternalNetworkManagementException(source.readString());
}
};
}
diff --git a/packages/SettingsLib/res/values/arrays.xml b/packages/SettingsLib/res/values/arrays.xml
index 93e3deef7aa5..29a1831d28cb 100644
--- a/packages/SettingsLib/res/values/arrays.xml
+++ b/packages/SettingsLib/res/values/arrays.xml
@@ -647,6 +647,11 @@
<item>disabled</item>
</array>
+ <!-- Images offered as options in the avatar picker. If populated, the avatar_image_descriptions
+ array must also be populated with a content description for each image. -->
<array name="avatar_images"/>
+ <!-- Content descriptions for each of the images in the avatar_images array. -->
+ <string-array name="avatar_image_descriptions"/>
+
</resources>
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index af6a658f362a..0fe869fc44ef 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -1562,4 +1562,8 @@
<!-- Title for a screen allowing the user to choose a profile picture. [CHAR LIMIT=NONE] -->
<string name="avatar_picker_title">Choose a profile picture</string>
+
+ <!-- Content description for a default user icon. [CHAR LIMIT=NONE] -->
+ <string name="default_user_icon_description">Default user icon</string>
+
</resources>
diff --git a/packages/SettingsLib/src/com/android/settingslib/users/AvatarPickerActivity.java b/packages/SettingsLib/src/com/android/settingslib/users/AvatarPickerActivity.java
index 50015e653399..93be66ad4882 100644
--- a/packages/SettingsLib/src/com/android/settingslib/users/AvatarPickerActivity.java
+++ b/packages/SettingsLib/src/com/android/settingslib/users/AvatarPickerActivity.java
@@ -45,6 +45,7 @@ import com.google.android.setupdesign.GlifLayout;
import com.google.android.setupdesign.util.ThemeHelper;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
/**
@@ -180,6 +181,7 @@ public class AvatarPickerActivity extends Activity {
private final int mPreselectedImageStartPosition;
private final List<Drawable> mImageDrawables;
+ private final List<String> mImageDescriptions;
private final TypedArray mPreselectedImages;
private final int[] mUserIconColors;
private int mSelectedPosition = NONE;
@@ -196,6 +198,7 @@ public class AvatarPickerActivity extends Activity {
mPreselectedImages = getResources().obtainTypedArray(R.array.avatar_images);
mUserIconColors = UserIcons.getUserIconColors(getResources());
mImageDrawables = buildDrawableList();
+ mImageDescriptions = buildDescriptionsList();
}
@NonNull
@@ -210,15 +213,24 @@ public class AvatarPickerActivity extends Activity {
public void onBindViewHolder(@NonNull AvatarViewHolder viewHolder, int position) {
if (position == mTakePhotoPosition) {
viewHolder.setDrawable(getDrawable(R.drawable.avatar_take_photo_circled));
+ viewHolder.setContentDescription(getString(R.string.user_image_take_photo));
viewHolder.setClickListener(view -> mAvatarPhotoController.takePhoto());
} else if (position == mChoosePhotoPosition) {
viewHolder.setDrawable(getDrawable(R.drawable.avatar_choose_photo_circled));
+ viewHolder.setContentDescription(getString(R.string.user_image_choose_photo));
viewHolder.setClickListener(view -> mAvatarPhotoController.choosePhoto());
} else if (position >= mPreselectedImageStartPosition) {
+ int index = indexFromPosition(position);
viewHolder.setSelected(position == mSelectedPosition);
- viewHolder.setDrawable(mImageDrawables.get(indexFromPosition(position)));
+ viewHolder.setDrawable(mImageDrawables.get(index));
+ if (mImageDescriptions != null) {
+ viewHolder.setContentDescription(mImageDescriptions.get(index));
+ } else {
+ viewHolder.setContentDescription(
+ getString(R.string.default_user_icon_description));
+ }
viewHolder.setClickListener(view -> {
if (mSelectedPosition == position) {
deselect(position);
@@ -256,6 +268,15 @@ public class AvatarPickerActivity extends Activity {
return result;
}
+ private List<String> buildDescriptionsList() {
+ if (mPreselectedImages.length() > 0) {
+ return Arrays.asList(
+ getResources().getStringArray(R.array.avatar_image_descriptions));
+ }
+
+ return null;
+ }
+
private Drawable circularDrawableFrom(BitmapDrawable drawable) {
Bitmap bitmap = drawable.getBitmap();
@@ -323,6 +344,10 @@ public class AvatarPickerActivity extends Activity {
mImageView.setImageDrawable(drawable);
}
+ public void setContentDescription(String desc) {
+ mImageView.setContentDescription(desc);
+ }
+
public void setClickListener(View.OnClickListener listener) {
mImageView.setOnClickListener(listener);
}
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 27fc6ba47ec9..ca90fbedd4e0 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -192,6 +192,9 @@
<uses-permission android:name="android.permission.REVOKE_RUNTIME_PERMISSIONS" />
<uses-permission android:name="android.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS" />
<uses-permission android:name="android.permission.WHITELIST_RESTRICTED_PERMISSIONS" />
+ <!-- Permission required for processes that don't own the focused window to switch
+ touch mode state -->
+ <uses-permission android:name="android.permission.MODIFY_TOUCH_MODE_STATE" />
<!-- Permission required to test onPermissionsChangedListener -->
<uses-permission android:name="android.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS" />
<uses-permission android:name="android.permission.SET_KEYBOARD_LAYOUT" />
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 59893817da6f..f83431b58c62 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -308,6 +308,7 @@
<!-- To change system language (HDMI CEC) -->
<uses-permission android:name="android.permission.CHANGE_CONFIGURATION" />
+ <uses-permission android:name="android.permission.SUPPRESS_CLIPBOARD_ACCESS_NOTIFICATION" />
<protected-broadcast android:name="com.android.settingslib.action.REGISTER_SLICE_RECEIVER" />
<protected-broadcast android:name="com.android.settingslib.action.UNREGISTER_SLICE_RECEIVER" />
@@ -878,6 +879,12 @@
android:name=".media.taptotransfer.sender.MediaTttSenderService"
/>
+ <!-- Service for external clients to notify us of nearby media devices -->
+ <!-- TODO(b/216313420): Export and guard with a permission. -->
+ <service
+ android:name=".media.nearby.NearbyMediaDevicesService"
+ />
+
<receiver
android:name=".tuner.TunerService$ClearReceiver"
android:exported="false">
diff --git a/packages/SystemUI/TEST_MAPPING b/packages/SystemUI/TEST_MAPPING
index dee4ff5a0bf5..9722b1fe2d2e 100644
--- a/packages/SystemUI/TEST_MAPPING
+++ b/packages/SystemUI/TEST_MAPPING
@@ -1,7 +1,7 @@
{
// Looking for unit test presubmit configuration?
// This currently lives in ATP config apct/system_ui/unit_test
- "presubmit": [
+ "presubmit-large": [
{
"name": "PlatformScenarioTests",
"options": [
@@ -24,7 +24,9 @@
"exclude-annotation": "android.platform.test.scenario.annotation.FoldableOnly"
}
]
- },
+ }
+ ],
+ "presubmit": [
{
"name": "SystemUIGoogleTests",
"options": [
diff --git a/packages/SystemUI/res/drawable/action_chip_background.xml b/packages/SystemUI/res/drawable/action_chip_background.xml
index eeff39b7a8fd..745470f4c61a 100644
--- a/packages/SystemUI/res/drawable/action_chip_background.xml
+++ b/packages/SystemUI/res/drawable/action_chip_background.xml
@@ -17,11 +17,11 @@
<ripple
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
- android:color="@color/screenshot_button_ripple">
+ android:color="@color/overlay_button_ripple">
<item android:id="@android:id/background">
<shape android:shape="rectangle">
<solid android:color="?androidprv:attr/colorAccentSecondary"/>
- <corners android:radius="@dimen/screenshot_button_corner_radius"/>
+ <corners android:radius="@dimen/overlay_button_corner_radius"/>
</shape>
</item>
</ripple>
diff --git a/packages/SystemUI/res/drawable/action_chip_container_background.xml b/packages/SystemUI/res/drawable/action_chip_container_background.xml
index 72767a12bcf5..36083f1f0408 100644
--- a/packages/SystemUI/res/drawable/action_chip_container_background.xml
+++ b/packages/SystemUI/res/drawable/action_chip_container_background.xml
@@ -19,5 +19,5 @@
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
android:shape="rectangle">
<solid android:color="?androidprv:attr/colorSurface"/>
- <corners android:radius="@dimen/screenshot_action_container_corner_radius"/>
+ <corners android:radius="@dimen/overlay_action_container_corner_radius"/>
</shape>
diff --git a/packages/SystemUI/res/drawable/auth_dialog_enterprise.xml b/packages/SystemUI/res/drawable/auth_dialog_enterprise.xml
index c547c52a4077..ec9465b20d61 100644
--- a/packages/SystemUI/res/drawable/auth_dialog_enterprise.xml
+++ b/packages/SystemUI/res/drawable/auth_dialog_enterprise.xml
@@ -20,6 +20,6 @@
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
- android:pathData="M20,6h-4L16,4c0,-1.11 -0.89,-2 -2,-2h-4c-1.11,0 -2,0.89 -2,2v2L4,6c-1.11,0 -1.99,0.89 -1.99,2L2,19c0,1.11 0.89,2 2,2h16c1.11,0 2,-0.89 2,-2L22,8c0,-1.11 -0.89,-2 -2,-2zM12,15c-1.1,0 -2,-0.9 -2,-2s0.9,-2 2,-2 2,0.9 2,2 -0.9,2 -2,2zM14,6h-4L10,4h4v2z"
+ android:pathData="@*android:string/config_work_badge_path_24"
android:fillColor="?android:attr/colorAccent"/>
</vector> \ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/screenshot_actions_background_protection.xml b/packages/SystemUI/res/drawable/overlay_actions_background_protection.xml
index dd818a068d61..d8f56324566d 100644
--- a/packages/SystemUI/res/drawable/screenshot_actions_background_protection.xml
+++ b/packages/SystemUI/res/drawable/overlay_actions_background_protection.xml
@@ -17,6 +17,6 @@
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
<gradient
android:angle="90"
- android:startColor="@color/screenshot_background_protection_start"
+ android:startColor="@color/overlay_background_protection_start"
android:endColor="#00000000"/>
</shape> \ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/screenshot_button_background.xml b/packages/SystemUI/res/drawable/overlay_button_background.xml
index 3c39fe2ecb06..3c39fe2ecb06 100644
--- a/packages/SystemUI/res/drawable/screenshot_button_background.xml
+++ b/packages/SystemUI/res/drawable/overlay_button_background.xml
diff --git a/packages/SystemUI/res/layout/auth_credential_password_view.xml b/packages/SystemUI/res/layout/auth_credential_password_view.xml
index 1e0ce0026d8e..0ff1db2ef694 100644
--- a/packages/SystemUI/res/layout/auth_credential_password_view.xml
+++ b/packages/SystemUI/res/layout/auth_credential_password_view.xml
@@ -18,64 +18,72 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:orientation="vertical"
- android:gravity="center_horizontal"
- android:elevation="@dimen/biometric_dialog_elevation">
+ android:elevation="@dimen/biometric_dialog_elevation"
+ android:orientation="vertical">
- <Space
- android:layout_width="0dp"
- android:layout_height="0dp"
- android:layout_weight="1"/>
+ <RelativeLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
- <ImageView
- android:id="@+id/icon"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"/>
+ <LinearLayout
+ android:id="@+id/auth_credential_header"
+ style="@style/AuthCredentialHeaderStyle"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_alignParentTop="true">
- <TextView
- android:id="@+id/title"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- style="@style/TextAppearance.AuthCredential.Title"/>
+ <ImageView
+ android:id="@+id/icon"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:contentDescription="@null" />
- <TextView
- android:id="@+id/subtitle"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- style="@style/TextAppearance.AuthCredential.Subtitle"/>
+ <TextView
+ android:id="@+id/title"
+ style="@style/TextAppearance.AuthNonBioCredential.Title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
- <TextView
- android:id="@+id/description"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- style="@style/TextAppearance.AuthCredential.Description"/>
+ <TextView
+ android:id="@+id/subtitle"
+ style="@style/TextAppearance.AuthNonBioCredential.Subtitle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
- <Space
- android:layout_width="0dp"
- android:layout_height="0dp"
- android:layout_weight="1"/>
+ <TextView
+ android:id="@+id/description"
+ style="@style/TextAppearance.AuthNonBioCredential.Description"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
- <ImeAwareEditText
- android:id="@+id/lockPassword"
- android:layout_width="208dp"
- android:layout_height="wrap_content"
- android:layout_gravity="center_horizontal"
- android:minHeight="48dp"
- android:gravity="center"
- android:inputType="textPassword"
- android:maxLength="500"
- android:imeOptions="actionNext|flagNoFullscreen|flagForceAscii"
- style="@style/TextAppearance.AuthCredential.PasswordEntry"/>
+ </LinearLayout>
- <TextView
- android:id="@+id/error"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- style="@style/TextAppearance.AuthCredential.Error"/>
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:gravity="center"
+ android:orientation="vertical"
+ android:layout_alignParentBottom="true">
+
+ <ImeAwareEditText
+ android:id="@+id/lockPassword"
+ style="@style/TextAppearance.AuthCredential.PasswordEntry"
+ android:layout_width="208dp"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:imeOptions="actionNext|flagNoFullscreen|flagForceAscii"
+ android:inputType="textPassword"
+ android:minHeight="48dp" />
+
+ <TextView
+ android:id="@+id/error"
+ style="@style/TextAppearance.AuthNonBioCredential.Error"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
+
+ </LinearLayout>
- <Space
- android:layout_width="0dp"
- android:layout_height="0dp"
- android:layout_weight="5"/>
+ </RelativeLayout>
</com.android.systemui.biometrics.AuthCredentialPasswordView> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/auth_credential_pattern_view.xml b/packages/SystemUI/res/layout/auth_credential_pattern_view.xml
index 4939ea2c99ee..dada9813c320 100644
--- a/packages/SystemUI/res/layout/auth_credential_pattern_view.xml
+++ b/packages/SystemUI/res/layout/auth_credential_pattern_view.xml
@@ -22,76 +22,81 @@
android:gravity="center_horizontal"
android:elevation="@dimen/biometric_dialog_elevation">
- <Space
- android:layout_width="0dp"
- android:layout_height="0dp"
- android:layout_weight="1"/>
-
- <ImageView
- android:id="@+id/icon"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"/>
-
- <TextView
- android:id="@+id/title"
+ <RelativeLayout
android:layout_width="match_parent"
- android:layout_height="wrap_content"
- style="@style/TextAppearance.AuthCredential.Title"/>
+ android:layout_height="match_parent"
+ android:orientation="vertical">
- <TextView
- android:id="@+id/subtitle"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- style="@style/TextAppearance.AuthCredential.Subtitle"/>
+ <LinearLayout
+ android:id="@+id/auth_credential_header"
+ style="@style/AuthCredentialHeaderStyle"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
- <TextView
- android:id="@+id/description"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- style="@style/TextAppearance.AuthCredential.Description"/>
+ <ImageView
+ android:id="@+id/icon"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:contentDescription="@null" />
- <Space
- android:layout_width="0dp"
- android:layout_height="0dp"
- android:layout_weight="1"/>
+ <TextView
+ android:id="@+id/title"
+ style="@style/TextAppearance.AuthNonBioCredential.Title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical"
- android:gravity="center"
- android:paddingLeft="0dp"
- android:paddingRight="0dp"
- android:paddingTop="0dp"
- android:paddingBottom="16dp"
- android:clipToPadding="false">
-
- <FrameLayout
- android:layout_width="wrap_content"
- android:layout_height="0dp"
- android:layout_weight="1"
- style="@style/LockPatternContainerStyle">
-
- <com.android.internal.widget.LockPatternView
- android:id="@+id/lockPattern"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_gravity="center"
- style="@style/LockPatternStyleBiometricPrompt"/>
+ <TextView
+ android:id="@+id/subtitle"
+ style="@style/TextAppearance.AuthNonBioCredential.Subtitle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+
+ <TextView
+ android:id="@+id/description"
+ style="@style/TextAppearance.AuthNonBioCredential.Description"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/auth_credential_header"
+ android:gravity="center"
+ android:orientation="vertical"
+ android:paddingBottom="16dp"
+ android:paddingTop="60dp">
+
+ <FrameLayout
+ style="@style/LockPatternContainerStyle"
+ android:layout_width="wrap_content"
+ android:layout_height="0dp"
+ android:layout_weight="1">
+
+ <com.android.internal.widget.LockPatternView
+ android:id="@+id/lockPattern"
+ style="@style/LockPatternStyle"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_gravity="center" />
- </FrameLayout>
+ </FrameLayout>
- <TextView
- android:id="@+id/error"
+ </LinearLayout>
+
+ <LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
- style="@style/TextAppearance.AuthCredential.Error"/>
+ android:layout_alignParentBottom="true">
+
+ <TextView
+ android:id="@+id/error"
+ style="@style/TextAppearance.AuthNonBioCredential.Error"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
- </LinearLayout>
+ </LinearLayout>
- <Space
- android:layout_width="0dp"
- android:layout_height="0dp"
- android:layout_weight="1"/>
+ </RelativeLayout>
</com.android.systemui.biometrics.AuthCredentialPatternView> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/clipboard_overlay.xml b/packages/SystemUI/res/layout/clipboard_overlay.xml
index 7e31909613ee..4817d453ba0b 100644
--- a/packages/SystemUI/res/layout/clipboard_overlay.xml
+++ b/packages/SystemUI/res/layout/clipboard_overlay.xml
@@ -17,7 +17,7 @@
<com.android.systemui.clipboardoverlay.DraggableConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
- android:theme="@style/Screenshot"
+ android:theme="@style/FloatingOverlay"
android:alpha="0"
android:layout_width="match_parent"
android:layout_height="match_parent">
@@ -28,7 +28,7 @@
android:layout_width="0dp"
android:elevation="1dp"
android:background="@drawable/action_chip_container_background"
- android:layout_marginStart="@dimen/screenshot_action_container_margin_horizontal"
+ android:layout_marginStart="@dimen/overlay_action_container_margin_horizontal"
app:layout_constraintBottom_toBottomOf="@+id/actions_container"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/actions_container"
@@ -37,9 +37,9 @@
android:id="@+id/actions_container"
android:layout_width="0dp"
android:layout_height="wrap_content"
- android:layout_marginEnd="@dimen/screenshot_action_container_margin_horizontal"
- android:paddingEnd="@dimen/screenshot_action_container_padding_right"
- android:paddingVertical="@dimen/screenshot_action_container_padding_vertical"
+ android:layout_marginEnd="@dimen/overlay_action_container_margin_horizontal"
+ android:paddingEnd="@dimen/overlay_action_container_padding_right"
+ android:paddingVertical="@dimen/overlay_action_container_padding_vertical"
android:elevation="1dp"
android:scrollbars="none"
app:layout_constraintHorizontal_bias="0"
@@ -53,9 +53,9 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:animateLayoutChanges="true">
- <include layout="@layout/screenshot_action_chip"
+ <include layout="@layout/overlay_action_chip"
android:id="@+id/remote_copy_chip"/>
- <include layout="@layout/screenshot_action_chip"
+ <include layout="@layout/overlay_action_chip"
android:id="@+id/edit_chip"/>
</LinearLayout>
</HorizontalScrollView>
diff --git a/packages/SystemUI/res/layout/long_screenshot.xml b/packages/SystemUI/res/layout/long_screenshot.xml
index 856697c5673d..cdf61036e2b7 100644
--- a/packages/SystemUI/res/layout/long_screenshot.xml
+++ b/packages/SystemUI/res/layout/long_screenshot.xml
@@ -18,7 +18,6 @@
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
- xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
android:background="?android:colorBackgroundFloating"
android:id="@+id/root"
android:layout_width="match_parent"
@@ -32,7 +31,7 @@
android:text="@string/save"
android:layout_marginStart="8dp"
android:layout_marginTop="@dimen/long_screenshot_action_bar_top_margin"
- android:background="@drawable/screenshot_button_background"
+ android:background="@drawable/overlay_button_background"
android:textColor="?android:textColorSecondary"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
@@ -46,7 +45,7 @@
android:text="@android:string/cancel"
android:layout_marginStart="6dp"
android:layout_marginTop="@dimen/long_screenshot_action_bar_top_margin"
- android:background="@drawable/screenshot_button_background"
+ android:background="@drawable/overlay_button_background"
android:textColor="?android:textColorSecondary"
app:layout_constraintStart_toEndOf="@id/save"
app:layout_constraintTop_toTopOf="parent"
diff --git a/packages/SystemUI/res/layout/screenshot_action_chip.xml b/packages/SystemUI/res/layout/overlay_action_chip.xml
index b80469febf3c..6d2d93124234 100644
--- a/packages/SystemUI/res/layout/screenshot_action_chip.xml
+++ b/packages/SystemUI/res/layout/overlay_action_chip.xml
@@ -14,33 +14,33 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-<com.android.systemui.screenshot.ScreenshotActionChip
+<com.android.systemui.screenshot.OverlayActionChip
xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/screenshot_action_chip"
+ android:id="@+id/overlay_action_chip"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginStart="@dimen/screenshot_action_chip_margin_start"
- android:paddingVertical="@dimen/screenshot_action_chip_margin_vertical"
+ android:layout_marginStart="@dimen/overlay_action_chip_margin_start"
+ android:paddingVertical="@dimen/overlay_action_chip_margin_vertical"
android:layout_gravity="center"
android:gravity="center"
android:alpha="0.0">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:paddingVertical="@dimen/screenshot_action_chip_padding_vertical"
+ android:paddingVertical="@dimen/overlay_action_chip_padding_vertical"
android:background="@drawable/action_chip_background"
android:gravity="center">
<ImageView
- android:id="@+id/screenshot_action_chip_icon"
- android:tint="?android:attr/textColorPrimary"
- android:layout_width="@dimen/screenshot_action_chip_icon_size"
- android:layout_height="@dimen/screenshot_action_chip_icon_size"/>
+ android:id="@+id/overlay_action_chip_icon"
+ android:tint="?attr/overlayButtonTextColor"
+ android:layout_width="@dimen/overlay_action_chip_icon_size"
+ android:layout_height="@dimen/overlay_action_chip_icon_size"/>
<TextView
- android:id="@+id/screenshot_action_chip_text"
+ android:id="@+id/overlay_action_chip_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@*android:string/config_headlineFontFamilyMedium"
- android:textSize="@dimen/screenshot_action_chip_text_size"
- android:textColor="?android:attr/textColorPrimary"/>
+ android:textSize="@dimen/overlay_action_chip_text_size"
+ android:textColor="?attr/overlayButtonTextColor"/>
</LinearLayout>
-</com.android.systemui.screenshot.ScreenshotActionChip>
+</com.android.systemui.screenshot.OverlayActionChip>
diff --git a/packages/SystemUI/res/layout/screenshot.xml b/packages/SystemUI/res/layout/screenshot.xml
index 227212bd4634..890dbe592fc7 100644
--- a/packages/SystemUI/res/layout/screenshot.xml
+++ b/packages/SystemUI/res/layout/screenshot.xml
@@ -17,7 +17,7 @@
<com.android.systemui.screenshot.ScreenshotView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/screenshot_frame"
- android:theme="@style/Screenshot"
+ android:theme="@style/FloatingOverlay"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:importantForAccessibility="no">
@@ -30,11 +30,11 @@
android:importantForAccessibility="no"/>
<ImageView
android:id="@+id/screenshot_actions_background"
- android:layout_height="@dimen/screenshot_bg_protection_height"
+ android:layout_height="@dimen/overlay_bg_protection_height"
android:layout_width="match_parent"
android:layout_gravity="bottom"
android:alpha="0.0"
- android:src="@drawable/screenshot_actions_background_protection"/>
+ android:src="@drawable/overlay_actions_background_protection"/>
<ImageView
android:id="@+id/screenshot_flash"
android:layout_width="match_parent"
diff --git a/packages/SystemUI/res/layout/screenshot_static.xml b/packages/SystemUI/res/layout/screenshot_static.xml
index 8f791c34419d..813bb6018801 100644
--- a/packages/SystemUI/res/layout/screenshot_static.xml
+++ b/packages/SystemUI/res/layout/screenshot_static.xml
@@ -26,7 +26,7 @@
android:layout_width="0dp"
android:elevation="1dp"
android:background="@drawable/action_chip_container_background"
- android:layout_marginStart="@dimen/screenshot_action_container_margin_horizontal"
+ android:layout_marginStart="@dimen/overlay_action_container_margin_horizontal"
app:layout_constraintBottom_toBottomOf="@+id/screenshot_actions_container"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/screenshot_actions_container"
@@ -35,9 +35,9 @@
android:id="@+id/screenshot_actions_container"
android:layout_width="0dp"
android:layout_height="wrap_content"
- android:layout_marginEnd="@dimen/screenshot_action_container_margin_horizontal"
- android:paddingEnd="@dimen/screenshot_action_container_padding_right"
- android:paddingVertical="@dimen/screenshot_action_container_padding_vertical"
+ android:layout_marginEnd="@dimen/overlay_action_container_margin_horizontal"
+ android:paddingEnd="@dimen/overlay_action_container_padding_right"
+ android:paddingVertical="@dimen/overlay_action_container_padding_vertical"
android:elevation="1dp"
android:scrollbars="none"
app:layout_constraintHorizontal_bias="0"
@@ -50,11 +50,11 @@
android:id="@+id/screenshot_actions"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
- <include layout="@layout/screenshot_action_chip"
+ <include layout="@layout/overlay_action_chip"
android:id="@+id/screenshot_share_chip"/>
- <include layout="@layout/screenshot_action_chip"
+ <include layout="@layout/overlay_action_chip"
android:id="@+id/screenshot_edit_chip"/>
- <include layout="@layout/screenshot_action_chip"
+ <include layout="@layout/overlay_action_chip"
android:id="@+id/screenshot_scroll_chip"
android:visibility="gone" />
</LinearLayout>
@@ -89,7 +89,7 @@
<ImageView
android:id="@+id/screenshot_preview"
android:visibility="invisible"
- android:layout_width="@dimen/screenshot_x_scale"
+ android:layout_width="@dimen/overlay_x_scale"
android:layout_margin="@dimen/overlay_border_width"
android:layout_height="wrap_content"
android:layout_gravity="center"
diff --git a/packages/SystemUI/res/values-night/colors.xml b/packages/SystemUI/res/values-night/colors.xml
index 3412722776c2..b318bbc157ca 100644
--- a/packages/SystemUI/res/values-night/colors.xml
+++ b/packages/SystemUI/res/values-night/colors.xml
@@ -58,9 +58,9 @@
<!-- The color of the text in the Global Actions menu -->
<color name="global_actions_alert_text">@color/GM2_red_300</color>
- <!-- Global screenshot actions -->
- <color name="screenshot_button_ripple">#42FFFFFF</color>
- <color name="screenshot_background_protection_start">#80000000</color> <!-- 50% black -->
+ <!-- Floating overlay actions -->
+ <color name="overlay_button_ripple">#42FFFFFF</color>
+ <color name="overlay_background_protection_start">#80000000</color> <!-- 50% black -->
<!-- Media -->
<color name="media_divider">#85ffffff</color>
diff --git a/packages/SystemUI/res/values-night/styles.xml b/packages/SystemUI/res/values-night/styles.xml
index 1f815b79ec30..f7261e70a610 100644
--- a/packages/SystemUI/res/values-night/styles.xml
+++ b/packages/SystemUI/res/values-night/styles.xml
@@ -47,8 +47,8 @@
<item name="android:textColorSecondary">?android:attr/textColorPrimaryInverse</item>
</style>
- <style name="Screenshot" parent="@android:style/Theme.DeviceDefault.DayNight">
- <item name="android:textColorPrimary">?android:attr/textColorPrimaryInverse</item>
+ <style name="FloatingOverlay" parent="@android:style/Theme.DeviceDefault.DayNight">
+ <item name="overlayButtonTextColor">?android:attr/textColorPrimaryInverse</item>
</style>
<style name="Theme.PeopleTileConfigActivity" parent="@style/Theme.SystemUI">
diff --git a/packages/SystemUI/res/values/attrs.xml b/packages/SystemUI/res/values/attrs.xml
index de136de9dd5f..e6ab0ff9bd73 100644
--- a/packages/SystemUI/res/values/attrs.xml
+++ b/packages/SystemUI/res/values/attrs.xml
@@ -204,5 +204,7 @@
<attr name="singleLineVerticalPadding" format="dimension" />
<attr name="textViewId" format="reference" />
</declare-styleable>
+
+ <attr name="overlayButtonTextColor" format="color" />
</resources>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 81e3e04b279e..3ab569a19c0c 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -138,9 +138,9 @@
<color name="udfps_enroll_progress">#7DA7F1</color>
<color name="udfps_enroll_progress_help">#ffEE675C</color>
- <!-- Global screenshot actions -->
- <color name="screenshot_button_ripple">#1f000000</color>
- <color name="screenshot_background_protection_start">#40000000</color> <!-- 25% black -->
+ <!-- Floating overlay actions -->
+ <color name="overlay_button_ripple">#1f000000</color>
+ <color name="overlay_background_protection_start">#40000000</color> <!-- 25% black -->
<!-- GM2 colors -->
<color name="GM2_grey_100">#F1F3F4</color>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index bba616fe24a2..74bb9e45a6f2 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -258,36 +258,36 @@
<!-- Dimensions related to screenshots -->
- <!-- The padding on the global screenshot background image -->
- <dimen name="screenshot_x_scale">80dp</dimen>
- <dimen name="screenshot_bg_protection_height">242dp</dimen>
- <dimen name="screenshot_action_container_corner_radius">18dp</dimen>
- <dimen name="screenshot_action_container_padding_vertical">4dp</dimen>
- <dimen name="screenshot_action_container_margin_horizontal">8dp</dimen>
- <dimen name="screenshot_action_container_padding_right">8dp</dimen>
- <!-- Radius of the chip background on global screenshot actions -->
- <dimen name="screenshot_button_corner_radius">8dp</dimen>
+
+ <dimen name="screenshot_crop_handle_thickness">3dp</dimen>
+ <dimen name="long_screenshot_action_bar_top_margin">8dp</dimen>
+
+ <!-- Dimensions shared between "overlays" (clipboard and screenshot preview UIs) -->
+ <!-- Constrained size of the floating overlay preview -->
+ <dimen name="overlay_x_scale">80dp</dimen>
+ <!-- Radius of the chip background on floating overlay actions -->
+ <dimen name="overlay_button_corner_radius">8dp</dimen>
<!-- Margin between successive chips -->
- <dimen name="screenshot_action_chip_margin_start">8dp</dimen>
+ <dimen name="overlay_action_chip_margin_start">8dp</dimen>
<!-- Padding to make tappable chip height 48dp (18+11+11+4+4) -->
- <dimen name="screenshot_action_chip_margin_vertical">4dp</dimen>
- <dimen name="screenshot_action_chip_padding_vertical">11dp</dimen>
- <dimen name="screenshot_action_chip_icon_size">18sp</dimen>
+ <dimen name="overlay_action_chip_margin_vertical">4dp</dimen>
+ <dimen name="overlay_action_chip_padding_vertical">11dp</dimen>
+ <dimen name="overlay_action_chip_icon_size">18sp</dimen>
<!-- Padding on each side of the icon for icon-only chips -->
- <dimen name="screenshot_action_chip_icon_only_padding_horizontal">14dp</dimen>
+ <dimen name="overlay_action_chip_icon_only_padding_horizontal">14dp</dimen>
<!-- Padding at the edges of the chip for icon-and-text chips -->
- <dimen name="screenshot_action_chip_padding_horizontal">12dp</dimen>
+ <dimen name="overlay_action_chip_padding_horizontal">12dp</dimen>
<!-- Spacing between chip icon and chip text -->
- <dimen name="screenshot_action_chip_spacing">8dp</dimen>
- <dimen name="screenshot_action_chip_text_size">14sp</dimen>
- <dimen name="screenshot_dismissal_height_delta">80dp</dimen>
- <dimen name="screenshot_crop_handle_thickness">3dp</dimen>
- <dimen name="long_screenshot_action_bar_top_margin">8dp</dimen>
-
- <!-- Dimensions shared between "overlays" (clipboard and screenshot preview UIs) -->
+ <dimen name="overlay_action_chip_spacing">8dp</dimen>
+ <dimen name="overlay_action_chip_text_size">14sp</dimen>
<dimen name="overlay_offset_y">8dp</dimen>
<dimen name="overlay_offset_x">16dp</dimen>
<dimen name="overlay_preview_elevation">4dp</dimen>
+ <dimen name="overlay_action_container_margin_horizontal">8dp</dimen>
+ <dimen name="overlay_bg_protection_height">242dp</dimen>
+ <dimen name="overlay_action_container_corner_radius">18dp</dimen>
+ <dimen name="overlay_action_container_padding_vertical">4dp</dimen>
+ <dimen name="overlay_action_container_padding_right">8dp</dimen>
<dimen name="overlay_dismiss_button_elevation">7dp</dimen>
<dimen name="overlay_dismiss_button_tappable_size">48dp</dimen>
<dimen name="overlay_dismiss_button_margin">8dp</dimen>
@@ -295,7 +295,7 @@
<!-- need a negative margin for some of the constraints. should be overlay_border_width * -1 -->
<dimen name="overlay_border_width_neg">-4dp</dimen>
- <dimen name="clipboard_preview_size">@dimen/screenshot_x_scale</dimen>
+ <dimen name="clipboard_preview_size">@dimen/overlay_x_scale</dimen>
<!-- The width of the view containing navigation buttons -->
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 57f1f3f1606c..590cc9b4eb0a 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -236,6 +236,41 @@
<item name="android:textColor">?android:attr/colorError</item>
</style>
+ <style name="TextAppearance.AuthNonBioCredential"
+ parent="@android:style/TextAppearance.DeviceDefault">
+ <item name="android:accessibilityLiveRegion">polite</item>
+ <item name="android:textAlignment">gravity</item>
+ <item name="android:layout_gravity">top</item>
+ <item name="android:textColor">?android:attr/textColorPrimary</item>
+ </style>
+
+ <style name="TextAppearance.AuthNonBioCredential.Title">
+ <item name="android:fontFamily">google-sans</item>
+ <item name="android:layout_marginTop">20dp</item>
+ <item name="android:textSize">36sp</item>
+ </style>
+
+ <style name="TextAppearance.AuthNonBioCredential.Subtitle">
+ <item name="android:fontFamily">google-sans</item>
+ <item name="android:layout_marginTop">20dp</item>
+ <item name="android:textSize">18sp</item>
+ </style>
+
+ <style name="TextAppearance.AuthNonBioCredential.Description">
+ <item name="android:fontFamily">google-sans</item>
+ <item name="android:layout_marginTop">20dp</item>
+ <item name="android:textSize">16sp</item>
+ </style>
+
+ <style name="TextAppearance.AuthNonBioCredential.Error">
+ <item name="android:paddingTop">6dp</item>
+ <item name="android:paddingBottom">18dp</item>
+ <item name="android:paddingHorizontal">24dp</item>
+ <item name="android:textSize">14sp</item>
+ <item name="android:textColor">?android:attr/colorError</item>
+ <item name="android:gravity">center</item>
+ </style>
+
<style name="TextAppearance.AuthCredential.PasswordEntry" parent="@android:style/TextAppearance.DeviceDefault">
<item name="android:gravity">center</item>
<item name="android:singleLine">true</item>
@@ -243,6 +278,15 @@
<item name="android:textSize">24sp</item>
</style>
+ <style name="AuthCredentialHeaderStyle">
+ <item name="android:paddingStart">48dp</item>
+ <item name="android:paddingEnd">24dp</item>
+ <item name="android:paddingTop">28dp</item>
+ <item name="android:paddingBottom">20dp</item>
+ <item name="android:orientation">vertical</item>
+ <item name="android:layout_gravity">top</item>
+ </style>
+
<style name="DeviceManagementDialogTitle">
<item name="android:gravity">center</item>
<item name="android:textAppearance">@style/TextAppearance.DeviceManagementDialog.Title</item>
@@ -307,9 +351,8 @@
<item name="android:maxWidth">420dp</item>
<item name="android:minHeight">0dp</item>
<item name="android:minWidth">0dp</item>
- <item name="android:paddingBottom">0dp</item>
- <item name="android:paddingHorizontal">44dp</item>
- <item name="android:paddingTop">0dp</item>
+ <item name="android:paddingHorizontal">60dp</item>
+ <item name="android:paddingBottom">40dp</item>
</style>
<style name="LockPatternStyle">
@@ -664,7 +707,9 @@
<item name="android:windowActivityTransitions">true</item>
</style>
- <style name="Screenshot" parent="@android:style/Theme.DeviceDefault.DayNight"/>
+ <style name="FloatingOverlay" parent="@android:style/Theme.DeviceDefault.DayNight">
+ <item name="overlayButtonTextColor">?android:attr/textColorPrimary</item>
+ </style>
<!-- Clipboard overlay's edit text activity. -->
<style name="EditTextActivity" parent="@android:style/Theme.DeviceDefault.DayNight">
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/animation/UnfoldMoveFromCenterAnimator.kt b/packages/SystemUI/shared/src/com/android/systemui/shared/animation/UnfoldMoveFromCenterAnimator.kt
index 9010d5154156..fc6bb500562e 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/animation/UnfoldMoveFromCenterAnimator.kt
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/animation/UnfoldMoveFromCenterAnimator.kt
@@ -42,7 +42,9 @@ class UnfoldMoveFromCenterAnimator @JvmOverloads constructor(
* are different than actual bounds (e.g. view container may
* have larger width than width of the items in the container)
*/
- private val viewCenterProvider: ViewCenterProvider = object : ViewCenterProvider {}
+ private val viewCenterProvider: ViewCenterProvider = object : ViewCenterProvider {},
+ /** Allows to set the alpha based on the progress. */
+ private val alphaProvider: AlphaProvider? = null
) : UnfoldTransitionProgressProvider.TransitionProgressListener {
private val screenSize = Point()
@@ -99,17 +101,27 @@ class UnfoldMoveFromCenterAnimator @JvmOverloads constructor(
override fun onTransitionProgress(progress: Float) {
animatedViews.forEach {
- it.view.get()?.let { view ->
- translationApplier.apply(
- view = view,
- x = it.startTranslationX * (1 - progress),
- y = it.startTranslationY * (1 - progress)
- )
- }
+ it.applyTransition(progress)
+ it.applyAlpha(progress)
}
lastAnimationProgress = progress
}
+ private fun AnimatedView.applyTransition(progress: Float) {
+ view.get()?.let { view ->
+ translationApplier.apply(
+ view = view,
+ x = startTranslationX * (1 - progress),
+ y = startTranslationY * (1 - progress)
+ )
+ }
+ }
+
+ private fun AnimatedView.applyAlpha(progress: Float) {
+ if (alphaProvider == null) return
+ view.get()?.alpha = alphaProvider.getAlpha(progress)
+ }
+
private fun createAnimatedView(view: View): AnimatedView =
AnimatedView(view = WeakReference(view)).updateAnimatedView(view)
@@ -146,6 +158,13 @@ class UnfoldMoveFromCenterAnimator @JvmOverloads constructor(
}
}
+ /** Allows to set a custom alpha based on the progress. */
+ interface AlphaProvider {
+
+ /** Returns the alpha views should have at a given progress. */
+ fun getAlpha(progress: Float): Float
+ }
+
/**
* Interface that allows to use custom logic to get the center of the view
*/
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/media/INearbyMediaDevicesProvider.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/media/INearbyMediaDevicesProvider.aidl
new file mode 100644
index 000000000000..6db06f046c55
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/media/INearbyMediaDevicesProvider.aidl
@@ -0,0 +1,43 @@
+/*
+ * 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.shared.media;
+
+import com.android.systemui.shared.media.INearbyMediaDevicesUpdateCallback;
+import com.android.systemui.shared.media.NearbyDevice;
+
+/**
+ * An interface that provides information about nearby devices that are able to play media.
+ *
+ * External clients will implement this interface and System UI will invoke it if it's passed to
+ * SystemUI via {@link INearbyMediaDevicesService.registerProvider}.
+ */
+interface INearbyMediaDevicesProvider {
+ /**
+ * Returns a list of nearby devices that are able to play media.
+ */
+ List<NearbyDevice> getCurrentNearbyDevices() = 1;
+
+ /**
+ * Registers a callback that will be notified each time the status of a nearby device changes.
+ */
+ oneway void registerNearbyDevicesCallback(in INearbyMediaDevicesUpdateCallback callback) = 2;
+
+ /**
+ * Unregisters a callback. See {@link registerNearbyDevicesCallback}.
+ */
+ oneway void unregisterNearbyDevicesCallback(in INearbyMediaDevicesUpdateCallback callback) = 3;
+}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/media/INearbyMediaDevicesService.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/media/INearbyMediaDevicesService.aidl
new file mode 100644
index 000000000000..4f3e10d801f0
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/media/INearbyMediaDevicesService.aidl
@@ -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.systemui.shared.media;
+
+import com.android.systemui.shared.media.INearbyMediaDevicesProvider;
+
+/**
+ * An interface that can be invoked to notify System UI of nearby media devices.
+ *
+ * External clients wanting to notify System UI about the status of nearby media devices should
+ * implement {@link INearbyMediaDevicesProvider} and then register it with system UI using this
+ * service.
+ *
+ * System UI will implement this interface and external clients will invoke it.
+ */
+interface INearbyMediaDevicesService {
+ /** Registers a new provider. */
+ oneway void registerProvider(INearbyMediaDevicesProvider provider) = 1;
+}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/media/INearbyMediaDevicesUpdateCallback.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/media/INearbyMediaDevicesUpdateCallback.aidl
new file mode 100644
index 000000000000..a835f5227852
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/media/INearbyMediaDevicesUpdateCallback.aidl
@@ -0,0 +1,41 @@
+/*
+ * 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.shared.media;
+
+/**
+ * A callback used to notify implementors of changes in the status of nearby devices that are able
+ * to play media.
+ *
+ * External clients may allow registration of these callbacks and external clients will be
+ * responsible for notifying the callbacks appropriately. System UI is only a mediator between the
+ * external client and these callbacks.
+ */
+interface INearbyMediaDevicesUpdateCallback {
+ /** Unknown distance range. */
+ const int RANGE_UNKNOWN = 0;
+ /** Distance is very far away from the peer device. */
+ const int RANGE_FAR = 1;
+ /** Distance is relatively long from the peer device, typically a few meters. */
+ const int RANGE_LONG = 2;
+ /** Distance is close to the peer device, typically with one or two meter. */
+ const int RANGE_CLOSE = 3;
+ /** Distance is very close to the peer device, typically within one meter or less. */
+ const int RANGE_WITHIN_REACH = 4;
+
+ /** Invoked by external clients when media device changes are detected. */
+ oneway void nearbyDeviceUpdate(in String routeId, in int rangeZone) = 1;
+}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/media/NearbyDevice.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/media/NearbyDevice.aidl
new file mode 100644
index 000000000000..62b50ed5f953
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/media/NearbyDevice.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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.shared.media;
+
+parcelable NearbyDevice;
diff --git a/packages/SystemUI/src/com/android/systemui/media/nearby/NearbyDevice.kt b/packages/SystemUI/shared/src/com/android/systemui/shared/media/NearbyDevice.kt
index 96b853f394d4..9cab3ab355dd 100644
--- a/packages/SystemUI/src/com/android/systemui/media/nearby/NearbyDevice.kt
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/media/NearbyDevice.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.media.nearby
+package com.android.systemui.shared.media
import android.os.Parcel
import android.os.Parcelable
@@ -26,14 +26,15 @@ import android.os.Parcelable
* - [routeId] identifying the media route
* - [rangeZone] specifying how far away the device with the media route is from this device.
*/
-class NearbyDevice(parcel: Parcel) : Parcelable {
- var routeId: String? = null
+class NearbyDevice(
+ val routeId: String?,
@RangeZone val rangeZone: Int
+) : Parcelable {
- init {
- routeId = parcel.readString() ?: "unknown"
+ private constructor(parcel: Parcel) : this(
+ routeId = parcel.readString() ?: null,
rangeZone = parcel.readInt()
- }
+ )
override fun describeContents() = 0
diff --git a/packages/SystemUI/src/com/android/systemui/media/nearby/RangeZone.kt b/packages/SystemUI/shared/src/com/android/systemui/shared/media/RangeZone.kt
index 3c890bc9efab..b5eaff6e1cd9 100644
--- a/packages/SystemUI/src/com/android/systemui/media/nearby/RangeZone.kt
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/media/RangeZone.kt
@@ -14,31 +14,18 @@
* limitations under the License.
*/
-package com.android.systemui.media.nearby
+package com.android.systemui.shared.media
import androidx.annotation.IntDef
import kotlin.annotation.AnnotationRetention
@IntDef(
- RangeZone.RANGE_UNKNOWN,
- RangeZone.RANGE_FAR,
- RangeZone.RANGE_LONG,
- RangeZone.RANGE_CLOSE,
- RangeZone.RANGE_WITHIN_REACH
+ INearbyMediaDevicesUpdateCallback.RANGE_UNKNOWN,
+ INearbyMediaDevicesUpdateCallback.RANGE_FAR,
+ INearbyMediaDevicesUpdateCallback.RANGE_LONG,
+ INearbyMediaDevicesUpdateCallback.RANGE_CLOSE,
+ INearbyMediaDevicesUpdateCallback.RANGE_WITHIN_REACH
)
@Retention(AnnotationRetention.SOURCE)
/** The various range zones a device can be in, in relation to the current device. */
-annotation class RangeZone {
- companion object {
- /** Unknown distance range. */
- const val RANGE_UNKNOWN = 0
- /** Distance is very far away from the peer device. */
- const val RANGE_FAR = 1
- /** Distance is relatively long from the peer device, typically a few meters. */
- const val RANGE_LONG = 2
- /** Distance is close to the peer device, typically with one or two meter. */
- const val RANGE_CLOSE = 3
- /** Distance is very close to the peer device, typically within one meter or less. */
- const val RANGE_WITHIN_REACH = 4
- }
-}
+annotation class RangeZone
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java b/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java
index 20d6e3247cd1..881e6a917a45 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java
@@ -120,6 +120,13 @@ public class SystemActions extends CoreStartable {
AccessibilityService.GLOBAL_ACTION_TAKE_SCREENSHOT; // = 9
/**
+ * Action ID to send the KEYCODE_HEADSETHOOK KeyEvent, which is used to answer/hang up calls and
+ * play/stop media
+ */
+ private static final int SYSTEM_ACTION_ID_KEYCODE_HEADSETHOOK =
+ AccessibilityService.GLOBAL_ACTION_KEYCODE_HEADSETHOOK; // = 10
+
+ /**
* Action ID to trigger the accessibility button
*/
public static final int SYSTEM_ACTION_ID_ACCESSIBILITY_BUTTON =
@@ -137,6 +144,36 @@ public class SystemActions extends CoreStartable {
public static final int SYSTEM_ACTION_ID_ACCESSIBILITY_DISMISS_NOTIFICATION_SHADE =
AccessibilityService.GLOBAL_ACTION_DISMISS_NOTIFICATION_SHADE; // 15
+ /**
+ * Action ID to trigger the dpad up button
+ */
+ private static final int SYSTEM_ACTION_ID_DPAD_UP =
+ AccessibilityService.GLOBAL_ACTION_DPAD_UP; // 16
+
+ /**
+ * Action ID to trigger the dpad down button
+ */
+ private static final int SYSTEM_ACTION_ID_DPAD_DOWN =
+ AccessibilityService.GLOBAL_ACTION_DPAD_DOWN; // 17
+
+ /**
+ * Action ID to trigger the dpad left button
+ */
+ private static final int SYSTEM_ACTION_ID_DPAD_LEFT =
+ AccessibilityService.GLOBAL_ACTION_DPAD_LEFT; // 18
+
+ /**
+ * Action ID to trigger the dpad right button
+ */
+ private static final int SYSTEM_ACTION_ID_DPAD_RIGHT =
+ AccessibilityService.GLOBAL_ACTION_DPAD_RIGHT; // 19
+
+ /**
+ * Action ID to trigger dpad center keyevent
+ */
+ private static final int SYSTEM_ACTION_ID_DPAD_CENTER =
+ AccessibilityService.GLOBAL_ACTION_DPAD_CENTER; // 20
+
private static final String PERMISSION_SELF = "com.android.systemui.permission.SELF";
private final SystemActionsBroadcastReceiver mReceiver;
@@ -222,10 +259,34 @@ public class SystemActions extends CoreStartable {
R.string.accessibility_system_action_screenshot_label,
SystemActionsBroadcastReceiver.INTENT_ACTION_TAKE_SCREENSHOT);
+ RemoteAction actionHeadsetHook = createRemoteAction(
+ R.string.accessibility_system_action_headset_hook_label,
+ SystemActionsBroadcastReceiver.INTENT_ACTION_HEADSET_HOOK);
+
RemoteAction actionAccessibilityShortcut = createRemoteAction(
R.string.accessibility_system_action_hardware_a11y_shortcut_label,
SystemActionsBroadcastReceiver.INTENT_ACTION_ACCESSIBILITY_SHORTCUT);
+ RemoteAction actionDpadUp = createRemoteAction(
+ R.string.accessibility_system_action_dpad_up_label,
+ SystemActionsBroadcastReceiver.INTENT_ACTION_DPAD_UP);
+
+ RemoteAction actionDpadDown = createRemoteAction(
+ R.string.accessibility_system_action_dpad_down_label,
+ SystemActionsBroadcastReceiver.INTENT_ACTION_DPAD_DOWN);
+
+ RemoteAction actionDpadLeft = createRemoteAction(
+ R.string.accessibility_system_action_dpad_left_label,
+ SystemActionsBroadcastReceiver.INTENT_ACTION_DPAD_LEFT);
+
+ RemoteAction actionDpadRight = createRemoteAction(
+ R.string.accessibility_system_action_dpad_right_label,
+ SystemActionsBroadcastReceiver.INTENT_ACTION_DPAD_RIGHT);
+
+ RemoteAction actionDpadCenter = createRemoteAction(
+ R.string.accessibility_system_action_dpad_center_label,
+ SystemActionsBroadcastReceiver.INTENT_ACTION_DPAD_CENTER);
+
mA11yManager.registerSystemAction(actionBack, SYSTEM_ACTION_ID_BACK);
mA11yManager.registerSystemAction(actionHome, SYSTEM_ACTION_ID_HOME);
mA11yManager.registerSystemAction(actionRecents, SYSTEM_ACTION_ID_RECENTS);
@@ -234,8 +295,14 @@ public class SystemActions extends CoreStartable {
mA11yManager.registerSystemAction(actionPowerDialog, SYSTEM_ACTION_ID_POWER_DIALOG);
mA11yManager.registerSystemAction(actionLockScreen, SYSTEM_ACTION_ID_LOCK_SCREEN);
mA11yManager.registerSystemAction(actionTakeScreenshot, SYSTEM_ACTION_ID_TAKE_SCREENSHOT);
+ mA11yManager.registerSystemAction(actionHeadsetHook, SYSTEM_ACTION_ID_KEYCODE_HEADSETHOOK);
mA11yManager.registerSystemAction(
actionAccessibilityShortcut, SYSTEM_ACTION_ID_ACCESSIBILITY_SHORTCUT);
+ mA11yManager.registerSystemAction(actionDpadUp, SYSTEM_ACTION_ID_DPAD_UP);
+ mA11yManager.registerSystemAction(actionDpadDown, SYSTEM_ACTION_ID_DPAD_DOWN);
+ mA11yManager.registerSystemAction(actionDpadLeft, SYSTEM_ACTION_ID_DPAD_LEFT);
+ mA11yManager.registerSystemAction(actionDpadRight, SYSTEM_ACTION_ID_DPAD_RIGHT);
+ mA11yManager.registerSystemAction(actionDpadCenter, SYSTEM_ACTION_ID_DPAD_CENTER);
registerOrUnregisterDismissNotificationShadeAction();
}
@@ -305,6 +372,10 @@ public class SystemActions extends CoreStartable {
labelId = R.string.accessibility_system_action_screenshot_label;
intent = SystemActionsBroadcastReceiver.INTENT_ACTION_TAKE_SCREENSHOT;
break;
+ case SYSTEM_ACTION_ID_KEYCODE_HEADSETHOOK:
+ labelId = R.string.accessibility_system_action_headset_hook_label;
+ intent = SystemActionsBroadcastReceiver.INTENT_ACTION_HEADSET_HOOK;
+ break;
case SYSTEM_ACTION_ID_ACCESSIBILITY_BUTTON:
labelId = R.string.accessibility_system_action_on_screen_a11y_shortcut_label;
intent = SystemActionsBroadcastReceiver.INTENT_ACTION_ACCESSIBILITY_BUTTON;
@@ -323,6 +394,26 @@ public class SystemActions extends CoreStartable {
intent = SystemActionsBroadcastReceiver
.INTENT_ACTION_ACCESSIBILITY_DISMISS_NOTIFICATION_SHADE;
break;
+ case SYSTEM_ACTION_ID_DPAD_UP:
+ labelId = R.string.accessibility_system_action_dpad_up_label;
+ intent = SystemActionsBroadcastReceiver.INTENT_ACTION_DPAD_UP;
+ break;
+ case SYSTEM_ACTION_ID_DPAD_DOWN:
+ labelId = R.string.accessibility_system_action_dpad_down_label;
+ intent = SystemActionsBroadcastReceiver.INTENT_ACTION_DPAD_DOWN;
+ break;
+ case SYSTEM_ACTION_ID_DPAD_LEFT:
+ labelId = R.string.accessibility_system_action_dpad_left_label;
+ intent = SystemActionsBroadcastReceiver.INTENT_ACTION_DPAD_LEFT;
+ break;
+ case SYSTEM_ACTION_ID_DPAD_RIGHT:
+ labelId = R.string.accessibility_system_action_dpad_right_label;
+ intent = SystemActionsBroadcastReceiver.INTENT_ACTION_DPAD_RIGHT;
+ break;
+ case SYSTEM_ACTION_ID_DPAD_CENTER:
+ labelId = R.string.accessibility_system_action_dpad_center_label;
+ intent = SystemActionsBroadcastReceiver.INTENT_ACTION_DPAD_CENTER;
+ break;
default:
return;
}
@@ -411,6 +502,10 @@ public class SystemActions extends CoreStartable {
SCREENSHOT_ACCESSIBILITY_ACTIONS, new Handler(Looper.getMainLooper()), null);
}
+ private void handleHeadsetHook() {
+ sendDownAndUpKeyEvents(KeyEvent.KEYCODE_HEADSETHOOK);
+ }
+
private void handleAccessibilityButton() {
AccessibilityManager.getInstance(mContext).notifyAccessibilityButtonClicked(
Display.DEFAULT_DISPLAY);
@@ -434,6 +529,26 @@ public class SystemActions extends CoreStartable {
CommandQueue.FLAG_EXCLUDE_NONE, false /* force */));
}
+ private void handleDpadUp() {
+ sendDownAndUpKeyEvents(KeyEvent.KEYCODE_DPAD_UP);
+ }
+
+ private void handleDpadDown() {
+ sendDownAndUpKeyEvents(KeyEvent.KEYCODE_DPAD_DOWN);
+ }
+
+ private void handleDpadLeft() {
+ sendDownAndUpKeyEvents(KeyEvent.KEYCODE_DPAD_LEFT);
+ }
+
+ private void handleDpadRight() {
+ sendDownAndUpKeyEvents(KeyEvent.KEYCODE_DPAD_RIGHT);
+ }
+
+ private void handleDpadCenter() {
+ sendDownAndUpKeyEvents(KeyEvent.KEYCODE_DPAD_CENTER);
+ }
+
private class SystemActionsBroadcastReceiver extends BroadcastReceiver {
private static final String INTENT_ACTION_BACK = "SYSTEM_ACTION_BACK";
private static final String INTENT_ACTION_HOME = "SYSTEM_ACTION_HOME";
@@ -443,6 +558,7 @@ public class SystemActions extends CoreStartable {
private static final String INTENT_ACTION_POWER_DIALOG = "SYSTEM_ACTION_POWER_DIALOG";
private static final String INTENT_ACTION_LOCK_SCREEN = "SYSTEM_ACTION_LOCK_SCREEN";
private static final String INTENT_ACTION_TAKE_SCREENSHOT = "SYSTEM_ACTION_TAKE_SCREENSHOT";
+ private static final String INTENT_ACTION_HEADSET_HOOK = "SYSTEM_ACTION_HEADSET_HOOK";
private static final String INTENT_ACTION_ACCESSIBILITY_BUTTON =
"SYSTEM_ACTION_ACCESSIBILITY_BUTTON";
private static final String INTENT_ACTION_ACCESSIBILITY_BUTTON_CHOOSER =
@@ -451,6 +567,11 @@ public class SystemActions extends CoreStartable {
"SYSTEM_ACTION_ACCESSIBILITY_SHORTCUT";
private static final String INTENT_ACTION_ACCESSIBILITY_DISMISS_NOTIFICATION_SHADE =
"SYSTEM_ACTION_ACCESSIBILITY_DISMISS_NOTIFICATION_SHADE";
+ private static final String INTENT_ACTION_DPAD_UP = "SYSTEM_ACTION_DPAD_UP";
+ private static final String INTENT_ACTION_DPAD_DOWN = "SYSTEM_ACTION_DPAD_DOWN";
+ private static final String INTENT_ACTION_DPAD_LEFT = "SYSTEM_ACTION_DPAD_LEFT";
+ private static final String INTENT_ACTION_DPAD_RIGHT = "SYSTEM_ACTION_DPAD_RIGHT";
+ private static final String INTENT_ACTION_DPAD_CENTER = "SYSTEM_ACTION_DPAD_CENTER";
private PendingIntent createPendingIntent(Context context, String intentAction) {
switch (intentAction) {
@@ -462,10 +583,16 @@ public class SystemActions extends CoreStartable {
case INTENT_ACTION_POWER_DIALOG:
case INTENT_ACTION_LOCK_SCREEN:
case INTENT_ACTION_TAKE_SCREENSHOT:
+ case INTENT_ACTION_HEADSET_HOOK:
case INTENT_ACTION_ACCESSIBILITY_BUTTON:
case INTENT_ACTION_ACCESSIBILITY_BUTTON_CHOOSER:
case INTENT_ACTION_ACCESSIBILITY_SHORTCUT:
- case INTENT_ACTION_ACCESSIBILITY_DISMISS_NOTIFICATION_SHADE: {
+ case INTENT_ACTION_ACCESSIBILITY_DISMISS_NOTIFICATION_SHADE:
+ case INTENT_ACTION_DPAD_UP:
+ case INTENT_ACTION_DPAD_DOWN:
+ case INTENT_ACTION_DPAD_LEFT:
+ case INTENT_ACTION_DPAD_RIGHT:
+ case INTENT_ACTION_DPAD_CENTER: {
Intent intent = new Intent(intentAction);
intent.setPackage(context.getPackageName());
return PendingIntent.getBroadcast(context, 0, intent,
@@ -487,10 +614,16 @@ public class SystemActions extends CoreStartable {
intentFilter.addAction(INTENT_ACTION_POWER_DIALOG);
intentFilter.addAction(INTENT_ACTION_LOCK_SCREEN);
intentFilter.addAction(INTENT_ACTION_TAKE_SCREENSHOT);
+ intentFilter.addAction(INTENT_ACTION_HEADSET_HOOK);
intentFilter.addAction(INTENT_ACTION_ACCESSIBILITY_BUTTON);
intentFilter.addAction(INTENT_ACTION_ACCESSIBILITY_BUTTON_CHOOSER);
intentFilter.addAction(INTENT_ACTION_ACCESSIBILITY_SHORTCUT);
intentFilter.addAction(INTENT_ACTION_ACCESSIBILITY_DISMISS_NOTIFICATION_SHADE);
+ intentFilter.addAction(INTENT_ACTION_DPAD_UP);
+ intentFilter.addAction(INTENT_ACTION_DPAD_DOWN);
+ intentFilter.addAction(INTENT_ACTION_DPAD_LEFT);
+ intentFilter.addAction(INTENT_ACTION_DPAD_RIGHT);
+ intentFilter.addAction(INTENT_ACTION_DPAD_CENTER);
return intentFilter;
}
@@ -530,6 +663,10 @@ public class SystemActions extends CoreStartable {
handleTakeScreenshot();
break;
}
+ case INTENT_ACTION_HEADSET_HOOK: {
+ handleHeadsetHook();
+ break;
+ }
case INTENT_ACTION_ACCESSIBILITY_BUTTON: {
handleAccessibilityButton();
break;
@@ -546,6 +683,26 @@ public class SystemActions extends CoreStartable {
handleAccessibilityDismissNotificationShade();
break;
}
+ case INTENT_ACTION_DPAD_UP: {
+ handleDpadUp();
+ break;
+ }
+ case INTENT_ACTION_DPAD_DOWN: {
+ handleDpadDown();
+ break;
+ }
+ case INTENT_ACTION_DPAD_LEFT: {
+ handleDpadLeft();
+ break;
+ }
+ case INTENT_ACTION_DPAD_RIGHT: {
+ handleDpadRight();
+ break;
+ }
+ case INTENT_ACTION_DPAD_CENTER: {
+ handleDpadCenter();
+ break;
+ }
default:
break;
}
diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java
index 12759f489a26..8b549b43019f 100644
--- a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java
+++ b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java
@@ -74,7 +74,7 @@ import android.widget.TextView;
import com.android.internal.policy.PhoneWindow;
import com.android.systemui.R;
import com.android.systemui.screenshot.FloatingWindowUtil;
-import com.android.systemui.screenshot.ScreenshotActionChip;
+import com.android.systemui.screenshot.OverlayActionChip;
import com.android.systemui.screenshot.TimeoutHandler;
import java.io.IOException;
@@ -106,12 +106,12 @@ public class ClipboardOverlayController {
private final DraggableConstraintLayout mView;
private final ImageView mImagePreview;
private final TextView mTextPreview;
- private final ScreenshotActionChip mEditChip;
- private final ScreenshotActionChip mRemoteCopyChip;
+ private final OverlayActionChip mEditChip;
+ private final OverlayActionChip mRemoteCopyChip;
private final View mActionContainerBackground;
private final View mDismissButton;
private final LinearLayout mActionContainer;
- private final ArrayList<ScreenshotActionChip> mActionChips = new ArrayList<>();
+ private final ArrayList<OverlayActionChip> mActionChips = new ArrayList<>();
private Runnable mOnSessionCompleteListener;
@@ -251,7 +251,7 @@ public class ClipboardOverlayController {
for (RemoteAction action : actions) {
Intent targetIntent = action.getActionIntent().getIntent();
if (!TextUtils.equals(source, targetIntent.getComponent().getPackageName())) {
- ScreenshotActionChip chip = constructActionChip(action);
+ OverlayActionChip chip = constructActionChip(action);
mActionContainer.addView(chip);
mActionChips.add(chip);
}
@@ -259,9 +259,9 @@ public class ClipboardOverlayController {
});
}
- private ScreenshotActionChip constructActionChip(RemoteAction action) {
- ScreenshotActionChip chip = (ScreenshotActionChip) LayoutInflater.from(mContext).inflate(
- R.layout.screenshot_action_chip, mActionContainer, false);
+ private OverlayActionChip constructActionChip(RemoteAction action) {
+ OverlayActionChip chip = (OverlayActionChip) LayoutInflater.from(mContext).inflate(
+ R.layout.overlay_action_chip, mActionContainer, false);
chip.setText(action.getTitle());
chip.setIcon(action.getIcon(), false);
chip.setPendingIntent(action.getActionIntent(), this::animateOut);
@@ -341,7 +341,7 @@ public class ClipboardOverlayController {
mEditChip.setAlpha(1f);
ContentResolver resolver = mContext.getContentResolver();
try {
- int size = mContext.getResources().getDimensionPixelSize(R.dimen.screenshot_x_scale);
+ int size = mContext.getResources().getDimensionPixelSize(R.dimen.overlay_x_scale);
// The width of the view is capped, height maintains aspect ratio, so allow it to be
// taller if needed.
Bitmap thumbnail = resolver.loadThumbnail(uri, new Size(size, size * 4), null);
@@ -365,7 +365,7 @@ public class ClipboardOverlayController {
}
private void animateOut() {
- getExitAnimation().start();
+ mView.dismiss();
}
private ValueAnimator getEnterAnimation() {
@@ -401,28 +401,6 @@ public class ClipboardOverlayController {
return anim;
}
- private ValueAnimator getExitAnimation() {
- ValueAnimator anim = ValueAnimator.ofFloat(0, 1);
-
- anim.addUpdateListener(animation -> {
- mView.setAlpha(1 - animation.getAnimatedFraction());
- final View actionBackground = requireNonNull(
- mView.findViewById(R.id.actions_container_background));
- mView.setTranslationX(
- -animation.getAnimatedFraction() * actionBackground.getWidth() / 2);
- });
-
- anim.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- super.onAnimationEnd(animation);
- hideImmediate();
- }
- });
-
- return anim;
- }
-
private void hideImmediate() {
// Note this may be called multiple times if multiple dismissal events happen at the same
// time.
@@ -453,7 +431,7 @@ public class ClipboardOverlayController {
}
private void resetActionChips() {
- for (ScreenshotActionChip chip : mActionChips) {
+ for (OverlayActionChip chip : mActionChips) {
mActionContainer.removeView(chip);
}
mActionChips.clear();
diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/DraggableConstraintLayout.java b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/DraggableConstraintLayout.java
index 6a4be6ee5eae..8843462413b5 100644
--- a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/DraggableConstraintLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/DraggableConstraintLayout.java
@@ -98,10 +98,23 @@ public class DraggableConstraintLayout extends ConstraintLayout {
return mSwipeDetector.onTouchEvent(ev);
}
+ /**
+ * Dismiss the view, with animation controlled by SwipeDismissHandler
+ */
+ public void dismiss() {
+ mSwipeDismissHandler.dismiss();
+ }
+
+ /**
+ * Set the callback to be run after view is dismissed
+ */
public void setOnDismissCallback(Runnable callback) {
mOnDismiss = callback;
}
+ /**
+ * Set the callback to be run when the view is interacted with (e.g. tapped)
+ */
public void setOnInteractionCallback(Runnable callback) {
mOnInteraction = callback;
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/KeyguardMediaController.kt b/packages/SystemUI/src/com/android/systemui/media/KeyguardMediaController.kt
index 44727f29888d..48f48266fda5 100644
--- a/packages/SystemUI/src/com/android/systemui/media/KeyguardMediaController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/KeyguardMediaController.kt
@@ -159,8 +159,7 @@ class KeyguardMediaController @Inject constructor(
}
fun refreshMediaPosition() {
- val keyguardOrUserSwitcher = (statusBarStateController.state == StatusBarState.KEYGUARD ||
- statusBarStateController.state == StatusBarState.FULLSCREEN_USER_SWITCHER)
+ val keyguardOrUserSwitcher = (statusBarStateController.state == StatusBarState.KEYGUARD)
// mediaHost.visible required for proper animations handling
visible = mediaHost.visible &&
!bypassController.bypassEnabled &&
@@ -196,4 +195,4 @@ class KeyguardMediaController @Inject constructor(
visibilityChangedListener?.invoke(newVisibility == View.VISIBLE)
}
}
-} \ No newline at end of file
+}
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt
index 64ebe568c790..6145f0ffebad 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt
@@ -567,8 +567,7 @@ class MediaHierarchyManager @Inject constructor(
previousLocation = this.desiredLocation
} else if (forceStateUpdate) {
val onLockscreen = (!bypassController.bypassEnabled &&
- (statusbarState == StatusBarState.KEYGUARD ||
- statusbarState == StatusBarState.FULLSCREEN_USER_SWITCHER))
+ (statusbarState == StatusBarState.KEYGUARD))
if (desiredLocation == LOCATION_QS && previousLocation == LOCATION_LOCKSCREEN &&
!onLockscreen) {
// If media active state changed and the device is now unlocked, update the
@@ -955,8 +954,7 @@ class MediaHierarchyManager @Inject constructor(
return desiredLocation
}
val onLockscreen = (!bypassController.bypassEnabled &&
- (statusbarState == StatusBarState.KEYGUARD ||
- statusbarState == StatusBarState.FULLSCREEN_USER_SWITCHER))
+ (statusbarState == StatusBarState.KEYGUARD))
val allowedOnLockscreen = notifLockscreenUserManager.shouldShowLockscreenNotifications()
val location = when {
dreamOverlayActive -> LOCATION_DREAM_OVERLAY
@@ -1087,4 +1085,4 @@ private annotation class TransformationType
@IntDef(prefix = ["LOCATION_"], value = [MediaHierarchyManager.LOCATION_QS,
MediaHierarchyManager.LOCATION_QQS, MediaHierarchyManager.LOCATION_LOCKSCREEN])
@Retention(AnnotationRetention.SOURCE)
-annotation class MediaLocation \ No newline at end of file
+annotation class MediaLocation
diff --git a/packages/SystemUI/src/com/android/systemui/media/dagger/MediaModule.java b/packages/SystemUI/src/com/android/systemui/media/dagger/MediaModule.java
index 2bc910e4a21a..29938a05a327 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dagger/MediaModule.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dagger/MediaModule.java
@@ -26,6 +26,7 @@ import com.android.systemui.media.MediaHierarchyManager;
import com.android.systemui.media.MediaHost;
import com.android.systemui.media.MediaHostStatesManager;
import com.android.systemui.media.dream.dagger.MediaComplicationComponent;
+import com.android.systemui.media.nearby.NearbyMediaDevicesService;
import com.android.systemui.media.taptotransfer.MediaTttCommandLineHelper;
import com.android.systemui.media.taptotransfer.MediaTttFlags;
import com.android.systemui.media.taptotransfer.receiver.MediaTttChipControllerReceiver;
@@ -142,4 +143,10 @@ public interface MediaModule {
@IntoMap
@ClassKey(MediaTttSenderService.class)
Service bindMediaTttSenderService(MediaTttSenderService service);
+
+ /** Inject into NearbyMediaDevicesService. */
+ @Binds
+ @IntoMap
+ @ClassKey(NearbyMediaDevicesService.class)
+ Service bindMediaNearbyDevicesService(NearbyMediaDevicesService service);
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/nearby/MediaNearbyDevicesManager.kt b/packages/SystemUI/src/com/android/systemui/media/nearby/MediaNearbyDevicesManager.kt
deleted file mode 100644
index 0453fdb45931..000000000000
--- a/packages/SystemUI/src/com/android/systemui/media/nearby/MediaNearbyDevicesManager.kt
+++ /dev/null
@@ -1,51 +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.media.nearby
-
-import com.android.systemui.dagger.SysUISingleton
-
-/**
- * A manager that returns information about devices that are nearby and can receive media transfers.
- */
-@SysUISingleton
-class MediaNearbyDevicesManager {
-
- /** Returns a list containing the current nearby devices. */
- fun getCurrentNearbyDevices(): List<NearbyDevice> {
- // TODO(b/216313420): Implement this function.
- return emptyList()
- }
-
- /**
- * Registers [callback] to be notified each time a device's range changes or when a new device
- * comes within range.
- */
- fun registerNearbyDevicesCallback(
- callback: (device: NearbyDevice) -> Unit
- ) {
- // TODO(b/216313420): Implement this function.
- }
-
- /**
- * Un-registers [callback]. See [registerNearbyDevicesCallback].
- */
- fun unregisterNearbyDevicesCallback(
- callback: (device: NearbyDevice) -> Unit
- ) {
- // TODO(b/216313420): Implement this function.
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/media/nearby/NearbyMediaDevicesService.kt b/packages/SystemUI/src/com/android/systemui/media/nearby/NearbyMediaDevicesService.kt
new file mode 100644
index 000000000000..eaf2bd96e37a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/media/nearby/NearbyMediaDevicesService.kt
@@ -0,0 +1,81 @@
+/*
+ * 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.nearby
+
+import android.app.Service
+import android.content.Intent
+import android.os.IBinder
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.shared.media.INearbyMediaDevicesProvider
+import com.android.systemui.shared.media.INearbyMediaDevicesService
+import com.android.systemui.shared.media.INearbyMediaDevicesUpdateCallback
+import com.android.systemui.shared.media.NearbyDevice
+import javax.inject.Inject
+
+/**
+ * A service that acts as a bridge between (1) external clients that have data on nearby devices
+ * that are able to play media and (2) internal clients (like media Output Switcher) that need data
+ * on these nearby devices.
+ *
+ * TODO(b/216313420): Add logging to this class.
+ */
+@SysUISingleton
+class NearbyMediaDevicesService @Inject constructor() : Service() {
+
+ private var provider: INearbyMediaDevicesProvider? = null
+
+ private val binder: IBinder = object : INearbyMediaDevicesService.Stub() {
+ override fun registerProvider(newProvider: INearbyMediaDevicesProvider) {
+ provider = newProvider
+ newProvider.asBinder().linkToDeath(
+ {
+ // We might've gotten a new provider before the old provider died, so we only
+ // need to clear our provider if the most recent provider died.
+ if (provider == newProvider) {
+ provider = null
+ }
+ },
+ /* flags= */ 0
+ )
+ }
+ }
+
+ override fun onBind(intent: Intent?): IBinder = binder
+
+ /** Returns a list containing the current nearby devices. */
+ fun getCurrentNearbyDevices(): List<NearbyDevice> {
+ val currentProvider = provider ?: return emptyList()
+ return currentProvider.currentNearbyDevices
+ }
+
+ /**
+ * Registers [callback] to be notified each time a device's range changes or when a new device
+ * comes within range.
+ */
+ fun registerNearbyDevicesCallback(callback: INearbyMediaDevicesUpdateCallback) {
+ val currentProvider = provider ?: return
+ currentProvider.registerNearbyDevicesCallback(callback)
+ }
+
+ /**
+ * Un-registers [callback]. See [registerNearbyDevicesCallback].
+ */
+ fun unregisterNearbyDevicesCallback(callback: INearbyMediaDevicesUpdateCallback) {
+ val currentProvider = provider ?: return
+ currentProvider.unregisterNearbyDevicesCallback(callback)
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotActionChip.java b/packages/SystemUI/src/com/android/systemui/screenshot/OverlayActionChip.java
index dec5afdaccfe..c4ea67e0f79e 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotActionChip.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/OverlayActionChip.java
@@ -16,6 +16,8 @@
package com.android.systemui.screenshot;
+import static java.util.Objects.requireNonNull;
+
import android.app.PendingIntent;
import android.content.Context;
import android.graphics.drawable.Icon;
@@ -28,10 +30,11 @@ import android.widget.TextView;
import com.android.systemui.R;
+
/**
* View for a chip with an icon and text.
*/
-public class ScreenshotActionChip extends FrameLayout {
+public class OverlayActionChip extends FrameLayout {
private static final String TAG = "ScreenshotActionChip";
@@ -39,27 +42,27 @@ public class ScreenshotActionChip extends FrameLayout {
private TextView mTextView;
private boolean mIsPending = false;
- public ScreenshotActionChip(Context context) {
+ public OverlayActionChip(Context context) {
this(context, null);
}
- public ScreenshotActionChip(Context context, AttributeSet attrs) {
+ public OverlayActionChip(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
- public ScreenshotActionChip(Context context, AttributeSet attrs, int defStyleAttr) {
+ public OverlayActionChip(Context context, AttributeSet attrs, int defStyleAttr) {
this(context, attrs, defStyleAttr, 0);
}
- public ScreenshotActionChip(
+ public OverlayActionChip(
Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
@Override
protected void onFinishInflate() {
- mIconView = findViewById(R.id.screenshot_action_chip_icon);
- mTextView = findViewById(R.id.screenshot_action_chip_text);
+ mIconView = requireNonNull(findViewById(R.id.overlay_action_chip_icon));
+ mTextView = requireNonNull(findViewById(R.id.overlay_action_chip_text));
updatePadding(mTextView.getText().length() > 0);
}
@@ -116,15 +119,15 @@ public class ScreenshotActionChip extends FrameLayout {
(LinearLayout.LayoutParams) mTextView.getLayoutParams();
if (hasText) {
int paddingHorizontal = mContext.getResources().getDimensionPixelSize(
- R.dimen.screenshot_action_chip_padding_horizontal);
+ R.dimen.overlay_action_chip_padding_horizontal);
int spacing = mContext.getResources().getDimensionPixelSize(
- R.dimen.screenshot_action_chip_spacing);
+ R.dimen.overlay_action_chip_spacing);
iconParams.setMarginStart(paddingHorizontal);
iconParams.setMarginEnd(spacing);
textParams.setMarginEnd(paddingHorizontal);
} else {
int paddingHorizontal = mContext.getResources().getDimensionPixelSize(
- R.dimen.screenshot_action_chip_icon_only_padding_horizontal);
+ R.dimen.overlay_action_chip_icon_only_padding_horizontal);
iconParams.setMarginStart(paddingHorizontal);
iconParams.setMarginEnd(paddingHorizontal);
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java
index e5649a126807..f9827905b69a 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java
@@ -131,9 +131,9 @@ public class ScreenshotView extends FrameLayout implements
private final Resources mResources;
private final Interpolator mFastOutSlowIn;
private final DisplayMetrics mDisplayMetrics;
- private final float mCornerSizeX;
- private final float mDismissDeltaY;
+ private final float mFixedSize;
private final AccessibilityManager mAccessibilityManager;
+ private final GestureDetector mSwipeDetector;
private int mNavMode;
private boolean mOrientationPortrait;
@@ -151,23 +151,21 @@ public class ScreenshotView extends FrameLayout implements
private LinearLayout mActionsView;
private ImageView mBackgroundProtection;
private FrameLayout mDismissButton;
- private ScreenshotActionChip mShareChip;
- private ScreenshotActionChip mEditChip;
- private ScreenshotActionChip mScrollChip;
- private ScreenshotActionChip mQuickShareChip;
+ private OverlayActionChip mShareChip;
+ private OverlayActionChip mEditChip;
+ private OverlayActionChip mScrollChip;
+ private OverlayActionChip mQuickShareChip;
private UiEventLogger mUiEventLogger;
private ScreenshotViewCallback mCallbacks;
- private Animator mDismissAnimation;
private boolean mPendingSharedTransition;
- private GestureDetector mSwipeDetector;
private SwipeDismissHandler mSwipeDismissHandler;
private InputMonitorCompat mInputMonitor;
private InputChannelCompat.InputEventReceiver mInputEventReceiver;
private boolean mShowScrollablePreview;
private String mPackageName = "";
- private final ArrayList<ScreenshotActionChip> mSmartChips = new ArrayList<>();
+ private final ArrayList<OverlayActionChip> mSmartChips = new ArrayList<>();
private PendingInteraction mPendingInteraction;
private enum PendingInteraction {
@@ -194,9 +192,7 @@ public class ScreenshotView extends FrameLayout implements
super(context, attrs, defStyleAttr, defStyleRes);
mResources = mContext.getResources();
- mCornerSizeX = mResources.getDimensionPixelSize(R.dimen.screenshot_x_scale);
- mDismissDeltaY = mResources.getDimensionPixelSize(
- R.dimen.screenshot_dismissal_height_delta);
+ mFixedSize = mResources.getDimensionPixelSize(R.dimen.overlay_x_scale);
// standard material ease
mFastOutSlowIn =
@@ -474,16 +470,14 @@ public class ScreenshotView extends FrameLayout implements
int orientation = mContext.getResources().getConfiguration().orientation;
mOrientationPortrait = (orientation == ORIENTATION_PORTRAIT);
updateInsets(insets);
- int screenshotFixedSize =
- mContext.getResources().getDimensionPixelSize(R.dimen.screenshot_x_scale);
ViewGroup.LayoutParams params = mScreenshotPreview.getLayoutParams();
if (mOrientationPortrait) {
- params.width = screenshotFixedSize;
+ params.width = (int) mFixedSize;
params.height = LayoutParams.WRAP_CONTENT;
mScreenshotPreview.setScaleType(ImageView.ScaleType.FIT_START);
} else {
params.width = LayoutParams.WRAP_CONTENT;
- params.height = screenshotFixedSize;
+ params.height = (int) mFixedSize;
mScreenshotPreview.setScaleType(ImageView.ScaleType.FIT_END);
}
@@ -500,7 +494,7 @@ public class ScreenshotView extends FrameLayout implements
// ratio of preview width, end vs. start size
float cornerScale =
- mCornerSizeX / (mOrientationPortrait ? bounds.width() : bounds.height());
+ mFixedSize / (mOrientationPortrait ? bounds.width() : bounds.height());
final float currentScale = 1 / cornerScale;
AnimatorSet dropInAnimation = new AnimatorSet();
@@ -651,7 +645,7 @@ public class ScreenshotView extends FrameLayout implements
} catch (RemoteException e) {
}
- ArrayList<ScreenshotActionChip> chips = new ArrayList<>();
+ ArrayList<OverlayActionChip> chips = new ArrayList<>();
mShareChip.setContentDescription(mContext.getString(R.string.screenshot_share_description));
mShareChip.setIcon(Icon.createWithResource(mContext, R.drawable.ic_screenshot_share), true);
@@ -716,7 +710,7 @@ public class ScreenshotView extends FrameLayout implements
+ (t * (1 - SCREENSHOT_ACTIONS_START_SCALE_X));
mActionsContainer.setScaleX(containerScale);
mActionsContainerBackground.setScaleX(containerScale);
- for (ScreenshotActionChip chip : chips) {
+ for (OverlayActionChip chip : chips) {
chip.setAlpha(t);
chip.setScaleX(1 / containerScale); // invert to keep size of children constant
}
@@ -772,8 +766,8 @@ public class ScreenshotView extends FrameLayout implements
LayoutInflater inflater = LayoutInflater.from(mContext);
for (Notification.Action smartAction : imageData.smartActions) {
- ScreenshotActionChip actionChip = (ScreenshotActionChip) inflater.inflate(
- R.layout.screenshot_action_chip, mActionsView, false);
+ OverlayActionChip actionChip = (OverlayActionChip) inflater.inflate(
+ R.layout.overlay_action_chip, mActionsView, false);
actionChip.setText(smartAction.title);
actionChip.setIcon(smartAction.getIcon(), false);
actionChip.setPendingIntent(smartAction.actionIntent,
@@ -792,8 +786,8 @@ public class ScreenshotView extends FrameLayout implements
void addQuickShareChip(Notification.Action quickShareAction) {
if (mPendingInteraction == null) {
LayoutInflater inflater = LayoutInflater.from(mContext);
- mQuickShareChip = (ScreenshotActionChip) inflater.inflate(
- R.layout.screenshot_action_chip, mActionsView, false);
+ mQuickShareChip = (OverlayActionChip) inflater.inflate(
+ R.layout.overlay_action_chip, mActionsView, false);
mQuickShareChip.setText(quickShareAction.title);
mQuickShareChip.setIcon(quickShareAction.getIcon(), false);
mQuickShareChip.setOnClickListener(v -> {
@@ -894,7 +888,7 @@ public class ScreenshotView extends FrameLayout implements
if (mShowScrollablePreview) {
Rect scrollableArea = scrollableAreaOnScreen(response);
- float scale = mCornerSizeX
+ float scale = mFixedSize
/ (mOrientationPortrait ? screenBitmap.getWidth() : screenBitmap.getHeight());
ConstraintLayout.LayoutParams params =
(ConstraintLayout.LayoutParams) mScrollablePreview.getLayoutParams();
@@ -945,7 +939,7 @@ public class ScreenshotView extends FrameLayout implements
}
boolean isDismissing() {
- return (mDismissAnimation != null && mDismissAnimation.isRunning());
+ return mSwipeDismissHandler.isDismissing();
}
boolean isPendingSharedTransition() {
@@ -961,12 +955,6 @@ public class ScreenshotView extends FrameLayout implements
Log.d(TAG, "reset screenshot view");
}
- if (mDismissAnimation != null && mDismissAnimation.isRunning()) {
- if (DEBUG_ANIM) {
- Log.d(TAG, "cancelling dismiss animation");
- }
- mDismissAnimation.cancel();
- }
mSwipeDismissHandler.cancel();
if (DEBUG_WINDOW) {
Log.d(TAG, "removing OnComputeInternalInsetsListener");
@@ -994,7 +982,7 @@ public class ScreenshotView extends FrameLayout implements
mShareChip.setIsPending(false);
mEditChip.setIsPending(false);
mPendingInteraction = null;
- for (ScreenshotActionChip chip : mSmartChips) {
+ for (OverlayActionChip chip : mSmartChips) {
mActionsView.removeView(chip);
}
mSmartChips.clear();
@@ -1019,31 +1007,6 @@ public class ScreenshotView extends FrameLayout implements
}
}
- private AnimatorSet createScreenshotTranslateDismissAnimation() {
- ValueAnimator alphaAnim = ValueAnimator.ofFloat(0, 1);
- alphaAnim.setStartDelay(SCREENSHOT_DISMISS_ALPHA_OFFSET_MS);
- alphaAnim.setDuration(SCREENSHOT_DISMISS_ALPHA_DURATION_MS);
- alphaAnim.addUpdateListener(animation -> {
- setAlpha(1 - animation.getAnimatedFraction());
- });
-
- ValueAnimator xAnim = ValueAnimator.ofFloat(0, 1);
- xAnim.setInterpolator(mAccelerateInterpolator);
- xAnim.setDuration(SCREENSHOT_DISMISS_X_DURATION_MS);
- float deltaX = mDirectionLTR
- ? -1 * (mScreenshotPreviewBorder.getX() + mScreenshotPreviewBorder.getWidth())
- : (mDisplayMetrics.widthPixels - mScreenshotPreviewBorder.getX());
- xAnim.addUpdateListener(animation -> {
- float currXDelta = MathUtils.lerp(0, deltaX, animation.getAnimatedFraction());
- mScreenshotStatic.setTranslationX(currXDelta);
- });
-
- AnimatorSet animSet = new AnimatorSet();
- animSet.play(xAnim).with(alphaAnim);
-
- return animSet;
- }
-
ValueAnimator createScreenshotFadeDismissAnimation() {
ValueAnimator alphaAnim = ValueAnimator.ofFloat(0, 1);
alphaAnim.addUpdateListener(animation -> {
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/SwipeDismissHandler.java b/packages/SystemUI/src/com/android/systemui/screenshot/SwipeDismissHandler.java
index 4e960037bb7b..451fb1311ebb 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/SwipeDismissHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/SwipeDismissHandler.java
@@ -16,6 +16,7 @@
package com.android.systemui.screenshot;
+import static com.android.systemui.screenshot.LogConfig.DEBUG_ANIM;
import static com.android.systemui.screenshot.LogConfig.DEBUG_DISMISS;
import android.animation.Animator;
@@ -137,10 +138,20 @@ public class SwipeDismissHandler implements View.OnTouchListener {
}
/**
+ * Return whether the view is currently being dismissed
+ */
+ public boolean isDismissing() {
+ return (mDismissAnimation != null && mDismissAnimation.isRunning());
+ }
+
+ /**
* Cancel the currently-running dismissal animation, if any.
*/
public void cancel() {
- if (mDismissAnimation != null && mDismissAnimation.isRunning()) {
+ if (isDismissing()) {
+ if (DEBUG_ANIM) {
+ Log.d(TAG, "cancelling dismiss animation");
+ }
mDismissAnimation.cancel();
}
}
@@ -182,7 +193,13 @@ public class SwipeDismissHandler implements View.OnTouchListener {
// make sure the UI gets all the way off the screen in the direction of movement
// (the actions container background is guaranteed to be both the leftmost and
// rightmost UI element in LTR and RTL)
- float finalX = startX <= 0 ? -1 * mView.getRight() : mDisplayMetrics.widthPixels;
+ float finalX;
+ int layoutDir = mView.getContext().getResources().getConfiguration().getLayoutDirection();
+ if (startX > 0 || (startX == 0 && layoutDir == View.LAYOUT_DIRECTION_RTL)) {
+ finalX = mDisplayMetrics.widthPixels;
+ } else {
+ finalX = -1 * mView.getRight();
+ }
float distance = Math.abs(finalX - startX);
anim.addUpdateListener(animation -> {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarState.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarState.java
index c0148c0ecb21..16bc951e0323 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarState.java
@@ -37,12 +37,6 @@ public class StatusBarState {
*/
public static final int SHADE_LOCKED = 2;
- /**
- * Status bar is locked and shows the full screen user switcher.
- */
- public static final int FULLSCREEN_USER_SWITCHER = 3;
-
-
public static String toShortString(int x) {
switch (x) {
case SHADE:
@@ -51,8 +45,6 @@ public class StatusBarState {
return "SHD_LCK";
case KEYGUARD:
return "KGRD";
- case FULLSCREEN_USER_SWITCHER:
- return "FS_USRSW";
default:
return "bad_value_" + x;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
index f56602ee2bcd..ee12cc5679fe 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
@@ -76,7 +76,7 @@ public class StatusBarStateControllerImpl implements
// Must be a power of 2
private static final int HISTORY_SIZE = 32;
- private static final int MAX_STATE = StatusBarState.FULLSCREEN_USER_SWITCHER;
+ private static final int MAX_STATE = StatusBarState.SHADE_LOCKED;
private static final int MIN_STATE = StatusBarState.SHADE;
private static final Comparator<RankedListener> sComparator =
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateEvent.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateEvent.java
index 8330169980d4..b66a48e07777 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateEvent.java
@@ -34,10 +34,7 @@ public enum StatusBarStateEvent implements UiEventLogger.UiEventEnum {
STATUS_BAR_STATE_KEYGUARD(430),
@UiEvent(doc = "StatusBarState changed to SHADE_LOCKED state")
- STATUS_BAR_STATE_SHADE_LOCKED(431),
-
- @UiEvent(doc = "StatusBarState changed to FULLSCREEN_USER_SWITCHER state")
- STATUS_BAR_STATE_FULLSCREEN_USER_SWITCHER(432);
+ STATUS_BAR_STATE_SHADE_LOCKED(431);
private int mId;
StatusBarStateEvent(int id) {
@@ -60,8 +57,6 @@ public enum StatusBarStateEvent implements UiEventLogger.UiEventEnum {
return STATUS_BAR_STATE_KEYGUARD;
case StatusBarState.SHADE_LOCKED:
return STATUS_BAR_STATE_SHADE_LOCKED;
- case StatusBarState.FULLSCREEN_USER_SWITCHER:
- return STATUS_BAR_STATE_FULLSCREEN_USER_SWITCHER;
default:
return STATUS_BAR_STATE_UNKNOWN;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
index 04d3e9a01d86..6a78370c7dab 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
@@ -180,6 +180,7 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp
private final MetricsLogger mMetricsLogger;
private final AuthController mAuthController;
private final StatusBarStateController mStatusBarStateController;
+ private final LatencyTracker mLatencyTracker;
private long mLastFpFailureUptimeMillis;
private int mNumConsecutiveFpFailures;
@@ -281,7 +282,8 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp
AuthController authController,
StatusBarStateController statusBarStateController,
KeyguardUnlockAnimationController keyguardUnlockAnimationController,
- SessionTracker sessionTracker) {
+ SessionTracker sessionTracker,
+ LatencyTracker latencyTracker) {
mContext = context;
mPowerManager = powerManager;
mShadeController = shadeController;
@@ -289,6 +291,7 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp
mDozeParameters = dozeParameters;
mUpdateMonitor.registerCallback(this);
mMediaManager = notificationMediaManager;
+ mLatencyTracker = latencyTracker;
wakefulnessLifecycle.addObserver(mWakefulnessObserver);
screenLifecycle.addObserver(mScreenObserver);
@@ -343,13 +346,13 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp
public void onBiometricAcquired(BiometricSourceType biometricSourceType) {
Trace.beginSection("BiometricUnlockController#onBiometricAcquired");
releaseBiometricWakeLock();
- if (!mUpdateMonitor.isDeviceInteractive()) {
- if (LatencyTracker.isEnabled(mContext)) {
+ if (isWakeAndUnlock()) {
+ if (mLatencyTracker.isEnabled()) {
int action = LatencyTracker.ACTION_FINGERPRINT_WAKE_AND_UNLOCK;
if (biometricSourceType == BiometricSourceType.FACE) {
action = LatencyTracker.ACTION_FACE_WAKE_AND_UNLOCK;
}
- LatencyTracker.getInstance(mContext).onActionStart(action);
+ mLatencyTracker.onActionStart(action);
}
mWakeLock = mPowerManager.newWakeLock(
PowerManager.PARTIAL_WAKE_LOCK, BIOMETRIC_WAKE_LOCK_NAME);
@@ -652,6 +655,14 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp
Optional.ofNullable(BiometricUiEvent.FAILURE_EVENT_BY_SOURCE_TYPE.get(biometricSourceType))
.ifPresent(event -> UI_EVENT_LOGGER.log(event, getSessionId()));
+ if (mLatencyTracker.isEnabled()) {
+ int action = LatencyTracker.ACTION_FINGERPRINT_WAKE_AND_UNLOCK;
+ if (biometricSourceType == BiometricSourceType.FACE) {
+ action = LatencyTracker.ACTION_FACE_WAKE_AND_UNLOCK;
+ }
+ mLatencyTracker.onActionCancel(action);
+ }
+
if (biometricSourceType == BiometricSourceType.FINGERPRINT
&& mUpdateMonitor.isUdfpsSupported()) {
long currUptimeMillis = SystemClock.uptimeMillis();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt
index 1cb19ab727aa..d6bf5f21c834 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt
@@ -49,29 +49,29 @@ class PhoneStatusBarViewController private constructor(
}
override fun onViewAttached() {
- moveFromCenterAnimationController?.let { animationController ->
- val statusBarLeftSide: View = mView.findViewById(R.id.status_bar_left_side)
- val systemIconArea: ViewGroup = mView.findViewById(R.id.system_icon_area)
-
- val viewsToAnimate = arrayOf(
- statusBarLeftSide,
- systemIconArea
- )
-
- mView.viewTreeObserver.addOnPreDrawListener(object :
- ViewTreeObserver.OnPreDrawListener {
- override fun onPreDraw(): Boolean {
- animationController.onViewsReady(viewsToAnimate)
- mView.viewTreeObserver.removeOnPreDrawListener(this)
- return true
- }
- })
+ if (moveFromCenterAnimationController == null) return
+
+ val statusBarLeftSide: View = mView.findViewById(R.id.status_bar_left_side)
+ val systemIconArea: ViewGroup = mView.findViewById(R.id.system_icon_area)
+
+ val viewsToAnimate = arrayOf(
+ statusBarLeftSide,
+ systemIconArea
+ )
+
+ mView.viewTreeObserver.addOnPreDrawListener(object :
+ ViewTreeObserver.OnPreDrawListener {
+ override fun onPreDraw(): Boolean {
+ moveFromCenterAnimationController.onViewsReady(viewsToAnimate)
+ mView.viewTreeObserver.removeOnPreDrawListener(this)
+ return true
+ }
+ })
- mView.addOnLayoutChangeListener { _, left, _, right, _, oldLeft, _, oldRight, _ ->
- val widthChanged = right - left != oldRight - oldLeft
- if (widthChanged) {
- moveFromCenterAnimationController.onStatusBarWidthChanged()
- }
+ mView.addOnLayoutChangeListener { _, left, _, right, _, oldLeft, _, oldRight, _ ->
+ val widthChanged = right - left != oldRight - oldLeft
+ if (widthChanged) {
+ moveFromCenterAnimationController.onStatusBarWidthChanged()
}
}
@@ -162,9 +162,7 @@ class PhoneStatusBarViewController private constructor(
PhoneStatusBarViewController(
view,
progressProvider.getOrNull(),
- unfoldComponent.map {
- it.getStatusBarMoveFromCenterAnimationController()
- }.getOrNull(),
+ unfoldComponent.getOrNull()?.getStatusBarMoveFromCenterAnimationController(),
touchEventHandler,
configurationController
)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 2f3300a53ad6..c8cc807475f3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -2935,14 +2935,6 @@ public class StatusBar extends CoreStartable implements
return updateIsKeyguard();
}
- /**
- * stop(tag)
- * @return True if StatusBar state is FULLSCREEN_USER_SWITCHER.
- */
- public boolean isFullScreenUserSwitcherState() {
- return mState == StatusBarState.FULLSCREEN_USER_SWITCHER;
- }
-
boolean updateIsKeyguard() {
return updateIsKeyguard(false /* forceStateChange */);
}
@@ -2996,9 +2988,7 @@ public class StatusBar extends CoreStartable implements
onLaunchTransitionFadingEnded();
}
mMessageRouter.cancelMessages(MSG_LAUNCH_TRANSITION_TIMEOUT);
- if (mUserSwitcherController != null && mUserSwitcherController.useFullscreenUserSwitcher()) {
- mStatusBarStateController.setState(StatusBarState.FULLSCREEN_USER_SWITCHER);
- } else if (!mLockscreenShadeTransitionController.isWakingToShadeLocked()) {
+ if (!mLockscreenShadeTransitionController.isWakingToShadeLocked()) {
mStatusBarStateController.setState(StatusBarState.KEYGUARD);
}
updatePanelExpansionForKeyguard();
@@ -3009,8 +2999,6 @@ public class StatusBar extends CoreStartable implements
if (mState == StatusBarState.KEYGUARD && mBiometricUnlockController.getMode()
!= BiometricUnlockController.MODE_WAKE_AND_UNLOCK && !mBouncerShowing) {
mShadeController.instantExpandNotificationsPanel();
- } else if (mState == StatusBarState.FULLSCREEN_USER_SWITCHER) {
- instantCollapseNotificationPanel();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index b833c894c43f..d42a42364f21 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -49,7 +49,6 @@ import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.keyguard.KeyguardViewController;
import com.android.keyguard.ViewMediatorCallback;
-import com.android.systemui.DejankUtils;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dock.DockManager;
import com.android.systemui.dreams.DreamOverlayStateController;
@@ -214,6 +213,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
private final SysuiStatusBarStateController mStatusBarStateController;
private final DockManager mDockManager;
private final KeyguardUpdateMonitor mKeyguardUpdateManager;
+ private final LatencyTracker mLatencyTracker;
private KeyguardBypassController mBypassController;
@Nullable private AlternateAuthInterceptor mAlternateAuthInterceptor;
@@ -246,7 +246,8 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
NotificationMediaManager notificationMediaManager,
KeyguardBouncer.Factory keyguardBouncerFactory,
KeyguardMessageAreaController.Factory keyguardMessageAreaFactory,
- Lazy<ShadeController> shadeController) {
+ Lazy<ShadeController> shadeController,
+ LatencyTracker latencyTracker) {
mContext = context;
mViewMediatorCallback = callback;
mLockPatternUtils = lockPatternUtils;
@@ -262,6 +263,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
mKeyguardBouncerFactory = keyguardBouncerFactory;
mKeyguardMessageAreaFactory = keyguardMessageAreaFactory;
mShadeController = shadeController;
+ mLatencyTracker = latencyTracker;
}
@Override
@@ -859,15 +861,11 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
}
private void wakeAndUnlockDejank() {
- if (mBiometricUnlockController.getMode() == MODE_WAKE_AND_UNLOCK
- && LatencyTracker.isEnabled(mContext)) {
+ if (mBiometricUnlockController.isWakeAndUnlock() && mLatencyTracker.isEnabled()) {
BiometricSourceType type = mBiometricUnlockController.getBiometricType();
- DejankUtils.postAfterTraversal(() -> {
- LatencyTracker.getInstance(mContext).onActionEnd(
- type == BiometricSourceType.FACE
- ? LatencyTracker.ACTION_FACE_WAKE_AND_UNLOCK
- : LatencyTracker.ACTION_FINGERPRINT_WAKE_AND_UNLOCK);
- });
+ mLatencyTracker.onActionEnd(type == BiometricSourceType.FACE
+ ? LatencyTracker.ACTION_FACE_WAKE_AND_UNLOCK
+ : LatencyTracker.ACTION_FINGERPRINT_WAKE_AND_UNLOCK);
}
}
@@ -1186,7 +1184,6 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
// When a dream overlay is active, scrimming will cause any expansion to immediately expand.
return (mOccluded && !mDreamOverlayStateController.isOverlayActive())
|| mBouncer.willDismissWithAction()
- || mStatusBar.isFullScreenUserSwitcherState()
|| (mBouncer.isShowing() && mBouncer.isScrimmed())
|| mBouncer.isFullscreenBouncer();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarMoveFromCenterAnimationController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarMoveFromCenterAnimationController.kt
index 6d033477e3c9..79c0984d9bf7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarMoveFromCenterAnimationController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarMoveFromCenterAnimationController.kt
@@ -18,11 +18,13 @@ package com.android.systemui.statusbar.phone
import android.view.View
import android.view.WindowManager
import com.android.systemui.shared.animation.UnfoldMoveFromCenterAnimator
+import com.android.systemui.shared.animation.UnfoldMoveFromCenterAnimator.AlphaProvider
import com.android.systemui.statusbar.phone.PhoneStatusBarViewController.StatusBarViewsCenterProvider
import com.android.systemui.unfold.SysUIUnfoldScope
import com.android.systemui.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener
import com.android.systemui.unfold.util.ScopedUnfoldTransitionProgressProvider
import javax.inject.Inject
+import kotlin.math.max
@SysUIUnfoldScope
class StatusBarMoveFromCenterAnimationController @Inject constructor(
@@ -31,8 +33,11 @@ class StatusBarMoveFromCenterAnimationController @Inject constructor(
) {
private val transitionListener = TransitionListener()
- private val moveFromCenterAnimator = UnfoldMoveFromCenterAnimator(windowManager,
- viewCenterProvider = StatusBarViewsCenterProvider())
+ private val moveFromCenterAnimator = UnfoldMoveFromCenterAnimator(
+ windowManager,
+ viewCenterProvider = StatusBarViewsCenterProvider(),
+ alphaProvider = StatusBarIconsAlphaProvider()
+ )
fun onViewsReady(viewsToAnimate: Array<View>) {
moveFromCenterAnimator.updateDisplayProperties()
@@ -65,4 +70,15 @@ class StatusBarMoveFromCenterAnimationController @Inject constructor(
moveFromCenterAnimator.onTransitionProgress(1f)
}
}
+
+ private class StatusBarIconsAlphaProvider : AlphaProvider {
+ override fun getAlpha(progress: Float): Float {
+ return max(
+ 0f,
+ (progress - ICONS_START_APPEARING_PROGRESS) / (1 - ICONS_START_APPEARING_PROGRESS)
+ )
+ }
+ }
}
+
+private const val ICONS_START_APPEARING_PROGRESS = 0.75F
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 49e712d386e5..1b73595beb7c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
@@ -19,7 +19,6 @@ package com.android.systemui.statusbar.policy;
import static android.os.UserManager.SWITCHABILITY_STATUS_OK;
import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
-import static com.android.systemui.DejankUtils.whitelistIpcs;
import android.annotation.UserIdInt;
import android.app.ActivityManager;
@@ -427,22 +426,6 @@ public class UserSwitcherController implements Dumpable {
return mSimpleUserSwitcher;
}
- public boolean useFullscreenUserSwitcher() {
- // Use adb to override:
- // adb shell settings put system enable_fullscreen_user_switcher 0 # Turn it off.
- // adb shell settings put system enable_fullscreen_user_switcher 1 # Turn it on.
- // Restart SystemUI or adb reboot.
- final int DEFAULT = -1;
- final int overrideUseFullscreenUserSwitcher =
- whitelistIpcs(() -> Settings.System.getInt(mContext.getContentResolver(),
- "enable_fullscreen_user_switcher", DEFAULT));
- if (overrideUseFullscreenUserSwitcher != DEFAULT) {
- return overrideUseFullscreenUserSwitcher != 0;
- }
- // Otherwise default to the build setting.
- return mContext.getResources().getBoolean(R.bool.config_enableFullscreenUserSwitcher);
- }
-
public void setResumeUserOnGuestLogout(boolean resume) {
mResumeUserOnGuestLogout = resume;
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/KeyguardMediaControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/KeyguardMediaControllerTest.kt
index 43d9a755269f..dc7026da2194 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/KeyguardMediaControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/KeyguardMediaControllerTest.kt
@@ -95,7 +95,6 @@ class KeyguardMediaControllerTest : SysuiTestCase() {
fun testVisibleOnKeyguardOrFullScreenUserSwitcher() {
testStateVisibility(StatusBarState.SHADE, GONE)
testStateVisibility(StatusBarState.SHADE_LOCKED, GONE)
- testStateVisibility(StatusBarState.FULLSCREEN_USER_SWITCHER, VISIBLE)
testStateVisibility(StatusBarState.KEYGUARD, VISIBLE)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/nearby/NearbyMediaDevicesServiceTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/nearby/NearbyMediaDevicesServiceTest.kt
new file mode 100644
index 000000000000..c26108619ff4
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/nearby/NearbyMediaDevicesServiceTest.kt
@@ -0,0 +1,124 @@
+package com.android.systemui.media.nearby
+
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.shared.media.INearbyMediaDevicesProvider
+import com.android.systemui.shared.media.INearbyMediaDevicesService
+import com.android.systemui.shared.media.INearbyMediaDevicesUpdateCallback
+import com.android.systemui.shared.media.INearbyMediaDevicesUpdateCallback.RANGE_LONG
+import com.android.systemui.shared.media.INearbyMediaDevicesUpdateCallback.RANGE_WITHIN_REACH
+import com.android.systemui.shared.media.NearbyDevice
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+
+@SmallTest
+class NearbyMediaDevicesServiceTest : SysuiTestCase() {
+
+ private lateinit var service: NearbyMediaDevicesService
+ private lateinit var binderInterface: INearbyMediaDevicesService
+
+ @Before
+ fun setUp() {
+ service = NearbyMediaDevicesService()
+ binderInterface = INearbyMediaDevicesService.Stub.asInterface(service.onBind(null))
+ }
+
+ @Test
+ fun getCurrentNearbyDevices_noProviderRegistered_returnsEmptyList() {
+ assertThat(service.getCurrentNearbyDevices()).isEmpty()
+ }
+
+ @Test
+ fun getCurrentNearbyDevices_providerRegistered_returnsProviderInfo() {
+ val nearbyDevice1 = NearbyDevice("routeId1", RANGE_LONG)
+ val nearbyDevice2 = NearbyDevice("routeId2", RANGE_WITHIN_REACH)
+ val provider = object : INearbyMediaDevicesProvider.Stub() {
+ override fun getCurrentNearbyDevices(): List<NearbyDevice> {
+ return listOf(nearbyDevice1, nearbyDevice2)
+ }
+
+ override fun registerNearbyDevicesCallback(
+ callback: INearbyMediaDevicesUpdateCallback?
+ ) {}
+ override fun unregisterNearbyDevicesCallback(
+ callback: INearbyMediaDevicesUpdateCallback?
+ ) {}
+ }
+ binderInterface.registerProvider(provider)
+
+ val returnedNearbyDevices = service.getCurrentNearbyDevices()
+
+ assertThat(returnedNearbyDevices).isEqualTo(listOf(nearbyDevice1, nearbyDevice2))
+ }
+
+ @Test
+ fun registerNearbyDevicesCallback_noProviderRegistered_noCrash() {
+ // No assert, just needs no crash
+ service.registerNearbyDevicesCallback(object : INearbyMediaDevicesUpdateCallback.Stub() {
+ override fun nearbyDeviceUpdate(routeId: String?, rangeZone: Int) {}
+ })
+ }
+
+ @Test
+ fun registerNearbyDevicesCallback_providerRegistered_providerReceivesCallback() {
+ val provider = object : INearbyMediaDevicesProvider.Stub() {
+ var registeredCallback: INearbyMediaDevicesUpdateCallback? = null
+ override fun getCurrentNearbyDevices(): List<NearbyDevice> = listOf()
+
+ override fun registerNearbyDevicesCallback(
+ callback: INearbyMediaDevicesUpdateCallback?
+ ) {
+ registeredCallback = callback
+ }
+
+ override fun unregisterNearbyDevicesCallback(
+ callback: INearbyMediaDevicesUpdateCallback?
+ ) {}
+ }
+ binderInterface.registerProvider(provider)
+
+ val callback = object : INearbyMediaDevicesUpdateCallback.Stub() {
+ override fun nearbyDeviceUpdate(routeId: String?, rangeZone: Int) {}
+ }
+
+ service.registerNearbyDevicesCallback(callback)
+
+ assertThat(provider.registeredCallback).isEqualTo(callback)
+ }
+
+ @Test
+ fun unregisterNearbyDevicesCallback_noProviderRegistered_noCrash() {
+ // No assert, just needs no crash
+ service.unregisterNearbyDevicesCallback(object : INearbyMediaDevicesUpdateCallback.Stub() {
+ override fun nearbyDeviceUpdate(routeId: String?, rangeZone: Int) {}
+ })
+ }
+
+ @Test
+ fun unregisterNearbyDevicesCallback_providerRegistered_providerReceivesCallback() {
+ val provider = object : INearbyMediaDevicesProvider.Stub() {
+ var unregisteredCallback: INearbyMediaDevicesUpdateCallback? = null
+ override fun getCurrentNearbyDevices(): List<NearbyDevice> = listOf()
+
+ override fun registerNearbyDevicesCallback(
+ callback: INearbyMediaDevicesUpdateCallback?
+ ) {}
+
+ override fun unregisterNearbyDevicesCallback(
+ callback: INearbyMediaDevicesUpdateCallback?
+ ) {
+ unregisteredCallback = callback
+ }
+ }
+ binderInterface.registerProvider(provider)
+
+ val callback = object : INearbyMediaDevicesUpdateCallback.Stub() {
+ override fun nearbyDeviceUpdate(routeId: String?, rangeZone: Int) {}
+ }
+
+ service.unregisterNearbyDevicesCallback(callback)
+
+ assertThat(provider.unregisteredCallback).isEqualTo(callback)
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
index d51d370eecb9..9076e1607be5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
@@ -169,8 +169,6 @@ class LockscreenShadeTransitionControllerTest : SysuiTestCase() {
transitionController.goToLockedShade(null)
whenever(statusbarStateController.state).thenReturn(StatusBarState.SHADE)
transitionController.goToLockedShade(null)
- whenever(statusbarStateController.state).thenReturn(StatusBarState.FULLSCREEN_USER_SWITCHER)
- transitionController.goToLockedShade(null)
verify(statusbarStateController, never()).setState(anyInt())
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt
index b736f389ad6c..a5ea897b6a6f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt
@@ -61,18 +61,16 @@ class StatusBarStateControllerImplTest : SysuiTestCase() {
@Test
fun testChangeState_logged() {
TestableLooper.get(this).runWithLooper {
- controller.state = StatusBarState.FULLSCREEN_USER_SWITCHER
controller.state = StatusBarState.KEYGUARD
controller.state = StatusBarState.SHADE
controller.state = StatusBarState.SHADE_LOCKED
}
val logs = uiEventLogger.logs
- assertEquals(4, logs.size)
+ assertEquals(3, logs.size)
val ids = logs.map(UiEventLoggerFake.FakeUiEvent::eventId)
- assertEquals(StatusBarStateEvent.STATUS_BAR_STATE_FULLSCREEN_USER_SWITCHER.id, ids[0])
- assertEquals(StatusBarStateEvent.STATUS_BAR_STATE_KEYGUARD.id, ids[1])
- assertEquals(StatusBarStateEvent.STATUS_BAR_STATE_SHADE.id, ids[2])
- assertEquals(StatusBarStateEvent.STATUS_BAR_STATE_SHADE_LOCKED.id, ids[3])
+ assertEquals(StatusBarStateEvent.STATUS_BAR_STATE_KEYGUARD.id, ids[0])
+ assertEquals(StatusBarStateEvent.STATUS_BAR_STATE_SHADE.id, ids[1])
+ assertEquals(StatusBarStateEvent.STATUS_BAR_STATE_SHADE_LOCKED.id, ids[2])
}
-} \ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateEventTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateEventTest.kt
index b5b2f1fc0484..79a2008e7542 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateEventTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateEventTest.kt
@@ -33,18 +33,16 @@ class StatusBarStateEventTest : SysuiTestCase() {
StatusBarStateEvent.STATUS_BAR_STATE_SHADE,
StatusBarStateEvent.STATUS_BAR_STATE_SHADE_LOCKED,
StatusBarStateEvent.STATUS_BAR_STATE_KEYGUARD,
- StatusBarStateEvent.STATUS_BAR_STATE_FULLSCREEN_USER_SWITCHER,
StatusBarStateEvent.STATUS_BAR_STATE_UNKNOWN
)
val states = listOf(
StatusBarState.SHADE,
StatusBarState.SHADE_LOCKED,
StatusBarState.KEYGUARD,
- StatusBarState.FULLSCREEN_USER_SWITCHER,
-1
)
events.zip(states).forEach { (event, state) ->
assertEquals(event, StatusBarStateEvent.fromState(state))
}
}
-} \ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
index 8c7d22dde0b7..fb232ba3ac2c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
@@ -38,6 +38,7 @@ import android.testing.TestableLooper.RunWithLooper;
import android.testing.TestableResources;
import com.android.internal.logging.MetricsLogger;
+import com.android.internal.util.LatencyTracker;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.biometrics.AuthController;
@@ -110,6 +111,8 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase {
private KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
@Mock
private SessionTracker mSessionTracker;
+ @Mock
+ private LatencyTracker mLatencyTracker;
private BiometricUnlockController mBiometricUnlockController;
@Before
@@ -133,7 +136,7 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase {
mMetricsLogger, mDumpManager, mPowerManager,
mNotificationMediaManager, mWakefulnessLifecycle, mScreenLifecycle,
mAuthController, mStatusBarStateController, mKeyguardUnlockAnimationController,
- mSessionTracker);
+ mSessionTracker, mLatencyTracker);
mBiometricUnlockController.setKeyguardViewController(mStatusBarKeyguardViewManager);
mBiometricUnlockController.setBiometricModeListener(mBiometricModeListener);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
index bb79941b0e53..107ba8130349 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
@@ -36,6 +36,7 @@ import android.view.ViewGroup;
import androidx.test.filters.SmallTest;
+import com.android.internal.util.LatencyTracker;
import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.KeyguardMessageArea;
import com.android.keyguard.KeyguardMessageAreaController;
@@ -100,6 +101,8 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase {
private ShadeController mShadeController;
@Mock
private DreamOverlayStateController mDreamOverlayStateController;
+ @Mock
+ private LatencyTracker mLatencyTracker;
private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
@@ -127,7 +130,8 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase {
mock(NotificationMediaManager.class),
mKeyguardBouncerFactory,
mKeyguardMessageAreaFactory,
- () -> mShadeController);
+ () -> mShadeController,
+ mLatencyTracker);
mStatusBarKeyguardViewManager.registerStatusBar(
mStatusBar,
mNotificationPanelView,
@@ -171,17 +175,6 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase {
}
@Test
- public void onPanelExpansionChanged_neverHidesFullscreenBouncer() {
- // TODO: StatusBar should not be here, mBouncer.isFullscreenBouncer() should do the same.
- when(mStatusBar.isFullScreenUserSwitcherState()).thenReturn(true);
- mStatusBarKeyguardViewManager.onPanelExpansionChanged(
- /* fraction= */ 0.5f,
- /* expanded= */ false,
- /* tracking= */ true);
- verify(mBouncer).setExpansion(eq(KeyguardBouncer.EXPANSION_VISIBLE));
- }
-
- @Test
public void onPanelExpansionChanged_neverHidesScrimmedBouncer() {
when(mBouncer.isShowing()).thenReturn(true);
when(mBouncer.isScrimmed()).thenReturn(true);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
index 1564dfe8cd06..90b93e797410 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
@@ -885,15 +885,6 @@ public class StatusBarTest extends SysuiTestCase {
}
@Test
- public void testSetState_changesIsFullScreenUserSwitcherState() {
- mStatusBar.setBarStateForTest(StatusBarState.KEYGUARD);
- assertFalse(mStatusBar.isFullScreenUserSwitcherState());
-
- mStatusBar.setBarStateForTest(StatusBarState.FULLSCREEN_USER_SWITCHER);
- assertTrue(mStatusBar.isFullScreenUserSwitcherState());
- }
-
- @Test
public void testShowKeyguardImplementation_setsState() {
when(mLockscreenUserManager.getCurrentProfiles()).thenReturn(new SparseArray<>());
@@ -903,12 +894,6 @@ public class StatusBarTest extends SysuiTestCase {
mStatusBar.showKeyguardImpl();
verify(mStatusBarStateController).setState(
eq(StatusBarState.KEYGUARD), eq(false) /* force */);
-
- // If useFullscreenUserSwitcher is true, state is set to FULLSCREEN_USER_SWITCHER.
- when(mUserSwitcherController.useFullscreenUserSwitcher()).thenReturn(true);
- mStatusBar.showKeyguardImpl();
- verify(mStatusBarStateController).setState(
- eq(StatusBarState.FULLSCREEN_USER_SWITCHER), eq(false) /* force */);
}
@Test
diff --git a/services/Android.bp b/services/Android.bp
index af70692a88e5..b0a5c66b53dd 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -102,6 +102,7 @@ filegroup {
":services.usage-sources",
":services.usb-sources",
":services.voiceinteraction-sources",
+ ":services.wallpapereffectsgeneration-sources",
":services.wifi-sources",
],
visibility: ["//visibility:private"],
@@ -158,6 +159,7 @@ java_library {
"services.usage",
"services.usb",
"services.voiceinteraction",
+ "services.wallpapereffectsgeneration",
"services.wifi",
"service-blobstore",
"service-jobscheduler",
diff --git a/services/accessibility/java/com/android/server/accessibility/SystemActionPerformer.java b/services/accessibility/java/com/android/server/accessibility/SystemActionPerformer.java
index 6744ea8e26a5..803177b6c010 100644
--- a/services/accessibility/java/com/android/server/accessibility/SystemActionPerformer.java
+++ b/services/accessibility/java/com/android/server/accessibility/SystemActionPerformer.java
@@ -295,6 +295,21 @@ public class SystemActionPerformer {
case AccessibilityService.GLOBAL_ACTION_KEYCODE_HEADSETHOOK :
sendDownAndUpKeyEvents(KeyEvent.KEYCODE_HEADSETHOOK);
return true;
+ case AccessibilityService.GLOBAL_ACTION_DPAD_UP:
+ sendDownAndUpKeyEvents(KeyEvent.KEYCODE_DPAD_UP);
+ return true;
+ case AccessibilityService.GLOBAL_ACTION_DPAD_DOWN:
+ sendDownAndUpKeyEvents(KeyEvent.KEYCODE_DPAD_DOWN);
+ return true;
+ case AccessibilityService.GLOBAL_ACTION_DPAD_LEFT:
+ sendDownAndUpKeyEvents(KeyEvent.KEYCODE_DPAD_LEFT);
+ return true;
+ case AccessibilityService.GLOBAL_ACTION_DPAD_RIGHT:
+ sendDownAndUpKeyEvents(KeyEvent.KEYCODE_DPAD_RIGHT);
+ return true;
+ case AccessibilityService.GLOBAL_ACTION_DPAD_CENTER:
+ sendDownAndUpKeyEvents(KeyEvent.KEYCODE_DPAD_CENTER);
+ return true;
default:
Slog.e(TAG, "Invalid action id: " + actionId);
return false;
diff --git a/services/core/Android.bp b/services/core/Android.bp
index 1106fe7270e6..561009fe2a71 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -134,6 +134,7 @@ java_library_static {
"app-compat-annotations",
"framework-tethering.stubs.module_lib",
"service-permission.stubs.system_server",
+ "service-supplementalprocess.stubs.system_server",
],
required: [
diff --git a/services/core/java/com/android/server/app/GameManagerService.java b/services/core/java/com/android/server/app/GameManagerService.java
index 3c9d29d77bbe..551773e3e834 100644
--- a/services/core/java/com/android/server/app/GameManagerService.java
+++ b/services/core/java/com/android/server/app/GameManagerService.java
@@ -20,6 +20,11 @@ import static android.content.Intent.ACTION_PACKAGE_ADDED;
import static android.content.Intent.ACTION_PACKAGE_CHANGED;
import static android.content.Intent.ACTION_PACKAGE_REMOVED;
+import static com.android.internal.R.styleable.GameModeConfig_allowGameAngleDriver;
+import static com.android.internal.R.styleable.GameModeConfig_allowGameDownscaling;
+import static com.android.internal.R.styleable.GameModeConfig_allowGameFpsOverride;
+import static com.android.internal.R.styleable.GameModeConfig_supportsBatteryGameMode;
+import static com.android.internal.R.styleable.GameModeConfig_supportsPerformanceGameMode;
import static com.android.server.wm.CompatModePackages.DOWNSCALED;
import static com.android.server.wm.CompatModePackages.DOWNSCALE_30;
import static com.android.server.wm.CompatModePackages.DOWNSCALE_35;
@@ -54,6 +59,10 @@ import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.content.res.XmlResourceParser;
import android.hardware.power.Mode;
import android.net.Uri;
import android.os.Binder;
@@ -71,8 +80,10 @@ import android.os.ShellCallback;
import android.provider.DeviceConfig;
import android.provider.DeviceConfig.Properties;
import android.util.ArrayMap;
+import android.util.AttributeSet;
import android.util.KeyValueListParser;
import android.util.Slog;
+import android.util.Xml;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
@@ -84,7 +95,11 @@ import com.android.server.ServiceThread;
import com.android.server.SystemService;
import com.android.server.SystemService.TargetUser;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
import java.io.FileDescriptor;
+import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;
@@ -425,12 +440,20 @@ public final class GameManagerService extends IGameManagerService.Stub {
public static final String METADATA_BATTERY_MODE_ENABLE =
"com.android.app.gamemode.battery.enabled";
+ /**
+ * Metadata that allows a game to specify all intervention information with an XML file in
+ * the application field.
+ */
+ public static final String METADATA_GAME_MODE_CONFIG = "android.game_mode_config";
+
+ private static final String GAME_MODE_CONFIG_NODE_NAME = "game-mode-config";
private final String mPackageName;
private final ArrayMap<Integer, GameModeConfiguration> mModeConfigs;
private boolean mPerfModeOptedIn;
private boolean mBatteryModeOptedIn;
private boolean mAllowDownscale;
private boolean mAllowAngle;
+ private boolean mAllowFpsOverride;
GamePackageConfiguration(String packageName, int userId) {
mPackageName = packageName;
@@ -438,18 +461,21 @@ public final class GameManagerService extends IGameManagerService.Stub {
try {
final ApplicationInfo ai = mPackageManager.getApplicationInfoAsUser(packageName,
PackageManager.GET_META_DATA, userId);
- if (ai.metaData != null) {
- mPerfModeOptedIn = ai.metaData.getBoolean(METADATA_PERFORMANCE_MODE_ENABLE);
- mBatteryModeOptedIn = ai.metaData.getBoolean(METADATA_BATTERY_MODE_ENABLE);
- mAllowDownscale = ai.metaData.getBoolean(METADATA_WM_ALLOW_DOWNSCALE, true);
- mAllowAngle = ai.metaData.getBoolean(METADATA_ANGLE_ALLOW_ANGLE, true);
- } else {
- mPerfModeOptedIn = false;
- mBatteryModeOptedIn = false;
- mAllowDownscale = true;
- mAllowAngle = true;
+ if (!parseInterventionFromXml(ai, packageName)) {
+ if (ai.metaData != null) {
+ mPerfModeOptedIn = ai.metaData.getBoolean(METADATA_PERFORMANCE_MODE_ENABLE);
+ mBatteryModeOptedIn = ai.metaData.getBoolean(METADATA_BATTERY_MODE_ENABLE);
+ mAllowDownscale = ai.metaData.getBoolean(METADATA_WM_ALLOW_DOWNSCALE, true);
+ mAllowAngle = ai.metaData.getBoolean(METADATA_ANGLE_ALLOW_ANGLE, true);
+ } else {
+ mPerfModeOptedIn = false;
+ mBatteryModeOptedIn = false;
+ mAllowDownscale = true;
+ mAllowAngle = true;
+ mAllowFpsOverride = true;
+ }
}
- } catch (PackageManager.NameNotFoundException e) {
+ } catch (NameNotFoundException e) {
// Not all packages are installed, hence ignore those that are not installed yet.
Slog.v(TAG, "Failed to get package metadata");
}
@@ -469,6 +495,53 @@ public final class GameManagerService extends IGameManagerService.Stub {
}
}
+ private boolean parseInterventionFromXml(ApplicationInfo ai, String packageName) {
+ boolean xmlFound = false;
+ try (XmlResourceParser parser = ai.loadXmlMetaData(mPackageManager,
+ METADATA_GAME_MODE_CONFIG)) {
+ if (parser == null) {
+ Slog.v(TAG, "No " + METADATA_GAME_MODE_CONFIG
+ + " meta-data found for package " + mPackageName);
+ } else {
+ xmlFound = true;
+ final Resources resources = mPackageManager.getResourcesForApplication(
+ packageName);
+ final AttributeSet attributeSet = Xml.asAttributeSet(parser);
+ int type;
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && type != XmlPullParser.START_TAG) {
+ // Do nothing
+ }
+
+ boolean isStartingTagGameModeConfig =
+ GAME_MODE_CONFIG_NODE_NAME.equals(parser.getName());
+ if (!isStartingTagGameModeConfig) {
+ Slog.w(TAG, "Meta-data does not start with "
+ + GAME_MODE_CONFIG_NODE_NAME
+ + " tag");
+ } else {
+ final TypedArray array = resources.obtainAttributes(attributeSet,
+ com.android.internal.R.styleable.GameModeConfig);
+ mPerfModeOptedIn = array.getBoolean(
+ GameModeConfig_supportsPerformanceGameMode, false);
+ mBatteryModeOptedIn = array.getBoolean(
+ GameModeConfig_supportsBatteryGameMode,
+ false);
+ mAllowDownscale = array.getBoolean(GameModeConfig_allowGameDownscaling,
+ true);
+ mAllowAngle = array.getBoolean(GameModeConfig_allowGameAngleDriver, true);
+ mAllowFpsOverride = array.getBoolean(GameModeConfig_allowGameFpsOverride,
+ true);
+ array.recycle();
+ }
+ }
+ } catch (NameNotFoundException | XmlPullParserException | IOException ex) {
+ Slog.e(TAG, "Error while parsing XML meta-data for "
+ + METADATA_GAME_MODE_CONFIG);
+ }
+ return xmlFound;
+ }
+
/**
* GameModeConfiguration contains all the values for all the interventions associated with
* a game mode.
@@ -497,7 +570,8 @@ public final class GameManagerService extends IGameManagerService.Stub {
mScaling = !mAllowDownscale || willGamePerformOptimizations(mGameMode)
? DEFAULT_SCALING : parser.getString(SCALING_KEY, DEFAULT_SCALING);
- mFps = parser.getString(FPS_KEY, DEFAULT_FPS);
+ mFps = mAllowFpsOverride && !willGamePerformOptimizations(mGameMode)
+ ? parser.getString(FPS_KEY, DEFAULT_FPS) : DEFAULT_FPS;
// We only want to use ANGLE if:
// - We're allowed to use ANGLE (the app hasn't opted out via the manifest) AND
// - The app has not opted in to performing the work itself AND
@@ -691,7 +765,7 @@ public final class GameManagerService extends IGameManagerService.Stub {
try {
return mPackageManager.getPackageUidAsUser(packageName, userId)
== Binder.getCallingUid();
- } catch (PackageManager.NameNotFoundException e) {
+ } catch (NameNotFoundException e) {
return false;
}
}
@@ -855,7 +929,7 @@ public final class GameManagerService extends IGameManagerService.Stub {
*/
@Override
@RequiresPermission(Manifest.permission.MANAGE_GAME_MODE)
- public @GameMode boolean getAngleEnabled(String packageName, int userId)
+ public @GameMode boolean isAngleEnabled(String packageName, int userId)
throws SecurityException {
final int gameMode = getGameMode(packageName, userId);
if (gameMode == GameManager.GAME_MODE_UNSUPPORTED) {
@@ -1413,7 +1487,7 @@ public final class GameManagerService extends IGameManagerService.Stub {
if (applicationInfo.category != ApplicationInfo.CATEGORY_GAME) {
return;
}
- } catch (PackageManager.NameNotFoundException e) {
+ } catch (NameNotFoundException e) {
// Ignore the exception.
}
switch (intent.getAction()) {
diff --git a/services/core/java/com/android/server/app/GameServiceProviderInstanceImpl.java b/services/core/java/com/android/server/app/GameServiceProviderInstanceImpl.java
index af1dd335ab1e..960fbf1d9330 100644
--- a/services/core/java/com/android/server/app/GameServiceProviderInstanceImpl.java
+++ b/services/core/java/com/android/server/app/GameServiceProviderInstanceImpl.java
@@ -50,6 +50,7 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.infra.AndroidFuture;
import com.android.internal.infra.ServiceConnector;
import com.android.server.wm.WindowManagerInternal;
+import com.android.server.wm.WindowManagerInternal.TaskSystemBarsListener;
import com.android.server.wm.WindowManagerService;
import java.util.List;
@@ -62,6 +63,18 @@ final class GameServiceProviderInstanceImpl implements GameServiceProviderInstan
private static final int CREATE_GAME_SESSION_TIMEOUT_MS = 10_000;
private static final boolean DEBUG = false;
+ private final TaskSystemBarsListener mTaskSystemBarsVisibilityListener =
+ new TaskSystemBarsListener() {
+ @Override
+ public void onTransientSystemBarsVisibilityChanged(
+ int taskId,
+ boolean visible,
+ boolean wereRevealedFromSwipeOnSystemBar) {
+ GameServiceProviderInstanceImpl.this.onTransientSystemBarsVisibilityChanged(
+ taskId, visible, wereRevealedFromSwipeOnSystemBar);
+ }
+ };
+
private final TaskStackListener mTaskStackListener = new TaskStackListener() {
@Override
public void onTaskCreated(int taskId, ComponentName componentName) throws RemoteException {
@@ -203,6 +216,8 @@ final class GameServiceProviderInstanceImpl implements GameServiceProviderInstan
} catch (RemoteException e) {
Slog.w(TAG, "Failed to register task stack listener", e);
}
+
+ mWindowManagerInternal.registerTaskSystemBarsListener(mTaskSystemBarsVisibilityListener);
}
@GuardedBy("mLock")
@@ -218,6 +233,9 @@ final class GameServiceProviderInstanceImpl implements GameServiceProviderInstan
Slog.w(TAG, "Failed to unregister task stack listener", e);
}
+ mWindowManagerInternal.unregisterTaskSystemBarsListener(
+ mTaskSystemBarsVisibilityListener);
+
for (GameSessionRecord gameSessionRecord : mGameSessions.values()) {
destroyGameSessionFromRecord(gameSessionRecord);
}
@@ -307,6 +325,37 @@ final class GameServiceProviderInstanceImpl implements GameServiceProviderInstan
}
}
+ private void onTransientSystemBarsVisibilityChanged(
+ int taskId,
+ boolean visible,
+ boolean wereRevealedFromSwipeOnSystemBar) {
+ if (visible && !wereRevealedFromSwipeOnSystemBar) {
+ return;
+ }
+
+ GameSessionRecord gameSessionRecord;
+ synchronized (mLock) {
+ gameSessionRecord = mGameSessions.get(taskId);
+ }
+
+ if (gameSessionRecord == null) {
+ return;
+ }
+
+ IGameSession gameSession = gameSessionRecord.getGameSession();
+ if (gameSession == null) {
+ return;
+ }
+
+ try {
+ gameSession.onTransientSystemBarVisibilityFromRevealGestureChanged(visible);
+ } catch (RemoteException ex) {
+ Slog.w(TAG,
+ "Failed to send transient system bars visibility from reveal gesture for task: "
+ + taskId);
+ }
+ }
+
private void createGameSession(int taskId) {
synchronized (mLock) {
createGameSessionLocked(taskId);
diff --git a/services/core/java/com/android/server/attention/AttentionManagerService.java b/services/core/java/com/android/server/attention/AttentionManagerService.java
index a1395890fd3c..d2fa386ad6ba 100644
--- a/services/core/java/com/android/server/attention/AttentionManagerService.java
+++ b/services/core/java/com/android/server/attention/AttentionManagerService.java
@@ -22,6 +22,7 @@ import static android.content.Context.BIND_INCLUDE_CAPABILITIES;
import static android.provider.DeviceConfig.NAMESPACE_ATTENTION_MANAGER_SERVICE;
import static android.service.attention.AttentionService.ATTENTION_FAILURE_CANCELLED;
import static android.service.attention.AttentionService.ATTENTION_FAILURE_UNKNOWN;
+import static android.service.attention.AttentionService.PROXIMITY_UNKNOWN;
import android.Manifest;
import android.annotation.NonNull;
@@ -29,6 +30,7 @@ import android.annotation.Nullable;
import android.app.ActivityThread;
import android.attention.AttentionManagerInternal;
import android.attention.AttentionManagerInternal.AttentionCallbackInternal;
+import android.attention.AttentionManagerInternal.ProximityCallbackInternal;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
@@ -57,6 +59,7 @@ import android.service.attention.AttentionService.AttentionFailureCodes;
import android.service.attention.AttentionService.AttentionSuccessCodes;
import android.service.attention.IAttentionCallback;
import android.service.attention.IAttentionService;
+import android.service.attention.IProximityCallback;
import android.text.TextUtils;
import android.util.Slog;
@@ -134,6 +137,15 @@ public class AttentionManagerService extends SystemService {
@GuardedBy("mLock")
AttentionCheck mCurrentAttentionCheck;
+ /**
+ * A proxy for relaying proximity information between the Attention Service and the client.
+ * The proxy will be initialized when the client calls onStartProximityUpdates and will be
+ * disabled only when the client calls onStopProximityUpdates.
+ */
+ @VisibleForTesting
+ @GuardedBy("mLock")
+ ProximityUpdate mCurrentProximityUpdate;
+
public AttentionManagerService(Context context) {
this(context, (PowerManager) context.getSystemService(Context.POWER_SERVICE),
new Object(), null);
@@ -315,6 +327,77 @@ public class AttentionManagerService extends SystemService {
}
}
+ /**
+ * Requests the continuous updates of proximity signal via the provided callback,
+ * until the given callback is stopped.
+ *
+ * Calling this multiple times for duplicate requests will be no-ops, returning true.
+ *
+ * @return {@code true} if the framework was able to dispatch the request
+ */
+ @VisibleForTesting
+ boolean onStartProximityUpdates(ProximityCallbackInternal callbackInternal) {
+ Objects.requireNonNull(callbackInternal);
+ if (!mIsServiceEnabled) {
+ Slog.w(LOG_TAG, "Trying to call onProximityUpdate() on an unsupported device.");
+ return false;
+ }
+
+ if (!isServiceAvailable()) {
+ Slog.w(LOG_TAG, "Service is not available at this moment.");
+ return false;
+ }
+
+ // don't allow proximity request in screen off state.
+ // This behavior might change in the future.
+ if (!mPowerManager.isInteractive()) {
+ Slog.w(LOG_TAG, "Proximity Service is unavailable during screen off at this moment.");
+ return false;
+ }
+
+ synchronized (mLock) {
+ // schedule shutting down the connection if no one resets this timer
+ freeIfInactiveLocked();
+
+ // lazily start the service, which should be very lightweight to start
+ bindLocked();
+
+ /*
+ Prevent spamming with multiple requests, only one at a time is allowed.
+ If there are use-cases for keeping track of multiple requests, we
+ can refactor ProximityUpdate object to keep track of multiple internal callbacks.
+ */
+ if (mCurrentProximityUpdate != null && mCurrentProximityUpdate.mStartedUpdates) {
+ if (mCurrentProximityUpdate.mCallbackInternal == callbackInternal) {
+ Slog.w(LOG_TAG, "Provided callback is already registered. Skipping.");
+ return true;
+ } else {
+ // reject the new request since the old request is still alive.
+ Slog.w(LOG_TAG, "New proximity update cannot be processed because there is "
+ + "already an ongoing update");
+ return false;
+ }
+ }
+ mCurrentProximityUpdate = new ProximityUpdate(callbackInternal);
+ return mCurrentProximityUpdate.startUpdates();
+ }
+ }
+
+ /** Cancels the specified proximity registration. */
+ @VisibleForTesting
+ void onStopProximityUpdates(ProximityCallbackInternal callbackInternal) {
+ synchronized (mLock) {
+ if (mCurrentProximityUpdate == null
+ || !mCurrentProximityUpdate.mCallbackInternal.equals(callbackInternal)
+ || !mCurrentProximityUpdate.mStartedUpdates) {
+ Slog.w(LOG_TAG, "Cannot stop a non-current callback");
+ return;
+ }
+ mCurrentProximityUpdate.cancelUpdates();
+ mCurrentProximityUpdate = null;
+ }
+ }
+
@GuardedBy("mLock")
@VisibleForTesting
protected void freeIfInactiveLocked() {
@@ -390,15 +473,18 @@ public class AttentionManagerService extends SystemService {
ipw.println("Class=" + mComponentName.getClassName());
ipw.decreaseIndent();
}
- ipw.println("binding=" + mBinding);
- ipw.println("current attention check:");
synchronized (mLock) {
+ ipw.println("binding=" + mBinding);
+ ipw.println("current attention check:");
if (mCurrentAttentionCheck != null) {
mCurrentAttentionCheck.dump(ipw);
}
if (mAttentionCheckCacheBuffer != null) {
mAttentionCheckCacheBuffer.dump(ipw);
}
+ if (mCurrentProximityUpdate != null) {
+ mCurrentProximityUpdate.dump(ipw);
+ }
}
}
@@ -417,6 +503,17 @@ public class AttentionManagerService extends SystemService {
public void cancelAttentionCheck(AttentionCallbackInternal callbackInternal) {
AttentionManagerService.this.cancelAttentionCheck(callbackInternal);
}
+
+ @Override
+ public boolean onStartProximityUpdates(
+ ProximityCallbackInternal callback) {
+ return AttentionManagerService.this.onStartProximityUpdates(callback);
+ }
+
+ @Override
+ public void onStopProximityUpdates(ProximityCallbackInternal callback) {
+ AttentionManagerService.this.onStopProximityUpdates(callback);
+ }
}
@VisibleForTesting
@@ -536,6 +633,71 @@ public class AttentionManagerService extends SystemService {
}
}
+ @VisibleForTesting
+ final class ProximityUpdate {
+ private final ProximityCallbackInternal mCallbackInternal;
+ private final IProximityCallback mIProximityCallback;
+ private boolean mStartedUpdates;
+
+ ProximityUpdate(ProximityCallbackInternal callbackInternal) {
+ mCallbackInternal = callbackInternal;
+ mIProximityCallback = new IProximityCallback.Stub() {
+ @Override
+ public void onProximityUpdate(double distance) {
+ synchronized (mLock) {
+ mCallbackInternal.onProximityUpdate(distance);
+ freeIfInactiveLocked();
+ }
+ }
+ };
+ }
+
+ boolean startUpdates() {
+ synchronized (mLock) {
+ if (mStartedUpdates) {
+ Slog.w(LOG_TAG, "Already registered to a proximity service.");
+ return false;
+ }
+ if (mService == null) {
+ Slog.w(LOG_TAG,
+ "There is no service bound. Proximity update request rejected.");
+ return false;
+ }
+ try {
+ mService.onStartProximityUpdates(mIProximityCallback);
+ mStartedUpdates = true;
+ } catch (RemoteException e) {
+ Slog.e(LOG_TAG, "Cannot call into the AttentionService", e);
+ return false;
+ }
+ }
+ return true;
+ }
+
+ void cancelUpdates() {
+ synchronized (mLock) {
+ if (mStartedUpdates) {
+ if (mService == null) {
+ mStartedUpdates = false;
+ return;
+ }
+ try {
+ mService.onStopProximityUpdates();
+ mStartedUpdates = false;
+ } catch (RemoteException e) {
+ Slog.e(LOG_TAG, "Cannot call into the AttentionService", e);
+ }
+ }
+ }
+ }
+
+ void dump(IndentingPrintWriter ipw) {
+ ipw.increaseIndent();
+ ipw.println("is StartedUpdates=" + mStartedUpdates);
+ ipw.decreaseIndent();
+ }
+ }
+
private void appendResultToAttentionCacheBuffer(AttentionCheckCache cache) {
synchronized (mLock) {
if (mAttentionCheckCacheBuffer == null) {
@@ -593,6 +755,18 @@ public class AttentionManagerService extends SystemService {
mCurrentAttentionCheck.mCallbackInternal.onFailure(ATTENTION_FAILURE_UNKNOWN);
}
}
+ if (mCurrentProximityUpdate != null && mCurrentProximityUpdate.mStartedUpdates) {
+ if (mService != null) {
+ try {
+ mService.onStartProximityUpdates(mCurrentProximityUpdate.mIProximityCallback);
+ } catch (RemoteException e) {
+ Slog.e(LOG_TAG, "Cannot call into the AttentionService", e);
+ }
+ } else {
+ mCurrentProximityUpdate.cancelUpdates();
+ mCurrentProximityUpdate = null;
+ }
+ }
}
@VisibleForTesting
@@ -609,7 +783,9 @@ public class AttentionManagerService extends SystemService {
switch (msg.what) {
// Do not occupy resources when not in use - unbind proactively.
case CHECK_CONNECTION_EXPIRATION: {
- cancelAndUnbindLocked();
+ synchronized (mLock) {
+ cancelAndUnbindLocked();
+ }
}
break;
@@ -653,10 +829,15 @@ public class AttentionManagerService extends SystemService {
@GuardedBy("mLock")
private void cancelAndUnbindLocked() {
synchronized (mLock) {
- if (mCurrentAttentionCheck == null) {
+ if (mCurrentAttentionCheck == null && mCurrentProximityUpdate == null) {
return;
}
- cancel();
+ if (mCurrentAttentionCheck != null) {
+ cancel();
+ }
+ if (mCurrentProximityUpdate != null) {
+ mCurrentProximityUpdate.cancelUpdates();
+ }
if (mService == null) {
return;
}
@@ -702,7 +883,9 @@ public class AttentionManagerService extends SystemService {
@Override
public void onReceive(Context context, Intent intent) {
if (Intent.ACTION_SCREEN_OFF.equals(intent.getAction())) {
- cancelAndUnbindLocked();
+ synchronized (mLock) {
+ cancelAndUnbindLocked();
+ }
}
}
}
@@ -730,8 +913,27 @@ public class AttentionManagerService extends SystemService {
}
}
+ class TestableProximityCallbackInternal extends ProximityCallbackInternal {
+ private double mLastCallbackCode = PROXIMITY_UNKNOWN;
+
+ @Override
+ public void onProximityUpdate(double distance) {
+ mLastCallbackCode = distance;
+ }
+
+ public void reset() {
+ mLastCallbackCode = PROXIMITY_UNKNOWN;
+ }
+
+ public double getLastCallbackCode() {
+ return mLastCallbackCode;
+ }
+ }
+
final TestableAttentionCallbackInternal mTestableAttentionCallback =
new TestableAttentionCallbackInternal();
+ final TestableProximityCallbackInternal mTestableProximityCallback =
+ new TestableProximityCallbackInternal();
@Override
public int onCommand(@Nullable final String cmd) {
@@ -749,6 +951,10 @@ public class AttentionManagerService extends SystemService {
return cmdCallCheckAttention();
case "cancelCheckAttention":
return cmdCallCancelAttention();
+ case "onStartProximityUpdates":
+ return cmdCallOnStartProximityUpdates();
+ case "onStopProximityUpdates":
+ return cmdCallOnStopProximityUpdates();
default:
throw new IllegalArgumentException("Invalid argument");
}
@@ -758,6 +964,8 @@ public class AttentionManagerService extends SystemService {
return cmdClearTestableAttentionService();
case "getLastTestCallbackCode":
return cmdGetLastTestCallbackCode();
+ case "getLastTestProximityCallbackCode":
+ return cmdGetLastTestProximityCallbackCode();
default:
return handleDefaultCommands(cmd);
}
@@ -782,6 +990,7 @@ public class AttentionManagerService extends SystemService {
private int cmdClearTestableAttentionService() {
sTestAttentionServicePackage = "";
mTestableAttentionCallback.reset();
+ mTestableProximityCallback.reset();
resetStates();
return 0;
}
@@ -800,6 +1009,20 @@ public class AttentionManagerService extends SystemService {
return 0;
}
+ private int cmdCallOnStartProximityUpdates() {
+ final PrintWriter out = getOutPrintWriter();
+ boolean calledSuccessfully = onStartProximityUpdates(mTestableProximityCallback);
+ out.println(calledSuccessfully ? "true" : "false");
+ return 0;
+ }
+
+ private int cmdCallOnStopProximityUpdates() {
+ final PrintWriter out = getOutPrintWriter();
+ onStopProximityUpdates(mTestableProximityCallback);
+ out.println("true");
+ return 0;
+ }
+
private int cmdResolveAttentionServiceComponent() {
final PrintWriter out = getOutPrintWriter();
ComponentName resolvedComponent = resolveAttentionService(mContext);
@@ -813,7 +1036,16 @@ public class AttentionManagerService extends SystemService {
return 0;
}
+ private int cmdGetLastTestProximityCallbackCode() {
+ final PrintWriter out = getOutPrintWriter();
+ out.println(mTestableProximityCallback.getLastCallbackCode());
+ return 0;
+ }
+
private void resetStates() {
+ synchronized (mLock) {
+ mCurrentProximityUpdate = null;
+ }
mComponentName = resolveAttentionService(mContext);
}
@@ -844,11 +1076,24 @@ public class AttentionManagerService extends SystemService {
+ " (to see the result, call getLastTestCallbackCode)");
out.println(" := false, otherwise");
out.println(" call cancelCheckAttention: Cancels check attention");
+ out.println(" call onStartProximityUpdates: Calls onStartProximityUpdates");
+ out.println(" ---returns:");
+ out.println(
+ " := true, if the request was successfully dispatched to the service "
+ + "implementation."
+ + " (to see the result, call getLastTestProximityCallbackCode)");
+ out.println(" := false, otherwise");
+ out.println(" call onStopProximityUpdates: Cancels proximity updates");
out.println(" getLastTestCallbackCode");
out.println(" ---returns:");
out.println(
" := An integer, representing the last callback code received from the "
+ "bounded implementation. If none, it will return -1");
+ out.println(" getLastTestProximityCallbackCode");
+ out.println(" ---returns:");
+ out.println(
+ " := A double, representing the last proximity value received from the "
+ + "bounded implementation. If none, it will return -1.0");
}
}
diff --git a/services/core/java/com/android/server/clipboard/ClipboardService.java b/services/core/java/com/android/server/clipboard/ClipboardService.java
index 28508f46bfe6..53fe4509b1cc 100644
--- a/services/core/java/com/android/server/clipboard/ClipboardService.java
+++ b/services/core/java/com/android/server/clipboard/ClipboardService.java
@@ -1090,6 +1090,10 @@ public class ClipboardService extends SystemService {
&& mAutofillInternal.isAugmentedAutofillServiceForUser(uid, userId)) {
return;
}
+ if (mPm.checkPermission(Manifest.permission.SUPPRESS_CLIPBOARD_ACCESS_NOTIFICATION,
+ callingPackage) == PackageManager.PERMISSION_GRANTED) {
+ return;
+ }
// Don't notify if already notified for this uid and clip.
if (clipboard.mNotifiedUids.get(uid)) {
return;
diff --git a/services/core/java/com/android/server/display/AutomaticBrightnessController.java b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
index 1b552577308d..162eb0e188b9 100644
--- a/services/core/java/com/android/server/display/AutomaticBrightnessController.java
+++ b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
@@ -201,6 +201,10 @@ class AutomaticBrightnessController {
// Controls High Brightness Mode.
private HighBrightnessModeController mHbmController;
+ // Throttles (caps) maximum allowed brightness
+ private BrightnessThrottler mBrightnessThrottler;
+ private boolean mIsBrightnessThrottled;
+
// Context-sensitive brightness configurations require keeping track of the foreground app's
// package name and category, which is done by registering a TaskStackListener to call back to
// us onTaskStackChanged, and then using the ActivityTaskManager to get the foreground app's
@@ -226,7 +230,7 @@ class AutomaticBrightnessController {
long brighteningLightDebounceConfig, long darkeningLightDebounceConfig,
boolean resetAmbientLuxAfterWarmUpConfig, HysteresisLevels ambientBrightnessThresholds,
HysteresisLevels screenBrightnessThresholds, Context context,
- HighBrightnessModeController hbmController,
+ HighBrightnessModeController hbmController, BrightnessThrottler brightnessThrottler,
BrightnessMappingStrategy idleModeBrightnessMapper, int ambientLightHorizonShort,
int ambientLightHorizonLong) {
this(new Injector(), callbacks, looper, sensorManager, lightSensor,
@@ -235,8 +239,8 @@ class AutomaticBrightnessController {
lightSensorRate, initialLightSensorRate, brighteningLightDebounceConfig,
darkeningLightDebounceConfig, resetAmbientLuxAfterWarmUpConfig,
ambientBrightnessThresholds, screenBrightnessThresholds, context,
- hbmController, idleModeBrightnessMapper, ambientLightHorizonShort,
- ambientLightHorizonLong
+ hbmController, brightnessThrottler, idleModeBrightnessMapper,
+ ambientLightHorizonShort, ambientLightHorizonLong
);
}
@@ -249,7 +253,7 @@ class AutomaticBrightnessController {
long brighteningLightDebounceConfig, long darkeningLightDebounceConfig,
boolean resetAmbientLuxAfterWarmUpConfig, HysteresisLevels ambientBrightnessThresholds,
HysteresisLevels screenBrightnessThresholds, Context context,
- HighBrightnessModeController hbmController,
+ HighBrightnessModeController hbmController, BrightnessThrottler brightnessThrottler,
BrightnessMappingStrategy idleModeBrightnessMapper, int ambientLightHorizonShort,
int ambientLightHorizonLong) {
mInjector = injector;
@@ -291,6 +295,7 @@ class AutomaticBrightnessController {
mForegroundAppCategory = ApplicationInfo.CATEGORY_UNDEFINED;
mPendingForegroundAppCategory = ApplicationInfo.CATEGORY_UNDEFINED;
mHbmController = hbmController;
+ mBrightnessThrottler = brightnessThrottler;
mInteractiveModeBrightnessMapper = interactiveModeBrightnessMapper;
mIdleModeBrightnessMapper = idleModeBrightnessMapper;
// Initialize to active (normal) screen brightness mode
@@ -365,6 +370,13 @@ class AutomaticBrightnessController {
prepareBrightnessAdjustmentSample();
}
changed |= setLightSensorEnabled(enable && !dozing);
+
+ if (mIsBrightnessThrottled != mBrightnessThrottler.isThrottled()) {
+ // Maximum brightness has changed, so recalculate display brightness.
+ mIsBrightnessThrottled = mBrightnessThrottler.isThrottled();
+ changed = true;
+ }
+
if (changed) {
updateAutoBrightness(false /*sendUpdate*/, userInitiatedChange);
}
@@ -855,8 +867,11 @@ class AutomaticBrightnessController {
// Clamps values with float range [0.0-1.0]
private float clampScreenBrightness(float value) {
- return MathUtils.constrain(value,
- mHbmController.getCurrentBrightnessMin(), mHbmController.getCurrentBrightnessMax());
+ final float minBrightness = Math.min(mHbmController.getCurrentBrightnessMin(),
+ mBrightnessThrottler.getBrightnessCap());
+ final float maxBrightness = Math.min(mHbmController.getCurrentBrightnessMax(),
+ mBrightnessThrottler.getBrightnessCap());
+ return MathUtils.constrain(value, minBrightness, maxBrightness);
}
private void prepareBrightnessAdjustmentSample() {
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 3494342a66fb..6ae1a5a96a24 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -974,7 +974,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
lightSensorRate, initialLightSensorRate, brighteningLightDebounce,
darkeningLightDebounce, autoBrightnessResetAmbientLuxAfterWarmUp,
ambientBrightnessThresholds, screenBrightnessThresholds, mContext,
- mHbmController, mIdleModeBrightnessMapper,
+ mHbmController, mBrightnessThrottler, mIdleModeBrightnessMapper,
mDisplayDeviceConfig.getAmbientHorizonShort(),
mDisplayDeviceConfig.getAmbientHorizonLong());
} else {
@@ -1347,6 +1347,29 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
mBrightnessReasonTemp.setReason(BrightnessReason.REASON_MANUAL);
}
+ // Now that a desired brightness has been calculated, apply brightness throttling. The
+ // dimming and low power transformations that follow can only dim brightness further.
+ //
+ // We didn't do this earlier through brightness clamping because we need to know both
+ // unthrottled (unclamped/ideal) and throttled brightness levels for subsequent operations.
+ // Note throttling effectively changes the allowed brightness range, so, similarly to HBM,
+ // we broadcast this change through setting.
+ final float unthrottledBrightnessState = brightnessState;
+ if (mBrightnessThrottler.isThrottled()) {
+ brightnessState = Math.min(brightnessState, mBrightnessThrottler.getBrightnessCap());
+ mBrightnessReasonTemp.addModifier(BrightnessReason.MODIFIER_THROTTLED);
+ if (!mAppliedThrottling) {
+ // Brightness throttling is needed, so do so quickly.
+ // Later, when throttling is removed, we let other mechanisms decide on speed.
+ slowChange = false;
+ updateScreenBrightnessSetting = true;
+ }
+ mAppliedThrottling = true;
+ } else if (mAppliedThrottling) {
+ mAppliedThrottling = false;
+ updateScreenBrightnessSetting = true;
+ }
+
if (updateScreenBrightnessSetting) {
// Tell the rest of the system about the new brightness in case we had to change it
// for things like auto-brightness or high-brightness-mode. Note that we do this
@@ -1393,20 +1416,6 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
mAppliedLowPower = false;
}
- // Apply brightness throttling after applying all other transforms
- final float unthrottledBrightnessState = brightnessState;
- if (mBrightnessThrottler.isThrottled()) {
- brightnessState = Math.min(brightnessState, mBrightnessThrottler.getBrightnessCap());
- mBrightnessReasonTemp.addModifier(BrightnessReason.MODIFIER_THROTTLED);
- if (!mAppliedThrottling) {
- slowChange = false;
- }
- mAppliedThrottling = true;
- } else if (mAppliedThrottling) {
- slowChange = false;
- mAppliedThrottling = false;
- }
-
// The current brightness to use has been calculated at this point, and HbmController should
// be notified so that it can accurately calculate HDR or HBM levels. We specifically do it
// here instead of having HbmController listen to the brightness setting because certain
@@ -1656,6 +1665,10 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
private boolean saveBrightnessInfo(float brightness, float adjustedBrightness) {
synchronized (mCachedBrightnessInfo) {
+ final float minBrightness = Math.min(mHbmController.getCurrentBrightnessMin(),
+ mBrightnessThrottler.getBrightnessCap());
+ final float maxBrightness = Math.min(mHbmController.getCurrentBrightnessMax(),
+ mBrightnessThrottler.getBrightnessCap());
boolean changed = false;
changed |=
@@ -1666,10 +1679,10 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
adjustedBrightness);
changed |=
mCachedBrightnessInfo.checkAndSetFloat(mCachedBrightnessInfo.brightnessMin,
- mHbmController.getCurrentBrightnessMin());
+ minBrightness);
changed |=
mCachedBrightnessInfo.checkAndSetFloat(mCachedBrightnessInfo.brightnessMax,
- mHbmController.getCurrentBrightnessMax());
+ maxBrightness);
changed |=
mCachedBrightnessInfo.checkAndSetInt(mCachedBrightnessInfo.hbmMode,
mHbmController.getHighBrightnessMode());
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecConfig.java b/services/core/java/com/android/server/hdmi/HdmiCecConfig.java
index 65ec1c07c4a1..4792821f652b 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecConfig.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecConfig.java
@@ -385,6 +385,16 @@ public class HdmiCecConfig {
R.bool.config_cecTvSendStandbyOnSleepDisabled_allowed,
R.bool.config_cecTvSendStandbyOnSleepDisabled_default);
+ Setting setMenuLanguage = registerSetting(
+ HdmiControlManager.CEC_SETTING_NAME_SET_MENU_LANGUAGE,
+ R.bool.config_cecSetMenuLanguage_userConfigurable);
+ setMenuLanguage.registerValue(HdmiControlManager.SET_MENU_LANGUAGE_ENABLED,
+ R.bool.config_cecSetMenuLanguageEnabled_allowed,
+ R.bool.config_cecSetMenuLanguageEnabled_default);
+ setMenuLanguage.registerValue(HdmiControlManager.SET_MENU_LANGUAGE_DISABLED,
+ R.bool.config_cecSetMenuLanguageDisabled_allowed,
+ R.bool.config_cecSetMenuLanguageDisabled_default);
+
Setting rcProfileTv = registerSetting(
HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_TV,
R.bool.config_cecRcProfileTv_userConfigurable);
@@ -697,6 +707,8 @@ public class HdmiCecConfig {
return STORAGE_SHARED_PREFS;
case HdmiControlManager.CEC_SETTING_NAME_TV_SEND_STANDBY_ON_SLEEP:
return STORAGE_SHARED_PREFS;
+ case HdmiControlManager.CEC_SETTING_NAME_SET_MENU_LANGUAGE:
+ return STORAGE_SHARED_PREFS;
case HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_TV:
return STORAGE_SHARED_PREFS;
case HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_ROOT_MENU:
@@ -768,6 +780,8 @@ public class HdmiCecConfig {
return setting.getName();
case HdmiControlManager.CEC_SETTING_NAME_TV_SEND_STANDBY_ON_SLEEP:
return setting.getName();
+ case HdmiControlManager.CEC_SETTING_NAME_SET_MENU_LANGUAGE:
+ return setting.getName();
case HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_TV:
return setting.getName();
case HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_ROOT_MENU:
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
index c674ffebfe92..454a76ac04f4 100755
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
@@ -901,17 +901,12 @@ abstract class HdmiCecLocalDevice {
protected int handleVendorCommandWithId(HdmiCecMessage message) {
byte[] params = message.getParams();
int vendorId = HdmiUtils.threeBytesToInt(params);
- if (vendorId == mService.getVendorId()) {
- if (!mService.invokeVendorCommandListenersOnReceived(
- mDeviceType, message.getSource(), message.getDestination(), params, true)) {
- return Constants.ABORT_REFUSED;
- }
- } else if (message.getDestination() != Constants.ADDR_BROADCAST
- && message.getSource() != Constants.ADDR_UNREGISTERED) {
- Slog.v(TAG, "Wrong direct vendor command. Replying with <Feature Abort>");
- return Constants.ABORT_UNRECOGNIZED_OPCODE;
- } else {
+ if (message.getDestination() == Constants.ADDR_BROADCAST
+ || message.getSource() == Constants.ADDR_UNREGISTERED) {
Slog.v(TAG, "Wrong broadcast vendor command. Ignoring");
+ } else if (!mService.invokeVendorCommandListenersOnReceived(
+ mDeviceType, message.getSource(), message.getDestination(), params, true)) {
+ return Constants.ABORT_REFUSED;
}
return Constants.HANDLED;
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
index f413fbd5c9b2..0edcea548055 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
@@ -50,9 +50,6 @@ import java.util.Locale;
public class HdmiCecLocalDevicePlayback extends HdmiCecLocalDeviceSource {
private static final String TAG = "HdmiCecLocalDevicePlayback";
- private static final boolean SET_MENU_LANGUAGE =
- HdmiProperties.set_menu_language_enabled().orElse(false);
-
// How long to wait after hotplug out before possibly going to Standby.
@VisibleForTesting
static final long STANDBY_AFTER_HOTPLUG_OUT_DELAY_MS = 30_000;
@@ -388,7 +385,9 @@ public class HdmiCecLocalDevicePlayback extends HdmiCecLocalDeviceSource {
@Constants.HandleMessageResult
protected int handleSetMenuLanguage(HdmiCecMessage message) {
assertRunOnServiceThread();
- if (!SET_MENU_LANGUAGE) {
+ if (mService.getHdmiCecConfig().getIntValue(
+ HdmiControlManager.CEC_SETTING_NAME_SET_MENU_LANGUAGE)
+ == HdmiControlManager.SET_MENU_LANGUAGE_DISABLED) {
return Constants.ABORT_UNRECOGNIZED_OPCODE;
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecStandbyModeHandler.java b/services/core/java/com/android/server/hdmi/HdmiCecStandbyModeHandler.java
index 6f7473d60121..57fe9e6a4acc 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecStandbyModeHandler.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecStandbyModeHandler.java
@@ -133,6 +133,7 @@ public final class HdmiCecStandbyModeHandler {
addHandler(Constants.MESSAGE_SET_OSD_NAME, mBypasser);
addHandler(Constants.MESSAGE_DEVICE_VENDOR_ID, mBypasser);
addHandler(Constants.MESSAGE_REPORT_POWER_STATUS, mBypasser);
+ addHandler(Constants.MESSAGE_GIVE_FEATURES, mBypasser);
addHandler(Constants.MESSAGE_USER_CONTROL_PRESSED, mUserControlProcessedHandler);
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index 8391e0b4e19a..8ac233114b48 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -1701,11 +1701,11 @@ public class HdmiControlService extends SystemService {
class VendorCommandListenerRecord implements IBinder.DeathRecipient {
private final IHdmiVendorCommandListener mListener;
- private final int mDeviceType;
+ private final int mVendorId;
- public VendorCommandListenerRecord(IHdmiVendorCommandListener listener, int deviceType) {
+ VendorCommandListenerRecord(IHdmiVendorCommandListener listener, int vendorId) {
mListener = listener;
- mDeviceType = deviceType;
+ mVendorId = vendorId;
}
@Override
@@ -2191,10 +2191,10 @@ public class HdmiControlService extends SystemService {
}
@Override
- public void addVendorCommandListener(final IHdmiVendorCommandListener listener,
- final int deviceType) {
+ public void addVendorCommandListener(
+ final IHdmiVendorCommandListener listener, final int vendorId) {
initBinderCall();
- HdmiControlService.this.addVendorCommandListener(listener, deviceType);
+ HdmiControlService.this.addVendorCommandListener(listener, vendorId);
}
@Override
@@ -3354,8 +3354,9 @@ public class HdmiControlService extends SystemService {
mStandbyMessageReceived = false;
}
- private void addVendorCommandListener(IHdmiVendorCommandListener listener, int deviceType) {
- VendorCommandListenerRecord record = new VendorCommandListenerRecord(listener, deviceType);
+ @VisibleForTesting
+ void addVendorCommandListener(IHdmiVendorCommandListener listener, int vendorId) {
+ VendorCommandListenerRecord record = new VendorCommandListenerRecord(listener, vendorId);
try {
listener.asBinder().linkToDeath(record, 0);
} catch (RemoteException e) {
@@ -3374,8 +3375,14 @@ public class HdmiControlService extends SystemService {
return false;
}
for (VendorCommandListenerRecord record : mVendorCommandListenerRecords) {
- if (record.mDeviceType != deviceType) {
- continue;
+ if (hasVendorId) {
+ int vendorId =
+ ((params[0] & 0xFF) << 16)
+ + ((params[1] & 0xFF) << 8)
+ + (params[2] & 0xFF);
+ if (record.mVendorId != vendorId) {
+ continue;
+ }
}
try {
record.mListener.onReceived(srcAddress, destAddress, params, hasVendorId);
diff --git a/services/core/java/com/android/server/input/GestureMonitorSpyWindow.java b/services/core/java/com/android/server/input/GestureMonitorSpyWindow.java
new file mode 100644
index 000000000000..dbd3f3529208
--- /dev/null
+++ b/services/core/java/com/android/server/input/GestureMonitorSpyWindow.java
@@ -0,0 +1,95 @@
+/*
+ * 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.input;
+
+import static android.os.InputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
+
+import android.os.IBinder;
+import android.view.InputApplicationHandle;
+import android.view.InputChannel;
+import android.view.InputMonitor;
+import android.view.InputWindowHandle;
+import android.view.SurfaceControl;
+import android.view.WindowManager;
+
+/**
+ * An internal implementation of an {@link InputMonitor} that uses a spy window.
+ *
+ * This spy window is a layer container in the SurfaceFlinger hierarchy that does not have any
+ * graphical buffer, but can still receive input. It is parented to the DisplayContent so
+ * that it can spy on any pointer events that start in the DisplayContent bounds. When the
+ * object is constructed, it will add itself to SurfaceFlinger.
+ */
+class GestureMonitorSpyWindow {
+ final InputApplicationHandle mApplicationHandle;
+ final InputWindowHandle mWindowHandle;
+
+ // The token, InputChannel, and SurfaceControl are owned by this object.
+ final IBinder mMonitorToken;
+ final InputChannel mClientChannel;
+ final SurfaceControl mInputSurface;
+
+ GestureMonitorSpyWindow(IBinder token, String name, int displayId, int pid, int uid,
+ SurfaceControl sc, InputChannel inputChannel) {
+ mMonitorToken = token;
+ mClientChannel = inputChannel;
+ mInputSurface = sc;
+
+ mApplicationHandle = new InputApplicationHandle(null, name,
+ DEFAULT_DISPATCHING_TIMEOUT_MILLIS);
+ mWindowHandle = new InputWindowHandle(mApplicationHandle, displayId);
+
+ mWindowHandle.name = name;
+ mWindowHandle.token = mClientChannel.getToken();
+ mWindowHandle.layoutParamsType = WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY;
+ mWindowHandle.layoutParamsFlags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
+ mWindowHandle.dispatchingTimeoutMillis = DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
+ mWindowHandle.visible = true;
+ mWindowHandle.focusable = false;
+ mWindowHandle.hasWallpaper = false;
+ mWindowHandle.paused = false;
+ mWindowHandle.ownerPid = pid;
+ mWindowHandle.ownerUid = uid;
+ mWindowHandle.inputFeatures = WindowManager.LayoutParams.INPUT_FEATURE_SPY;
+ mWindowHandle.scaleFactor = 1.0f;
+ mWindowHandle.trustedOverlay = true;
+ mWindowHandle.replaceTouchableRegionWithCrop(null /* use this surface's bounds */);
+
+ final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
+ t.setInputWindowInfo(mInputSurface, mWindowHandle);
+ t.setLayer(mInputSurface, Integer.MAX_VALUE);
+ t.setPosition(mInputSurface, 0, 0);
+ t.setCrop(mInputSurface, null /* crop to parent surface */);
+ t.show(mInputSurface);
+
+ t.apply();
+ }
+
+ void remove() {
+ final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
+ t.hide(mInputSurface);
+ t.remove(mInputSurface);
+ t.apply();
+
+ mClientChannel.dispose();
+ }
+
+ String dump() {
+ return "name='" + mWindowHandle.name + "', inputChannelToken="
+ + mClientChannel.getToken() + " displayId=" + mWindowHandle.displayId;
+ }
+}
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index 783a88ca29bf..64b4da7c5bba 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -150,6 +150,8 @@ public class InputManagerService extends IInputManager.Stub
static final String TAG = "InputManager";
static final boolean DEBUG = false;
+ private static final boolean USE_SPY_WINDOW_GESTURE_MONITORS = false;
+
private static final String EXCLUDED_DEVICES_PATH = "etc/excluded-input-devices.xml";
private static final String PORT_ASSOCIATIONS_PATH = "etc/input-port-associations.xml";
@@ -277,6 +279,12 @@ public class InputManagerService extends IInputManager.Stub
@GuardedBy("mPointerDisplayIdLock")
private int mOverriddenPointerDisplayId = Display.INVALID_DISPLAY;
+
+ // Holds all the registered gesture monitors that are implemented as spy windows. The spy
+ // windows are mapped by their InputChannel tokens.
+ @GuardedBy("mInputMonitors")
+ final Map<IBinder, GestureMonitorSpyWindow> mInputMonitors = new HashMap<>();
+
private static native long nativeInit(InputManagerService service,
Context context, MessageQueue messageQueue);
private static native void nativeStart(long ptr);
@@ -716,33 +724,77 @@ public class InputManagerService extends IInputManager.Stub
inputChannelName, Binder.getCallingPid());
}
+ @NonNull
+ private InputChannel createSpyWindowGestureMonitor(IBinder monitorToken, String name,
+ int displayId, int pid, int uid) {
+ final SurfaceControl sc = mWindowManagerCallbacks.createSurfaceForGestureMonitor(name,
+ displayId);
+ if (sc == null) {
+ throw new IllegalArgumentException(
+ "Could not create gesture monitor surface on display: " + displayId);
+ }
+ final InputChannel channel = createInputChannel(name);
+
+ try {
+ monitorToken.linkToDeath(() -> removeSpyWindowGestureMonitor(channel.getToken()), 0);
+ } catch (RemoteException e) {
+ Slog.i(TAG, "Client died before '" + name + "' could be created.");
+ return null;
+ }
+ synchronized (mInputMonitors) {
+ mInputMonitors.put(channel.getToken(),
+ new GestureMonitorSpyWindow(monitorToken, name, displayId, pid, uid, sc,
+ channel));
+ }
+
+ final InputChannel outInputChannel = new InputChannel();
+ channel.copyTo(outInputChannel);
+ return outInputChannel;
+ }
+
+ private void removeSpyWindowGestureMonitor(IBinder inputChannelToken) {
+ final GestureMonitorSpyWindow monitor;
+ synchronized (mInputMonitors) {
+ monitor = mInputMonitors.remove(inputChannelToken);
+ }
+ removeInputChannel(inputChannelToken);
+ if (monitor == null) return;
+ monitor.remove();
+ }
+
/**
* Creates an input monitor that will receive pointer events for the purposes of system-wide
* gesture interpretation.
*
- * @param inputChannelName The input channel name.
+ * @param requestedName The input channel name.
* @param displayId Target display id.
* @return The input channel.
*/
@Override // Binder call
- public InputMonitor monitorGestureInput(String inputChannelName, int displayId) {
+ public InputMonitor monitorGestureInput(IBinder monitorToken, @NonNull String requestedName,
+ int displayId) {
if (!checkCallingPermission(android.Manifest.permission.MONITOR_INPUT,
- "monitorInputRegion()")) {
+ "monitorGestureInput()")) {
throw new SecurityException("Requires MONITOR_INPUT permission");
}
- Objects.requireNonNull(inputChannelName, "inputChannelName must not be null.");
+ Objects.requireNonNull(requestedName, "name must not be null.");
+ Objects.requireNonNull(monitorToken, "token must not be null.");
if (displayId < Display.DEFAULT_DISPLAY) {
throw new IllegalArgumentException("displayId must >= 0.");
}
+ final String name = "[Gesture Monitor] " + requestedName;
final int pid = Binder.getCallingPid();
+ final int uid = Binder.getCallingUid();
final long ident = Binder.clearCallingIdentity();
try {
- InputChannel inputChannel = nativeCreateInputMonitor(
- mPtr, displayId, true /*isGestureMonitor*/, inputChannelName, pid);
- InputMonitorHost host = new InputMonitorHost(inputChannel.getToken());
- return new InputMonitor(inputChannel, host);
+ final InputChannel inputChannel =
+ USE_SPY_WINDOW_GESTURE_MONITORS
+ ? createSpyWindowGestureMonitor(monitorToken, name, displayId, pid, uid)
+ : nativeCreateInputMonitor(mPtr, displayId, true /*isGestureMonitor*/,
+ requestedName, pid);
+ return new InputMonitor(inputChannel, new InputMonitorHost(inputChannel.getToken()));
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -2563,37 +2615,51 @@ public class InputManagerService extends IInputManager.Stub
String dumpStr = nativeDump(mPtr);
if (dumpStr != null) {
pw.println(dumpStr);
- dumpAssociations(pw);
}
+
+ pw.println("Input Manager Service (Java) State:");
+ dumpAssociations(pw, " " /*prefix*/);
+ dumpSpyWindowGestureMonitors(pw, " " /*prefix*/);
}
- private void dumpAssociations(PrintWriter pw) {
+ private void dumpAssociations(PrintWriter pw, String prefix) {
if (!mStaticAssociations.isEmpty()) {
- pw.println("Static Associations:");
+ pw.println(prefix + "Static Associations:");
mStaticAssociations.forEach((k, v) -> {
- pw.print(" port: " + k);
+ pw.print(prefix + " port: " + k);
pw.println(" display: " + v);
});
}
synchronized (mAssociationsLock) {
if (!mRuntimeAssociations.isEmpty()) {
- pw.println("Runtime Associations:");
+ pw.println(prefix + "Runtime Associations:");
mRuntimeAssociations.forEach((k, v) -> {
- pw.print(" port: " + k);
+ pw.print(prefix + " port: " + k);
pw.println(" display: " + v);
});
}
if (!mUniqueIdAssociations.isEmpty()) {
- pw.println("Unique Id Associations:");
+ pw.println(prefix + "Unique Id Associations:");
mUniqueIdAssociations.forEach((k, v) -> {
- pw.print(" port: " + k);
+ pw.print(prefix + " port: " + k);
pw.println(" uniqueId: " + v);
});
}
}
}
+ private void dumpSpyWindowGestureMonitors(PrintWriter pw, String prefix) {
+ synchronized (mInputMonitors) {
+ if (mInputMonitors.isEmpty()) return;
+ pw.println(prefix + "Gesture Monitors (implemented as spy windows):");
+ int i = 0;
+ for (final GestureMonitorSpyWindow monitor : mInputMonitors.values()) {
+ pw.append(prefix + " " + i++ + ": ").println(monitor.dump());
+ }
+ }
+ }
+
private boolean checkCallingPermission(String permission, String func) {
// Quick check: if the calling permission is me, it's all okay.
if (Binder.getCallingPid() == Process.myPid()) {
@@ -2618,6 +2684,7 @@ public class InputManagerService extends IInputManager.Stub
synchronized (mAssociationsLock) { /* Test if blocked by associations lock. */}
synchronized (mLidSwitchLock) { /* Test if blocked by lid switch lock. */ }
synchronized (mPointerDisplayIdLock) { /* Test if blocked by pointer display id lock */ }
+ synchronized (mInputMonitors) { /* Test if blocked by input monitor lock. */ }
nativeMonitor(mPtr);
}
@@ -2686,6 +2753,11 @@ public class InputManagerService extends IInputManager.Stub
// Native callback.
private void notifyInputChannelBroken(IBinder token) {
+ synchronized (mInputMonitors) {
+ if (mInputMonitors.containsKey(token)) {
+ removeSpyWindowGestureMonitor(token);
+ }
+ }
mWindowManagerCallbacks.notifyInputChannelBroken(token);
}
@@ -2721,6 +2793,17 @@ public class InputManagerService extends IInputManager.Stub
// Native callback
private void notifyWindowUnresponsive(IBinder token, String reason) {
+ int gestureMonitorPid = -1;
+ synchronized (mInputMonitors) {
+ final GestureMonitorSpyWindow gestureMonitor = mInputMonitors.get(token);
+ if (gestureMonitor != null) {
+ gestureMonitorPid = gestureMonitor.mWindowHandle.ownerPid;
+ }
+ }
+ if (gestureMonitorPid != -1) {
+ mWindowManagerCallbacks.notifyGestureMonitorUnresponsive(gestureMonitorPid, reason);
+ return;
+ }
mWindowManagerCallbacks.notifyWindowUnresponsive(token, reason);
}
@@ -2731,6 +2814,17 @@ public class InputManagerService extends IInputManager.Stub
// Native callback
private void notifyWindowResponsive(IBinder token) {
+ int gestureMonitorPid = -1;
+ synchronized (mInputMonitors) {
+ final GestureMonitorSpyWindow gestureMonitor = mInputMonitors.get(token);
+ if (gestureMonitor != null) {
+ gestureMonitorPid = gestureMonitor.mWindowHandle.ownerPid;
+ }
+ }
+ if (gestureMonitorPid != -1) {
+ mWindowManagerCallbacks.notifyGestureMonitorResponsive(gestureMonitorPid);
+ return;
+ }
mWindowManagerCallbacks.notifyWindowResponsive(token);
}
@@ -3184,6 +3278,16 @@ public class InputManagerService extends IInputManager.Stub
* pointers such as the mouse cursor and touch spots for the given display.
*/
SurfaceControl getParentSurfaceForPointers(int displayId);
+
+ /**
+ * Create a {@link SurfaceControl} that can be configured to receive input over the entire
+ * display to implement a gesture monitor. The surface will not have a graphical buffer.
+ * @param name the name of the gesture monitor
+ * @param displayId the display to create the window in
+ * @return the SurfaceControl of the new layer container surface
+ */
+ @Nullable
+ SurfaceControl createSurfaceForGestureMonitor(String name, int displayId);
}
/**
@@ -3258,20 +3362,24 @@ public class InputManagerService extends IInputManager.Stub
* Interface for the system to handle request from InputMonitors.
*/
private final class InputMonitorHost extends IInputMonitorHost.Stub {
- private final IBinder mToken;
+ private final IBinder mInputChannelToken;
- InputMonitorHost(IBinder token) {
- mToken = token;
+ InputMonitorHost(IBinder inputChannelToken) {
+ mInputChannelToken = inputChannelToken;
}
@Override
public void pilferPointers() {
- nativePilferPointers(mPtr, mToken);
+ nativePilferPointers(mPtr, mInputChannelToken);
}
@Override
public void dispose() {
- nativeRemoveInputChannel(mPtr, mToken);
+ if (USE_SPY_WINDOW_GESTURE_MONITORS) {
+ removeSpyWindowGestureMonitor(mInputChannelToken);
+ return;
+ }
+ nativeRemoveInputChannel(mPtr, mInputChannelToken);
}
}
diff --git a/services/core/java/com/android/server/locales/LocaleManagerBackupHelper.java b/services/core/java/com/android/server/locales/LocaleManagerBackupHelper.java
index 134fb967cac5..01aee7bc1942 100644
--- a/services/core/java/com/android/server/locales/LocaleManagerBackupHelper.java
+++ b/services/core/java/com/android/server/locales/LocaleManagerBackupHelper.java
@@ -31,13 +31,11 @@ import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
-import android.os.BestClock;
import android.os.Binder;
import android.os.HandlerThread;
import android.os.LocaleList;
import android.os.Process;
import android.os.RemoteException;
-import android.os.SystemClock;
import android.os.UserHandle;
import android.text.TextUtils;
import android.util.Slog;
@@ -61,7 +59,6 @@ import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.time.Clock;
import java.time.Duration;
-import java.time.ZoneOffset;
import java.util.HashMap;
/**
@@ -97,15 +94,10 @@ class LocaleManagerBackupHelper {
LocaleManagerBackupHelper(LocaleManagerService localeManagerService,
PackageManagerInternal pmInternal) {
- this(localeManagerService.mContext, localeManagerService, pmInternal, getDefaultClock(),
+ this(localeManagerService.mContext, localeManagerService, pmInternal, Clock.systemUTC(),
new SparseArray<>());
}
- private static @NonNull Clock getDefaultClock() {
- return new BestClock(ZoneOffset.UTC, SystemClock.currentNetworkTimeClock(),
- Clock.systemUTC());
- }
-
@VisibleForTesting LocaleManagerBackupHelper(Context context,
LocaleManagerService localeManagerService,
PackageManagerInternal pmInternal, Clock clock, SparseArray<StagedData> stagedData) {
diff --git a/services/core/java/com/android/server/location/gnss/GnssNmeaProvider.java b/services/core/java/com/android/server/location/gnss/GnssNmeaProvider.java
index 5036a6e7edf5..bfef97856838 100644
--- a/services/core/java/com/android/server/location/gnss/GnssNmeaProvider.java
+++ b/services/core/java/com/android/server/location/gnss/GnssNmeaProvider.java
@@ -63,16 +63,25 @@ class GnssNmeaProvider extends GnssListenerMultiplexer<Void, IGnssNmeaListener,
@Override
protected boolean registerWithService(Void ignored,
Collection<GnssListenerRegistration> registrations) {
- if (D) {
- Log.d(TAG, "starting gnss nmea messages");
+ if (mGnssNative.startNmeaMessageCollection()) {
+ if (D) {
+ Log.d(TAG, "starting gnss nmea messages collection");
+ }
+ return true;
+ } else {
+ Log.e(TAG, "error starting gnss nmea messages collection");
+ return false;
}
- return true;
}
@Override
protected void unregisterWithService() {
- if (D) {
- Log.d(TAG, "stopping gnss nmea messages");
+ if (mGnssNative.stopNmeaMessageCollection()) {
+ if (D) {
+ Log.d(TAG, "stopping gnss nmea messages collection");
+ }
+ } else {
+ Log.e(TAG, "error stopping gnss nmea messages collection");
}
}
diff --git a/services/core/java/com/android/server/location/gnss/GnssStatusProvider.java b/services/core/java/com/android/server/location/gnss/GnssStatusProvider.java
index 936283deda8e..0ce36d6a8276 100644
--- a/services/core/java/com/android/server/location/gnss/GnssStatusProvider.java
+++ b/services/core/java/com/android/server/location/gnss/GnssStatusProvider.java
@@ -43,6 +43,7 @@ public class GnssStatusProvider extends
private final AppOpsHelper mAppOpsHelper;
private final LocationUsageLogger mLogger;
+ private final GnssNative mGnssNative;
private boolean mIsNavigating = false;
@@ -50,6 +51,7 @@ public class GnssStatusProvider extends
super(injector);
mAppOpsHelper = injector.getAppOpsHelper();
mLogger = injector.getLocationUsageLogger();
+ mGnssNative = gnssNative;
gnssNative.addBaseCallbacks(this);
gnssNative.addStatusCallbacks(this);
@@ -64,16 +66,25 @@ public class GnssStatusProvider extends
@Override
protected boolean registerWithService(Void ignored,
Collection<GnssListenerRegistration> registrations) {
- if (D) {
- Log.d(TAG, "starting gnss status");
+ if (mGnssNative.startSvStatusCollection()) {
+ if (D) {
+ Log.d(TAG, "starting gnss sv status");
+ }
+ return true;
+ } else {
+ Log.e(TAG, "error starting gnss sv status");
+ return false;
}
- return true;
}
@Override
protected void unregisterWithService() {
- if (D) {
- Log.d(TAG, "stopping gnss status");
+ if (mGnssNative.stopSvStatusCollection()) {
+ if (D) {
+ Log.d(TAG, "stopping gnss sv status");
+ }
+ } else {
+ Log.e(TAG, "error stopping gnss sv status");
}
}
diff --git a/services/core/java/com/android/server/location/gnss/hal/GnssNative.java b/services/core/java/com/android/server/location/gnss/hal/GnssNative.java
index e072bf7dc1f7..af87677ecb66 100644
--- a/services/core/java/com/android/server/location/gnss/hal/GnssNative.java
+++ b/services/core/java/com/android/server/location/gnss/hal/GnssNative.java
@@ -783,6 +783,38 @@ public class GnssNative {
}
/**
+ * Starts sv status collection.
+ */
+ public boolean startSvStatusCollection() {
+ Preconditions.checkState(mRegistered);
+ return mGnssHal.startSvStatusCollection();
+ }
+
+ /**
+ * Stops sv status collection.
+ */
+ public boolean stopSvStatusCollection() {
+ Preconditions.checkState(mRegistered);
+ return mGnssHal.stopSvStatusCollection();
+ }
+
+ /**
+ * Starts NMEA message collection.
+ */
+ public boolean startNmeaMessageCollection() {
+ Preconditions.checkState(mRegistered);
+ return mGnssHal.startNmeaMessageCollection();
+ }
+
+ /**
+ * Stops NMEA message collection.
+ */
+ public boolean stopNmeaMessageCollection() {
+ Preconditions.checkState(mRegistered);
+ return mGnssHal.stopNmeaMessageCollection();
+ }
+
+ /**
* Returns true if measurement corrections are supported.
*/
public boolean isMeasurementCorrectionsSupported() {
@@ -1369,6 +1401,22 @@ public class GnssNative {
return native_inject_measurement_corrections(corrections);
}
+ protected boolean startSvStatusCollection() {
+ return native_start_sv_status_collection();
+ }
+
+ protected boolean stopSvStatusCollection() {
+ return native_stop_sv_status_collection();
+ }
+
+ protected boolean startNmeaMessageCollection() {
+ return native_start_nmea_message_collection();
+ }
+
+ protected boolean stopNmeaMessageCollection() {
+ return native_stop_nmea_message_collection();
+ }
+
protected int getBatchSize() {
return native_get_batch_size();
}
@@ -1478,6 +1526,10 @@ public class GnssNative {
private static native int native_read_nmea(byte[] buffer, int bufferSize);
+ private static native boolean native_start_nmea_message_collection();
+
+ private static native boolean native_stop_nmea_message_collection();
+
// location injection APIs
private static native void native_inject_location(
@@ -1501,6 +1553,11 @@ public class GnssNative {
private static native void native_inject_time(long time, long timeReference, int uncertainty);
+ // sv status APIs
+ private static native boolean native_start_sv_status_collection();
+
+ private static native boolean native_stop_sv_status_collection();
+
// navigation message APIs
private static native boolean native_is_navigation_message_supported();
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 3549c9ec2e74..ee5c6385429a 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -247,6 +247,7 @@ import com.android.server.pm.verify.domain.DomainVerificationService;
import com.android.server.pm.verify.domain.proxy.DomainVerificationProxy;
import com.android.server.pm.verify.domain.proxy.DomainVerificationProxyV1;
import com.android.server.storage.DeviceStorageMonitorInternal;
+import com.android.server.supplementalprocess.SupplementalProcessManagerLocal;
import com.android.server.utils.SnapshotCache;
import com.android.server.utils.TimingsTraceAndSlog;
import com.android.server.utils.Watchable;
@@ -934,6 +935,7 @@ public class PackageManagerService extends IPackageManager.Stub
final @Nullable String mOverlayConfigSignaturePackage;
final @Nullable String mRecentsPackage;
final @Nullable String mAmbientContextDetectionPackage;
+ private final @NonNull String mRequiredSupplementalProcessPackage;
@GuardedBy("mLock")
private final PackageUsage mPackageUsage = new PackageUsage();
@@ -1671,6 +1673,7 @@ public class PackageManagerService extends IPackageManager.Stub
mSharedSystemSharedLibraryPackageName = testParams.sharedSystemSharedLibraryPackageName;
mOverlayConfigSignaturePackage = testParams.overlayConfigSignaturePackage;
mResolveComponentName = testParams.resolveComponentName;
+ mRequiredSupplementalProcessPackage = testParams.requiredSupplementalProcessPackage;
mLiveComputer = createLiveComputer();
mSnapshotComputer = null;
@@ -1695,6 +1698,7 @@ public class PackageManagerService extends IPackageManager.Stub
mResolveIntentHelper = testParams.resolveIntentHelper;
mDexOptHelper = testParams.dexOptHelper;
mSuspendPackageHelper = testParams.suspendPackageHelper;
+
mSharedLibraries.setDeletePackageHelper(mDeletePackageHelper);
registerObservers(false);
@@ -2138,6 +2142,9 @@ public class PackageManagerService extends IPackageManager.Stub
getPackageInfo(mRequiredPermissionControllerPackage, 0,
UserHandle.USER_SYSTEM).getLongVersionCode());
+ // Resolve the supplemental process
+ mRequiredSupplementalProcessPackage = getRequiredSupplementalProcessPackageName();
+
// Initialize InstantAppRegistry's Instant App list for all users.
for (AndroidPackage pkg : mPackages.values()) {
if (pkg.isSystem()) {
@@ -3153,6 +3160,11 @@ public class PackageManagerService extends IPackageManager.Stub
throw new IllegalStateException("PermissionController is not found");
}
+ @Override
+ public String getSupplementalProcessPackageName() {
+ return mRequiredSupplementalProcessPackage;
+ }
+
String getPackageInstallerPackageName() {
return mRequiredInstallerPackage;
}
@@ -5518,6 +5530,24 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
+ private @NonNull String getRequiredSupplementalProcessPackageName() {
+ final Intent intent = new Intent(SupplementalProcessManagerLocal.SERVICE_INTERFACE);
+
+ final List<ResolveInfo> matches = queryIntentServicesInternal(
+ intent,
+ /* resolvedType= */ null,
+ MATCH_SYSTEM_ONLY | MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE,
+ UserHandle.USER_SYSTEM,
+ /* callingUid= */ Process.myUid(),
+ /* includeInstantApps= */ false);
+ if (matches.size() == 1) {
+ return matches.get(0).getComponentInfo().packageName;
+ } else {
+ throw new RuntimeException("There should exactly one supplemental process; found "
+ + matches.size() + ": matches=" + matches);
+ }
+ }
+
@Override
public String getDefaultTextClassifierPackageName() {
return ensureSystemPackageName(
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceTestParams.java b/services/core/java/com/android/server/pm/PackageManagerServiceTestParams.java
index 1caa76d2435a..d12c826b8d40 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceTestParams.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceTestParams.java
@@ -89,6 +89,7 @@ public final class PackageManagerServiceTestParams {
public @Nullable String defaultTextClassifierPackage;
public @Nullable String systemTextClassifierPackage;
public @Nullable String overlayConfigSignaturePackage;
+ public @NonNull String requiredSupplementalProcessPackage;
public ViewCompiler viewCompiler;
public @Nullable String retailDemoPackage;
public @Nullable String recentsPackage;
diff --git a/services/core/java/com/android/server/trust/TrustAgentWrapper.java b/services/core/java/com/android/server/trust/TrustAgentWrapper.java
index 06ce4a41afec..1dea3d7943d8 100644
--- a/services/core/java/com/android/server/trust/TrustAgentWrapper.java
+++ b/services/core/java/com/android/server/trust/TrustAgentWrapper.java
@@ -71,6 +71,7 @@ public class TrustAgentWrapper {
private static final int MSG_ESCROW_TOKEN_STATE = 9;
private static final int MSG_UNLOCK_USER = 10;
private static final int MSG_SHOW_KEYGUARD_ERROR_MESSAGE = 11;
+ private static final int MSG_LOCK_USER = 12;
/**
* Time in uptime millis that we wait for the service connection, both when starting
@@ -100,6 +101,8 @@ public class TrustAgentWrapper {
// Trust state
private boolean mTrusted;
+ private boolean mWaitingForTrustableDowngrade = false;
+ private boolean mTrustable;
private CharSequence mMessage;
private boolean mDisplayTrustGrantedMessage;
private boolean mTrustDisabledByDpm;
@@ -108,6 +111,25 @@ public class TrustAgentWrapper {
private AlarmManager mAlarmManager;
private final Intent mAlarmIntent;
private PendingIntent mAlarmPendingIntent;
+ private final BroadcastReceiver mTrustableDowngradeReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (!TrustManagerService.ENABLE_ACTIVE_UNLOCK_FLAG) {
+ return;
+ }
+ if (!mWaitingForTrustableDowngrade) {
+ return;
+ }
+ // are these the broadcasts we want to listen to
+ if (Intent.ACTION_SCREEN_OFF.equals(intent.getAction())
+ || Intent.ACTION_USER_PRESENT.equals(intent.getAction())) {
+ mTrusted = false;
+ mTrustable = true;
+ mWaitingForTrustableDowngrade = false;
+ mTrustManagerService.updateTrust(mUserId, 0);
+ }
+ }
+ };
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@Override
@@ -126,16 +148,21 @@ public class TrustAgentWrapper {
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_GRANT_TRUST:
- // TODO(b/213631675): Respect FLAG_GRANT_TRUST_TEMPORARY_AND_RENEWABLE
if (!isConnected()) {
Log.w(TAG, "Agent is not connected, cannot grant trust: "
+ mName.flattenToShortString());
return;
}
mTrusted = true;
+ mTrustable = false;
mMessage = (CharSequence) msg.obj;
int flags = msg.arg1;
mDisplayTrustGrantedMessage = (flags & FLAG_GRANT_TRUST_DISPLAY_MESSAGE) != 0;
+ if ((flags & TrustAgentService.FLAG_GRANT_TRUST_TEMPORARY_AND_RENEWABLE) != 0) {
+ mWaitingForTrustableDowngrade = true;
+ } else {
+ mWaitingForTrustableDowngrade = false;
+ }
long durationMs = msg.getData().getLong(DATA_DURATION);
if (durationMs > 0) {
final long duration;
@@ -270,6 +297,13 @@ public class TrustAgentWrapper {
mTrustManagerService.showKeyguardErrorMessage(message);
break;
}
+ case MSG_LOCK_USER: {
+ mTrusted = false;
+ mTrustable = false;
+ mTrustManagerService.updateTrust(mUserId, 0 /* flags */);
+ mTrustManagerService.lockUser(mUserId);
+ break;
+ }
}
}
};
@@ -295,6 +329,11 @@ public class TrustAgentWrapper {
}
@Override
+ public void lockUser() {
+ mHandler.sendEmptyMessage(MSG_LOCK_USER);
+ }
+
+ @Override
public void setManagingTrust(boolean managingTrust) {
if (DEBUG) Slog.d(TAG, "managingTrust()");
mHandler.obtainMessage(MSG_MANAGING_TRUST, managingTrust ? 1 : 0, 0).sendToTarget();
@@ -427,6 +466,9 @@ public class TrustAgentWrapper {
final String pathUri = mAlarmIntent.toUri(Intent.URI_INTENT_SCHEME);
alarmFilter.addDataPath(pathUri, PatternMatcher.PATTERN_LITERAL);
+ IntentFilter trustableFilter = new IntentFilter(Intent.ACTION_USER_PRESENT);
+ trustableFilter.addAction(Intent.ACTION_SCREEN_OFF);
+
// Schedules a restart for when connecting times out. If the connection succeeds,
// the restart is canceled in mCallback's onConnected.
scheduleRestart();
@@ -435,6 +477,7 @@ public class TrustAgentWrapper {
if (mBound) {
mContext.registerReceiver(mBroadcastReceiver, alarmFilter, PERMISSION, null,
Context.RECEIVER_EXPORTED);
+ mContext.registerReceiver(mTrustableDowngradeReceiver, trustableFilter);
} else {
Log.e(TAG, "Can't bind to TrustAgent " + mName.flattenToShortString());
}
@@ -591,6 +634,10 @@ public class TrustAgentWrapper {
return mTrusted && mManagingTrust && !mTrustDisabledByDpm;
}
+ public boolean isTrustable() {
+ return mTrustable && mManagingTrust && !mTrustDisabledByDpm;
+ }
+
public boolean isManagingTrust() {
return mManagingTrust && !mTrustDisabledByDpm;
}
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index 9bed24d05f3d..6aafd4aec0ab 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -54,6 +54,7 @@ import android.os.Message;
import android.os.PersistableBundle;
import android.os.RemoteException;
import android.os.SystemClock;
+import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
@@ -65,6 +66,7 @@ import android.util.ArraySet;
import android.util.AttributeSet;
import android.util.Log;
import android.util.Slog;
+import android.util.SparseArray;
import android.util.SparseBooleanArray;
import android.util.Xml;
import android.view.IWindowManager;
@@ -145,6 +147,21 @@ public class TrustManagerService extends SystemService {
@GuardedBy("mUserIsTrusted")
private final SparseBooleanArray mUserIsTrusted = new SparseBooleanArray();
+ //TODO(b/215724686): remove flag
+ public static final boolean ENABLE_ACTIVE_UNLOCK_FLAG = SystemProperties.getBoolean(
+ "fw.enable_active_unlock_flag", true);
+
+ private enum TrustState {
+ UNTRUSTED, // the phone is not unlocked by any trustagents
+ TRUSTABLE, // the phone is in a semi-locked state that can be unlocked if
+ // FLAG_GRANT_TRUST_TEMPORARY_AND_RENEWABLE is passed and a trustagent is trusted
+ TRUSTED // the phone is unlocked
+ };
+
+ @GuardedBy("mUserTrustState")
+ private final SparseArray<TrustManagerService.TrustState> mUserTrustState =
+ new SparseArray<>();
+
/**
* Stores the locked state for users on the device. There are three different type of users
* which are handled slightly differently:
@@ -228,7 +245,6 @@ public class TrustManagerService extends SystemService {
}
// Extend unlock config and logic
-
private final class SettingsObserver extends ContentObserver {
private final Uri TRUST_AGENTS_EXTEND_UNLOCK =
Settings.Secure.getUriFor(Settings.Secure.TRUST_AGENTS_EXTEND_UNLOCK);
@@ -396,6 +412,14 @@ public class TrustManagerService extends SystemService {
}
private void updateTrust(int userId, int flags, boolean isFromUnlock) {
+ if (ENABLE_ACTIVE_UNLOCK_FLAG) {
+ updateTrustWithRenewableUnlock(userId, flags, isFromUnlock);
+ } else {
+ updateTrustWithExtendUnlock(userId, flags, isFromUnlock);
+ }
+ }
+
+ private void updateTrustWithExtendUnlock(int userId, int flags, boolean isFromUnlock) {
boolean managed = aggregateIsTrustManaged(userId);
dispatchOnTrustManagedChanged(managed, userId);
if (mStrongAuthTracker.isTrustAllowedForUser(userId)
@@ -441,6 +465,65 @@ public class TrustManagerService extends SystemService {
}
}
+ private void updateTrustWithRenewableUnlock(int userId, int flags, boolean isFromUnlock) {
+ boolean managed = aggregateIsTrustManaged(userId);
+ dispatchOnTrustManagedChanged(managed, userId);
+ if (mStrongAuthTracker.isTrustAllowedForUser(userId)
+ && isTrustUsuallyManagedInternal(userId) != managed) {
+ updateTrustUsuallyManaged(userId, managed);
+ }
+
+ boolean trustedByAtLeastOneAgent = aggregateIsTrusted(userId);
+ boolean trustableByAtLeastOneAgent = aggregateIsTrustable(userId);
+ boolean wasTrusted;
+ boolean wasTrustable;
+ TrustState pendingTrustState;
+
+ IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
+ boolean alreadyUnlocked = false;
+ try {
+ alreadyUnlocked = !wm.isKeyguardLocked();
+ } catch (RemoteException e) {
+ }
+
+ synchronized (mUserTrustState) {
+ wasTrusted = (mUserTrustState.get(userId) == TrustState.TRUSTED);
+ wasTrustable = (mUserTrustState.get(userId) == TrustState.TRUSTABLE);
+ boolean renewingTrust = wasTrustable && (
+ (flags & TrustAgentService.FLAG_GRANT_TRUST_TEMPORARY_AND_RENEWABLE) != 0);
+ boolean canMoveToTrusted = alreadyUnlocked || isFromUnlock || renewingTrust;
+ boolean upgradingTrustForCurrentUser = (userId == mCurrentUser);
+
+ if (trustedByAtLeastOneAgent && wasTrusted) {
+ // no change
+ return;
+ } else if (trustedByAtLeastOneAgent && canMoveToTrusted
+ && upgradingTrustForCurrentUser) {
+ pendingTrustState = TrustState.TRUSTED;
+ } else if (trustableByAtLeastOneAgent && (wasTrusted || wasTrustable)
+ && upgradingTrustForCurrentUser) {
+ pendingTrustState = TrustState.TRUSTABLE;
+ } else {
+ pendingTrustState = TrustState.UNTRUSTED;
+ }
+
+ mUserTrustState.put(userId, pendingTrustState);
+ }
+ if (DEBUG) Slog.d(TAG, "pendingTrustState: " + pendingTrustState);
+
+ boolean isNowTrusted = pendingTrustState == TrustState.TRUSTED;
+ dispatchOnTrustChanged(isNowTrusted, userId, flags, getTrustGrantedMessages(userId));
+ if (isNowTrusted != wasTrusted) {
+ refreshDeviceLockedForUser(userId);
+ if (!isNowTrusted) {
+ maybeLockScreen(userId);
+ } else {
+ scheduleTrustTimeout(userId, false /* override */);
+ }
+ }
+ }
+
+
private void updateTrustUsuallyManaged(int userId, boolean managed) {
synchronized (mTrustUsuallyManagedForUser) {
mTrustUsuallyManagedForUser.put(userId, managed);
@@ -472,6 +555,20 @@ public class TrustManagerService extends SystemService {
mLockPatternUtils.unlockUserWithToken(handle, token, userId);
}
+ /**
+ * Locks the phone and requires some auth (not trust) like a biometric or passcode before
+ * unlocking.
+ */
+ public void lockUser(int userId) {
+ mLockPatternUtils.requireStrongAuth(
+ StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_USER_REQUEST, userId);
+ try {
+ WindowManagerGlobal.getWindowManagerService().lockNow(null);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Error locking screen when called from trust agent");
+ }
+ }
+
void showKeyguardErrorMessage(CharSequence message) {
dispatchOnTrustError(message);
}
@@ -950,6 +1047,21 @@ public class TrustManagerService extends SystemService {
return false;
}
+ private boolean aggregateIsTrustable(int userId) {
+ if (!mStrongAuthTracker.isTrustAllowedForUser(userId)) {
+ return false;
+ }
+ for (int i = 0; i < mActiveAgents.size(); i++) {
+ AgentInfo info = mActiveAgents.valueAt(i);
+ if (info.userId == userId) {
+ if (info.agent.isTrustable()) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
private List<String> getTrustGrantedMessages(int userId) {
if (!mStrongAuthTracker.isTrustAllowedForUser(userId)) {
return new ArrayList<>();
diff --git a/services/core/java/com/android/server/wm/InputManagerCallback.java b/services/core/java/com/android/server/wm/InputManagerCallback.java
index f91969b2c558..1f0fdcf0a8d2 100644
--- a/services/core/java/com/android/server/wm/InputManagerCallback.java
+++ b/services/core/java/com/android/server/wm/InputManagerCallback.java
@@ -24,6 +24,7 @@ import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import static com.android.server.wm.WindowManagerService.H.ON_POINTER_DOWN_OUTSIDE_FOCUS;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.graphics.PointF;
import android.os.Debug;
import android.os.IBinder;
@@ -254,6 +255,25 @@ final class InputManagerCallback implements InputManagerService.WindowManagerCal
}
}
+ @Override
+ @Nullable
+ public SurfaceControl createSurfaceForGestureMonitor(String name, int displayId) {
+ synchronized (mService.mGlobalLock) {
+ final DisplayContent dc = mService.mRoot.getDisplayContent(displayId);
+ if (dc == null) {
+ Slog.e(TAG, "Failed to create a gesture monitor on display: " + displayId
+ + " - DisplayContent not found.");
+ return null;
+ }
+ return mService.makeSurfaceBuilder(dc.getSession())
+ .setContainerLayer()
+ .setName(name)
+ .setCallsite("createSurfaceForGestureMonitor")
+ .setParent(dc.getSurfaceControl())
+ .build();
+ }
+ }
+
/** Waits until the built-in input devices have been configured. */
public boolean waitForInputDevicesReady(long timeoutMillis) {
synchronized (mInputDevicesReadyMonitor) {
diff --git a/services/core/java/com/android/server/wm/InsetsPolicy.java b/services/core/java/com/android/server/wm/InsetsPolicy.java
index 10776abee51e..1e121737e2ac 100644
--- a/services/core/java/com/android/server/wm/InsetsPolicy.java
+++ b/services/core/java/com/android/server/wm/InsetsPolicy.java
@@ -32,6 +32,7 @@ import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_STATUS_FORCE_
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.app.ActivityTaskManager;
import android.app.StatusBarManager;
import android.graphics.Insets;
import android.graphics.Rect;
@@ -134,7 +135,7 @@ class InsetsPolicy {
/** Updates the target which can control system bars. */
void updateBarControlTarget(@Nullable WindowState focusedWin) {
- if (mFocusedWin != focusedWin){
+ if (mFocusedWin != focusedWin) {
abortTransient();
}
mFocusedWin = focusedWin;
@@ -156,7 +157,7 @@ class InsetsPolicy {
}
boolean isHidden(@InternalInsetsType int type) {
- final InsetsSourceProvider provider = mStateController.peekSourceProvider(type);
+ final InsetsSourceProvider provider = mStateController.peekSourceProvider(type);
return provider != null && provider.hasWindow() && !provider.getSource().isVisible();
}
@@ -181,6 +182,10 @@ class InsetsPolicy {
mShowingTransientTypes.toArray(), isGestureOnSystemBar);
}
updateBarControlTarget(mFocusedWin);
+ dispatchTransientSystemBarsVisibilityChanged(
+ mFocusedWin,
+ isTransient(ITYPE_STATUS_BAR) || isTransient(ITYPE_NAVIGATION_BAR),
+ isGestureOnSystemBar);
// The leashes can be created while updating bar control target. The surface transaction
// of the new leashes might not be applied yet. The callback posted here ensures we can
@@ -198,6 +203,12 @@ class InsetsPolicy {
if (mShowingTransientTypes.size() == 0) {
return;
}
+
+ dispatchTransientSystemBarsVisibilityChanged(
+ mFocusedWin,
+ /* areVisible= */ false,
+ /* wereRevealedFromSwipeOnSystemBar= */ false);
+
startAnimation(false /* show */, () -> {
synchronized (mDisplayContent.mWmService.mGlobalLock) {
for (int i = mShowingTransientTypes.size() - 1; i >= 0; i--) {
@@ -373,6 +384,11 @@ class InsetsPolicy {
mDisplayContent.getDisplayId(), mShowingTransientTypes.toArray());
}
mShowingTransientTypes.clear();
+
+ dispatchTransientSystemBarsVisibilityChanged(
+ mFocusedWin,
+ /* areVisible= */ false,
+ /* wereRevealedFromSwipeOnSystemBar= */ false);
}
private @Nullable InsetsControlTarget getStatusControlTarget(@Nullable WindowState focusedWin,
@@ -521,6 +537,32 @@ class InsetsPolicy {
listener.mControlCallbacks.controlAnimationUnchecked(typesReady, controls, show);
}
+ private void dispatchTransientSystemBarsVisibilityChanged(
+ @Nullable WindowState focusedWindow,
+ boolean areVisible,
+ boolean wereRevealedFromSwipeOnSystemBar) {
+ if (focusedWindow == null) {
+ return;
+ }
+
+ Task task = focusedWindow.getTask();
+ if (task == null) {
+ return;
+ }
+
+ int taskId = task.mTaskId;
+ boolean isValidTaskId = taskId != ActivityTaskManager.INVALID_TASK_ID;
+ if (!isValidTaskId) {
+ return;
+ }
+
+ mDisplayContent.mWmService.mTaskSystemBarsListenerController
+ .dispatchTransientSystemBarVisibilityChanged(
+ taskId,
+ areVisible,
+ wereRevealedFromSwipeOnSystemBar);
+ }
+
private class BarWindow {
private final int mId;
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 76a7981fa946..ee03d02791ff 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -981,6 +981,29 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
mWmService.checkDrawnWindowsLocked();
}
+ final int N = mWmService.mPendingRemove.size();
+ if (N > 0) {
+ if (mWmService.mPendingRemoveTmp.length < N) {
+ mWmService.mPendingRemoveTmp = new WindowState[N + 10];
+ }
+ mWmService.mPendingRemove.toArray(mWmService.mPendingRemoveTmp);
+ mWmService.mPendingRemove.clear();
+ ArrayList<DisplayContent> displayList = new ArrayList();
+ for (i = 0; i < N; i++) {
+ final WindowState w = mWmService.mPendingRemoveTmp[i];
+ w.removeImmediately();
+ final DisplayContent displayContent = w.getDisplayContent();
+ if (displayContent != null && !displayList.contains(displayContent)) {
+ displayList.add(displayContent);
+ }
+ }
+
+ for (int j = displayList.size() - 1; j >= 0; --j) {
+ final DisplayContent dc = displayList.get(j);
+ dc.assignWindowLayers(true /*setLayoutNeeded*/);
+ }
+ }
+
forAllDisplays(dc -> {
dc.getInputMonitor().updateInputWindowsLw(true /*force*/);
dc.updateSystemGestureExclusion();
diff --git a/services/core/java/com/android/server/wm/TaskSystemBarsListenerController.java b/services/core/java/com/android/server/wm/TaskSystemBarsListenerController.java
new file mode 100644
index 000000000000..acb6061de93f
--- /dev/null
+++ b/services/core/java/com/android/server/wm/TaskSystemBarsListenerController.java
@@ -0,0 +1,63 @@
+/*
+ * 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;
+
+import com.android.internal.os.BackgroundThread;
+import com.android.server.wm.WindowManagerInternal.TaskSystemBarsListener;
+
+import java.util.HashSet;
+import java.util.concurrent.Executor;
+
+/**
+ * Manages dispatch of task system bar changes to interested listeners. All invocations must be
+ * performed while the {@link WindowManagerService#getWindowManagerLock() Window Manager Lock} is
+ * held.
+ */
+final class TaskSystemBarsListenerController {
+
+ private final HashSet<TaskSystemBarsListener> mListeners = new HashSet<>();
+ private final Executor mBackgroundExecutor;
+
+ TaskSystemBarsListenerController() {
+ this.mBackgroundExecutor = BackgroundThread.getExecutor();
+ }
+
+ void registerListener(TaskSystemBarsListener listener) {
+ mListeners.add(listener);
+ }
+
+ void unregisterListener(TaskSystemBarsListener listener) {
+ mListeners.remove(listener);
+ }
+
+ void dispatchTransientSystemBarVisibilityChanged(
+ int taskId,
+ boolean visible,
+ boolean wereRevealedFromSwipeOnSystemBar) {
+ HashSet<TaskSystemBarsListener> localListeners;
+ localListeners = new HashSet<>(mListeners);
+
+ mBackgroundExecutor.execute(() -> {
+ for (TaskSystemBarsListener listener : localListeners) {
+ listener.onTransientSystemBarsVisibilityChanged(
+ taskId,
+ visible,
+ wereRevealedFromSwipeOnSystemBar);
+ }
+ });
+ }
+}
diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java
index 20fa7a9da256..4900f9292f2a 100644
--- a/services/core/java/com/android/server/wm/WindowManagerInternal.java
+++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java
@@ -256,6 +256,25 @@ public abstract class WindowManagerInternal {
}
/**
+ * An interface to be notified when the system bars for a task change.
+ */
+ public interface TaskSystemBarsListener {
+
+ /**
+ * Called when the visibility of the system bars of a task change.
+ *
+ * @param taskId the identifier of the task.
+ * @param visible if the transient system bars are visible.
+ * @param wereRevealedFromSwipeOnSystemBar if the transient bars were revealed due to a
+ * swipe gesture on a system bar.
+ */
+ void onTransientSystemBarsVisibilityChanged(
+ int taskId,
+ boolean visible,
+ boolean wereRevealedFromSwipeOnSystemBar);
+ }
+
+ /**
* An interface to be notified when keyguard exit animation should start.
*/
public interface KeyguardExitAnimationStartListener {
@@ -519,6 +538,20 @@ public abstract class WindowManagerInternal {
public abstract void registerAppTransitionListener(AppTransitionListener listener);
/**
+ * Registers a listener to be notified to when the system bars of a task changes.
+ *
+ * @param listener The listener to register.
+ */
+ public abstract void registerTaskSystemBarsListener(TaskSystemBarsListener listener);
+
+ /**
+ * Registers a listener to be notified to when the system bars of a task changes.
+ *
+ * @param listener The listener to unregister.
+ */
+ public abstract void unregisterTaskSystemBarsListener(TaskSystemBarsListener listener);
+
+ /**
* Registers a listener to be notified to start the keyguard exit animation.
*
* @param listener The listener to register.
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index b37cb4f286f9..1167cb531c76 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -222,6 +222,7 @@ import android.util.DisplayMetrics;
import android.util.EventLog;
import android.util.MergedConfiguration;
import android.util.Slog;
+import android.util.SparseArray;
import android.util.SparseBooleanArray;
import android.util.TimeUtils;
import android.util.TypedValue;
@@ -586,6 +587,20 @@ public class WindowManagerService extends IWindowManager.Stub
final ArrayList<WindowState> mResizingWindows = new ArrayList<>();
/**
+ * Windows whose animations have ended and now must be removed.
+ */
+ final ArrayList<WindowState> mPendingRemove = new ArrayList<>();
+
+ /**
+ * Used when processing mPendingRemove to avoid working on the original array.
+ */
+ WindowState[] mPendingRemoveTmp = new WindowState[20];
+
+ // TODO: use WindowProcessController once go/wm-unified is done.
+ /** Mapping of process pids to configurations */
+ final SparseArray<Configuration> mProcessConfigurations = new SparseArray<>();
+
+ /**
* Mapping of displayId to {@link DisplayImePolicy}.
* Note that this can be accessed without holding the lock.
*/
@@ -683,6 +698,7 @@ public class WindowManagerService extends IWindowManager.Stub
() -> mDisplayRotationController = null;
final DisplayWindowListenerController mDisplayNotificationController;
+ final TaskSystemBarsListenerController mTaskSystemBarsListenerController;
boolean mDisplayFrozen = false;
long mDisplayFreezeTime = 0;
@@ -1265,6 +1281,7 @@ public class WindowManagerService extends IWindowManager.Stub
mScreenFrozenLock.setReferenceCounted(false);
mDisplayNotificationController = new DisplayWindowListenerController(this);
+ mTaskSystemBarsListenerController = new TaskSystemBarsListenerController();
mActivityManager = ActivityManager.getService();
mActivityTaskManager = ActivityTaskManager.getService();
@@ -2036,6 +2053,7 @@ public class WindowManagerService extends IWindowManager.Stub
dc.mWinRemovedSinceNullFocus.add(win);
}
mEmbeddedWindowController.onWindowRemoved(win);
+ mPendingRemove.remove(win);
mResizingWindows.remove(win);
updateNonSystemOverlayWindowsVisibilityIfNeeded(win, false /* surfaceShown */);
mWindowsChanged = true;
@@ -6364,6 +6382,23 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
}
+ if (mPendingRemove.size() > 0) {
+ pw.println();
+ pw.println(" Remove pending for:");
+ for (int i=mPendingRemove.size()-1; i>=0; i--) {
+ WindowState w = mPendingRemove.get(i);
+ if (windows == null || windows.contains(w)) {
+ pw.print(" Remove #"); pw.print(i); pw.print(' ');
+ pw.print(w);
+ if (dumpAll) {
+ pw.println(":");
+ w.dump(pw, " ", true);
+ } else {
+ pw.println();
+ }
+ }
+ }
+ }
if (mForceRemoves != null && mForceRemoves.size() > 0) {
pw.println();
pw.println(" Windows force removing:");
@@ -7591,6 +7626,20 @@ public class WindowManagerService extends IWindowManager.Stub
}
@Override
+ public void registerTaskSystemBarsListener(TaskSystemBarsListener listener) {
+ synchronized (mGlobalLock) {
+ mTaskSystemBarsListenerController.registerListener(listener);
+ }
+ }
+
+ @Override
+ public void unregisterTaskSystemBarsListener(TaskSystemBarsListener listener) {
+ synchronized (mGlobalLock) {
+ mTaskSystemBarsListenerController.unregisterListener(listener);
+ }
+ }
+
+ @Override
public void registerKeyguardExitAnimationStartListener(
KeyguardExitAnimationStartListener listener) {
synchronized (mGlobalLock) {
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 0a02b4442518..79c64b19882d 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -4887,20 +4887,15 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
if (hasSurface) {
mWmService.mDestroySurface.add(this);
}
+ if (mRemoveOnExit) {
+ mWmService.mPendingRemove.add(this);
+ mRemoveOnExit = false;
+ }
}
mAnimatingExit = false;
getDisplayContent().mWallpaperController.hideWallpapers(this);
}
- @Override
- boolean handleCompleteDeferredRemoval() {
- if (mRemoveOnExit) {
- mRemoveOnExit = false;
- removeImmediately();
- }
- return super.handleCompleteDeferredRemoval();
- }
-
boolean clearAnimatingFlags() {
boolean didSomething = false;
// We don't want to clear it out for windows that get replaced, because the
diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
index 161d7ce350fc..166a0f5272cf 100644
--- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
+++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
@@ -244,6 +244,9 @@ bool hasLatLong(const GnssLocation_V2_0& location) {
return hasLatLong(location.v1_0);
}
+bool isSvStatusRegistered = false;
+bool isNmeaRegistered = false;
+
} // namespace
static inline jboolean boolToJbool(bool value) {
@@ -505,6 +508,13 @@ uint32_t GnssCallback::getConstellationType(
template <class T_list, class T_sv_info>
Return<void> GnssCallback::gnssSvStatusCbImpl(const T_list& svStatus) {
+ // In HIDL or AIDL v1, if no listener is registered, do not report svInfoList to the framework.
+ if (gnssHalAidl == nullptr || gnssHalAidl->getInterfaceVersion() == 1) {
+ if (!isSvStatusRegistered) {
+ return Void();
+ }
+ }
+
JNIEnv* env = getJniEnv();
uint32_t listSize = getGnssSvInfoListSize(svStatus);
@@ -566,8 +576,12 @@ Return<void> GnssCallback::gnssSvStatusCbImpl(const T_list& svStatus) {
return Void();
}
-Return<void> GnssCallback::gnssNmeaCb(
- int64_t timestamp, const ::android::hardware::hidl_string& nmea) {
+Return<void> GnssCallback::gnssNmeaCb(int64_t timestamp,
+ const ::android::hardware::hidl_string& nmea) {
+ // In HIDL, if no listener is registered, do not report nmea to the framework.
+ if (!isNmeaRegistered) {
+ return Void();
+ }
JNIEnv* env = getJniEnv();
/*
* The Java code will call back to read these values.
@@ -680,6 +694,12 @@ Status GnssCallbackAidl::gnssLocationCb(const GnssLocationAidl& location) {
}
Status GnssCallbackAidl::gnssNmeaCb(const int64_t timestamp, const std::string& nmea) {
+ // In AIDL v1, if no listener is registered, do not report nmea to the framework.
+ if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() == 1) {
+ if (!isNmeaRegistered) {
+ return Status::ok();
+ }
+ }
JNIEnv* env = getJniEnv();
/*
* The Java code will call back to read these values.
@@ -1562,6 +1582,58 @@ static jboolean android_location_gnss_hal_GnssNative_stop(JNIEnv* /* env */, jcl
return checkHidlReturn(result, "IGnss stop() failed.");
}
+static jboolean android_location_gnss_hal_GnssNative_start_sv_status_collection(JNIEnv* /* env */,
+ jclass) {
+ isSvStatusRegistered = true;
+ if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() >= 2) {
+ auto status = gnssHalAidl->startSvStatus();
+ return checkAidlStatus(status, "IGnssAidl startSvStatus() failed.");
+ }
+ if (gnssHal == nullptr) {
+ return JNI_FALSE;
+ }
+ return JNI_TRUE;
+}
+
+static jboolean android_location_gnss_hal_GnssNative_stop_sv_status_collection(JNIEnv* /* env */,
+ jclass) {
+ isSvStatusRegistered = false;
+ if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() >= 2) {
+ auto status = gnssHalAidl->stopSvStatus();
+ return checkAidlStatus(status, "IGnssAidl stopSvStatus() failed.");
+ }
+ if (gnssHal == nullptr) {
+ return JNI_FALSE;
+ }
+ return JNI_TRUE;
+}
+
+static jboolean android_location_gnss_hal_GnssNative_start_nmea_message_collection(
+ JNIEnv* /* env */, jclass) {
+ isNmeaRegistered = true;
+ if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() >= 2) {
+ auto status = gnssHalAidl->startNmea();
+ return checkAidlStatus(status, "IGnssAidl startNmea() failed.");
+ }
+ if (gnssHal == nullptr) {
+ return JNI_FALSE;
+ }
+ return JNI_TRUE;
+}
+
+static jboolean android_location_gnss_hal_GnssNative_stop_nmea_message_collection(JNIEnv* /* env */,
+ jclass) {
+ isNmeaRegistered = false;
+ if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() >= 2) {
+ auto status = gnssHalAidl->stopNmea();
+ return checkAidlStatus(status, "IGnssAidl stopNmea() failed.");
+ }
+ if (gnssHal == nullptr) {
+ return JNI_FALSE;
+ }
+ return JNI_TRUE;
+}
+
static void android_location_gnss_hal_GnssNative_delete_aiding_data(JNIEnv* /* env */, jclass,
jint flags) {
if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() >= 2) {
@@ -1989,7 +2061,7 @@ static SingleSatCorrection_V1_0 getSingleSatCorrection_1_0_withoutConstellation(
jfloat eplMeters = env->CallFloatMethod(singleSatCorrectionObj, method_correctionSatEpl);
jfloat eplUncMeters = env->CallFloatMethod(singleSatCorrectionObj, method_correctionSatEplUnc);
uint16_t corrFlags = static_cast<uint16_t>(correctionFlags);
- jobject reflectingPlaneObj;
+ jobject reflectingPlaneObj = nullptr;
bool has_ref_plane = (corrFlags & GnssSingleSatCorrectionFlags::HAS_REFLECTING_PLANE) != 0;
if (has_ref_plane) {
reflectingPlaneObj =
@@ -2013,6 +2085,7 @@ static SingleSatCorrection_V1_0 getSingleSatCorrection_1_0_withoutConstellation(
.azimuthDegrees = azimuthDegreeRefPlane,
};
}
+ env->DeleteLocalRef(reflectingPlaneObj);
SingleSatCorrection_V1_0 singleSatCorrection = {
.singleSatCorrectionFlags = corrFlags,
@@ -2044,6 +2117,7 @@ static void getSingleSatCorrectionList_1_1(JNIEnv* env, jobject singleSatCorrect
};
list[i] = singleSatCorrection_1_1;
+ env->DeleteLocalRef(singleSatCorrectionObj);
}
}
@@ -2061,6 +2135,7 @@ static void getSingleSatCorrectionList_1_0(JNIEnv* env, jobject singleSatCorrect
singleSatCorrection.constellation = static_cast<GnssConstellationType_V1_0>(constType),
list[i] = singleSatCorrection;
+ env->DeleteLocalRef(singleSatCorrectionObj);
}
}
@@ -2131,6 +2206,7 @@ static jboolean android_location_gnss_hal_GnssNative_inject_measurement_correcti
hidl_vec<SingleSatCorrection_V1_0> list(len);
getSingleSatCorrectionList_1_0(env, singleSatCorrectionList, list);
+ env->DeleteLocalRef(singleSatCorrectionList);
measurementCorrections_1_0.satCorrections = list;
auto result = gnssCorrectionsIface_V1_0->setCorrections(measurementCorrections_1_0);
@@ -2365,6 +2441,16 @@ static const JNINativeMethod sLocationProviderMethods[] = {
{"native_is_gnss_visibility_control_supported", "()Z",
reinterpret_cast<void*>(
android_location_gnss_hal_GnssNative_is_gnss_visibility_control_supported)},
+ {"native_start_sv_status_collection", "()Z",
+ reinterpret_cast<void*>(android_location_gnss_hal_GnssNative_start_sv_status_collection)},
+ {"native_stop_sv_status_collection", "()Z",
+ reinterpret_cast<void*>(android_location_gnss_hal_GnssNative_stop_sv_status_collection)},
+ {"native_start_nmea_message_collection", "()Z",
+ reinterpret_cast<void*>(
+ android_location_gnss_hal_GnssNative_start_nmea_message_collection)},
+ {"native_stop_nmea_message_collection", "()Z",
+ reinterpret_cast<void*>(
+ android_location_gnss_hal_GnssNative_stop_nmea_message_collection)},
};
static const JNINativeMethod sBatchingMethods[] = {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyData.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyData.java
index 26c442dc1f47..e18e0020407f 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyData.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyData.java
@@ -23,6 +23,7 @@ import android.app.admin.DevicePolicyManager;
import android.content.ComponentName;
import android.os.FileUtils;
import android.os.PersistableBundle;
+import android.os.UserHandle;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.DebugUtils;
@@ -83,7 +84,7 @@ class DevicePolicyData {
private static final String ATTR_NEW_USER_DISCLAIMER = "new-user-disclaimer";
// Values of ATTR_NEW_USER_DISCLAIMER
- static final String NEW_USER_DISCLAIMER_SHOWN = "shown";
+ static final String NEW_USER_DISCLAIMER_ACKNOWLEDGED = "acked";
static final String NEW_USER_DISCLAIMER_NOT_NEEDED = "not_needed";
static final String NEW_USER_DISCLAIMER_NEEDED = "needed";
@@ -613,6 +614,28 @@ class DevicePolicyData {
}
}
+ boolean isNewUserDisclaimerAcknowledged() {
+ if (mNewUserDisclaimer == null) {
+ if (mUserId == UserHandle.USER_SYSTEM) {
+ return true;
+ }
+ Slogf.w(TAG, "isNewUserDisclaimerAcknowledged(%d): mNewUserDisclaimer is null",
+ mUserId);
+ return false;
+ }
+ switch (mNewUserDisclaimer) {
+ case NEW_USER_DISCLAIMER_ACKNOWLEDGED:
+ case NEW_USER_DISCLAIMER_NOT_NEEDED:
+ return true;
+ case NEW_USER_DISCLAIMER_NEEDED:
+ return false;
+ default:
+ Slogf.w(TAG, "isNewUserDisclaimerAcknowledged(%d): invalid value %d", mUserId,
+ mNewUserDisclaimer);
+ return false;
+ }
+ }
+
void dump(IndentingPrintWriter pw) {
pw.println();
pw.println("Enabled Device Admins (User " + mUserId + ", provisioningState: "
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index e34178ab9cd2..6f41d42b3d54 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -10978,10 +10978,11 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
@Override
public void acknowledgeNewUserDisclaimer() {
CallerIdentity callerIdentity = getCallerIdentity();
- canManageUsers(callerIdentity);
+ Preconditions.checkCallAuthorization(canManageUsers(callerIdentity)
+ || hasCallingOrSelfPermission(permission.INTERACT_ACROSS_USERS));
setShowNewUserDisclaimer(callerIdentity.getUserId(),
- DevicePolicyData.NEW_USER_DISCLAIMER_SHOWN);
+ DevicePolicyData.NEW_USER_DISCLAIMER_ACKNOWLEDGED);
}
private void setShowNewUserDisclaimer(@UserIdInt int userId, String value) {
@@ -11014,6 +11015,18 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
@Override
+ public boolean isNewUserDisclaimerAcknowledged() {
+ CallerIdentity callerIdentity = getCallerIdentity();
+ Preconditions.checkCallAuthorization(canManageUsers(callerIdentity)
+ || hasCallingOrSelfPermission(permission.INTERACT_ACROSS_USERS));
+ int userId = callerIdentity.getUserId();
+ synchronized (getLockObject()) {
+ DevicePolicyData policyData = getUserData(userId);
+ return policyData.isNewUserDisclaimerAcknowledged();
+ }
+ }
+
+ @Override
public boolean removeUser(ComponentName who, UserHandle userHandle) {
Objects.requireNonNull(who, "ComponentName is null");
Objects.requireNonNull(userHandle, "UserHandle is null");
@@ -11210,8 +11223,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
@Override
public int logoutUserInternal() {
CallerIdentity caller = getCallerIdentity();
- Preconditions.checkCallAuthorization(
- canManageUsers(caller) || hasCallingOrSelfPermission(permission.CREATE_USERS));
+ Preconditions.checkCallAuthorization(canManageUsers(caller)
+ || hasCallingOrSelfPermission(permission.INTERACT_ACROSS_USERS));
int result = logoutUserUnchecked(getCurrentForegroundUserId());
Slogf.d(LOG_TAG, "logout called by uid %d. Result: %d", caller.getUid(), result);
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index c9aeabd17191..d0c861fa912e 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -366,6 +366,8 @@ public final class SystemServer implements Dumpable {
"com.android.server.adb.AdbService$Lifecycle";
private static final String SPEECH_RECOGNITION_MANAGER_SERVICE_CLASS =
"com.android.server.speech.SpeechRecognitionManagerService";
+ private static final String WALLPAPER_EFFECTS_GENERATION_MANAGER_SERVICE_CLASS =
+ "com.android.server.wallpapereffectsgeneration.WallpaperEffectsGenerationManagerService";
private static final String APP_PREDICTION_MANAGER_SERVICE_CLASS =
"com.android.server.appprediction.AppPredictionManagerService";
private static final String CONTENT_SUGGESTIONS_SERVICE_CLASS =
@@ -1895,7 +1897,6 @@ public final class SystemServer implements Dumpable {
}
t.traceEnd();
-
t.traceBegin("StartIpSecService");
try {
ipSecService = IpSecService.create(context);
@@ -2126,6 +2127,14 @@ public final class SystemServer implements Dumpable {
Slog.i(TAG, "Wallpaper service disabled by config");
}
+ // WallpaperEffectsGeneration manager service
+ // TODO (b/135218095): Use deviceHasConfigString(context,
+ // R.string.config_defaultWallpaperEffectsGenerationService)
+ t.traceBegin("StartWallpaperEffectsGenerationService");
+ mSystemServiceManager.startService(
+ WALLPAPER_EFFECTS_GENERATION_MANAGER_SERVICE_CLASS);
+ t.traceEnd();
+
t.traceBegin("StartAudioService");
if (!isArc) {
mSystemServiceManager.startService(AudioService.Lifecycle.class);
diff --git a/services/tests/mockingservicestests/Android.bp b/services/tests/mockingservicestests/Android.bp
index 9e221bec4749..75669d50c75d 100644
--- a/services/tests/mockingservicestests/Android.bp
+++ b/services/tests/mockingservicestests/Android.bp
@@ -52,6 +52,7 @@ android_test {
"service-blobstore",
"service-jobscheduler",
"service-permission.impl",
+ "service-supplementalprocess.impl",
"services.core",
"services.devicepolicy",
"services.net",
diff --git a/services/tests/mockingservicestests/res/xml/gama_manager_service_metadata_config_disabled.xml b/services/tests/mockingservicestests/res/xml/gama_manager_service_metadata_config_disabled.xml
new file mode 100644
index 000000000000..eb154518c911
--- /dev/null
+++ b/services/tests/mockingservicestests/res/xml/gama_manager_service_metadata_config_disabled.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<game-mode-config
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:supportsPerformanceGameMode="false"
+ android:supportsBatteryGameMode="false"
+ android:allowGameAngleDriver="false"
+ android:allowGameDownscaling="false"
+ android:allowGameFpsOverride="false"
+/> \ No newline at end of file
diff --git a/services/tests/mockingservicestests/res/xml/gama_manager_service_metadata_config_enabled.xml b/services/tests/mockingservicestests/res/xml/gama_manager_service_metadata_config_enabled.xml
new file mode 100644
index 000000000000..65b7467b80f5
--- /dev/null
+++ b/services/tests/mockingservicestests/res/xml/gama_manager_service_metadata_config_enabled.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<game-mode-config
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:supportsPerformanceGameMode="false"
+ android:supportsBatteryGameMode="false"
+ android:allowGameAngleDriver="true"
+ android:allowGameDownscaling="true"
+ android:allowGameFpsOverride="true"
+/> \ No newline at end of file
diff --git a/services/tests/mockingservicestests/src/android/service/games/GameSessionTest.java b/services/tests/mockingservicestests/src/android/service/games/GameSessionTest.java
index fec9b1249d17..e89c812ba1fb 100644
--- a/services/tests/mockingservicestests/src/android/service/games/GameSessionTest.java
+++ b/services/tests/mockingservicestests/src/android/service/games/GameSessionTest.java
@@ -359,6 +359,34 @@ public final class GameSessionTest {
LifecycleTrackingGameSession.LifecycleMethodCall.ON_DESTROY).inOrder();
}
+ @Test
+ public void dispatchTransientVisibilityChanged_valueUnchanged_doesNotInvokeCallback() {
+ mGameSession.dispatchTransientSystemBarVisibilityFromRevealGestureChanged(false);
+
+ assertThat(mGameSession.mCapturedTransientSystemBarVisibilityFromRevealGestures).hasSize(0);
+ }
+
+ @Test
+ public void dispatchTransientVisibilityChanged_valueChanged_invokesCallback() {
+ mGameSession.dispatchTransientSystemBarVisibilityFromRevealGestureChanged(true);
+
+ assertThat(mGameSession.mCapturedTransientSystemBarVisibilityFromRevealGestures)
+ .containsExactly(true).inOrder();
+ }
+
+ @Test
+ public void dispatchTransientVisibilityChanged_manyTimes_invokesCallbackWhenValueChanges() {
+ mGameSession.dispatchTransientSystemBarVisibilityFromRevealGestureChanged(false);
+ mGameSession.dispatchTransientSystemBarVisibilityFromRevealGestureChanged(true);
+ mGameSession.dispatchTransientSystemBarVisibilityFromRevealGestureChanged(false);
+ mGameSession.dispatchTransientSystemBarVisibilityFromRevealGestureChanged(false);
+ mGameSession.dispatchTransientSystemBarVisibilityFromRevealGestureChanged(true);
+ mGameSession.dispatchTransientSystemBarVisibilityFromRevealGestureChanged(true);
+
+ assertThat(mGameSession.mCapturedTransientSystemBarVisibilityFromRevealGestures)
+ .containsExactly(true, false, true).inOrder();
+ }
+
private static class LifecycleTrackingGameSession extends GameSession {
private enum LifecycleMethodCall {
ON_CREATE,
@@ -368,6 +396,8 @@ public final class GameSessionTest {
}
final List<LifecycleMethodCall> mLifecycleMethodCalls = new ArrayList<>();
+ final List<Boolean> mCapturedTransientSystemBarVisibilityFromRevealGestures =
+ new ArrayList<>();
@Override
public void onCreate() {
@@ -387,5 +417,11 @@ public final class GameSessionTest {
mLifecycleMethodCalls.add(LifecycleMethodCall.ON_GAME_TASK_UNFOCUSED);
}
}
+
+ @Override
+ public void onTransientSystemBarVisibilityFromRevealGestureChanged(
+ boolean visibleDueToGesture) {
+ mCapturedTransientSystemBarVisibilityFromRevealGestures.add(visibleDueToGesture);
+ }
}
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java b/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java
index 44b81d4d4100..d2358a08624d 100644
--- a/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java
+++ b/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java
@@ -26,6 +26,8 @@ import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -41,6 +43,9 @@ import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
+import android.content.res.AssetManager;
+import android.content.res.Resources;
+import android.content.res.XmlResourceParser;
import android.hardware.power.Mode;
import android.os.Bundle;
import android.os.PowerManagerInternal;
@@ -159,11 +164,17 @@ public class GameManagerServiceTests {
mPackageName = mMockContext.getPackageName();
final ApplicationInfo applicationInfo = new ApplicationInfo();
applicationInfo.category = ApplicationInfo.CATEGORY_GAME;
+ applicationInfo.packageName = mPackageName;
final PackageInfo pi = new PackageInfo();
pi.packageName = mPackageName;
pi.applicationInfo = applicationInfo;
final List<PackageInfo> packages = new ArrayList<>();
packages.add(pi);
+
+ final Resources resources =
+ InstrumentationRegistry.getInstrumentation().getContext().getResources();
+ when(mMockPackageManager.getResourcesForApplication(anyString()))
+ .thenReturn(resources);
when(mMockPackageManager.getInstalledPackagesAsUser(anyInt(), anyInt()))
.thenReturn(packages);
when(mMockPackageManager.getApplicationInfoAsUser(anyString(), anyInt(), anyInt()))
@@ -322,6 +333,46 @@ public class GameManagerServiceTests {
.thenReturn(applicationInfo);
}
+ private void mockInterventionsEnabledFromXml() throws Exception {
+ final ApplicationInfo applicationInfo = mMockPackageManager.getApplicationInfoAsUser(
+ mPackageName, PackageManager.GET_META_DATA, USER_ID_1);
+ Bundle metaDataBundle = new Bundle();
+ final int resId = 123;
+ metaDataBundle.putInt(
+ GameManagerService.GamePackageConfiguration.METADATA_GAME_MODE_CONFIG, resId);
+ applicationInfo.metaData = metaDataBundle;
+ when(mMockPackageManager.getApplicationInfoAsUser(anyString(), anyInt(), anyInt()))
+ .thenReturn(applicationInfo);
+ seedGameManagerServiceMetaDataFromFile(mPackageName, resId,
+ "res/xml/gama_manager_service_metadata_config_enabled.xml");
+ }
+
+ private void mockInterventionsDisabledFromXml() throws Exception {
+ final ApplicationInfo applicationInfo = mMockPackageManager.getApplicationInfoAsUser(
+ mPackageName, PackageManager.GET_META_DATA, USER_ID_1);
+ Bundle metaDataBundle = new Bundle();
+ final int resId = 123;
+ metaDataBundle.putInt(
+ GameManagerService.GamePackageConfiguration.METADATA_GAME_MODE_CONFIG, resId);
+ applicationInfo.metaData = metaDataBundle;
+ when(mMockPackageManager.getApplicationInfoAsUser(anyString(), anyInt(), anyInt()))
+ .thenReturn(applicationInfo);
+ seedGameManagerServiceMetaDataFromFile(mPackageName, resId,
+ "res/xml/gama_manager_service_metadata_config_disabled.xml");
+ }
+
+
+ private void seedGameManagerServiceMetaDataFromFile(String packageName, int resId,
+ String fileName)
+ throws Exception {
+ AssetManager assetManager =
+ InstrumentationRegistry.getInstrumentation().getContext().getAssets();
+ XmlResourceParser xmlResourceParser =
+ assetManager.openXmlResourceParser(fileName);
+ when(mMockPackageManager.getXml(eq(packageName), eq(resId), any()))
+ .thenReturn(xmlResourceParser);
+ }
+
/**
* By default game mode is not supported.
*/
@@ -511,8 +562,8 @@ public class GameManagerServiceTests {
gameManagerService.getConfig(mPackageName);
assertEquals(config.getGameModeConfiguration(gameMode).getUseAngle(), angleEnabled);
- // Validate GameManagerService.getAngleEnabled() returns the correct value.
- assertEquals(gameManagerService.getAngleEnabled(mPackageName, USER_ID_1), angleEnabled);
+ // Validate GameManagerService.isAngleEnabled() returns the correct value.
+ assertEquals(gameManagerService.isAngleEnabled(mPackageName, USER_ID_1), angleEnabled);
}
private void checkFps(GameManagerService gameManagerService, int gameMode, int fps) {
@@ -523,7 +574,7 @@ public class GameManagerServiceTests {
}
GameManagerService.GamePackageConfiguration config =
gameManagerService.getConfig(mPackageName);
- assertEquals(config.getGameModeConfiguration(gameMode).getFps(), fps);
+ assertEquals(fps, config.getGameModeConfiguration(gameMode).getFps());
}
/**
@@ -905,6 +956,36 @@ public class GameManagerServiceTests {
}
@Test
+ public void testGameModeConfigAllowFpsTrue() throws Exception {
+ mockDeviceConfigAll();
+ mockModifyGameModeGranted();
+ mockInterventionsEnabledFromXml();
+ GameManagerService gameManagerService = new GameManagerService(mMockContext,
+ mTestLooper.getLooper());
+ startUser(gameManagerService, USER_ID_1);
+ GameManagerService.GamePackageConfiguration config =
+ gameManagerService.getConfig(mPackageName);
+ assertEquals(90,
+ config.getGameModeConfiguration(GameManager.GAME_MODE_PERFORMANCE).getFps());
+ assertEquals(30, config.getGameModeConfiguration(GameManager.GAME_MODE_BATTERY).getFps());
+ }
+
+ @Test
+ public void testGameModeConfigAllowFpsFalse() throws Exception {
+ mockDeviceConfigAll();
+ mockModifyGameModeGranted();
+ mockInterventionsDisabledFromXml();
+ GameManagerService gameManagerService = new GameManagerService(mMockContext,
+ mTestLooper.getLooper());
+ startUser(gameManagerService, USER_ID_1);
+ GameManagerService.GamePackageConfiguration config =
+ gameManagerService.getConfig(mPackageName);
+ assertEquals(0,
+ config.getGameModeConfiguration(GameManager.GAME_MODE_PERFORMANCE).getFps());
+ assertEquals(0, config.getGameModeConfiguration(GameManager.GAME_MODE_BATTERY).getFps());
+ }
+
+ @Test
public void testInterventionFps() throws Exception {
mockDeviceConfigAll();
mockModifyGameModeGranted();
diff --git a/services/tests/mockingservicestests/src/com/android/server/app/GameServiceProviderInstanceImplTest.java b/services/tests/mockingservicestests/src/com/android/server/app/GameServiceProviderInstanceImplTest.java
index 317a51b3fe2d..08de62bc6537 100644
--- a/services/tests/mockingservicestests/src/com/android/server/app/GameServiceProviderInstanceImplTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/app/GameServiceProviderInstanceImplTest.java
@@ -31,7 +31,6 @@ import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.verifyZeroInteractions;
import android.Manifest;
@@ -72,6 +71,7 @@ import com.android.internal.util.ConcurrentUtils;
import com.android.internal.util.FunctionalUtils.ThrowingConsumer;
import com.android.internal.util.Preconditions;
import com.android.server.wm.WindowManagerInternal;
+import com.android.server.wm.WindowManagerInternal.TaskSystemBarsListener;
import com.android.server.wm.WindowManagerService;
import org.junit.After;
@@ -112,6 +112,7 @@ public final class GameServiceProviderInstanceImplTest {
private static final ComponentName GAME_B_MAIN_ACTIVITY =
new ComponentName(GAME_B_PACKAGE, "com.package.game.b.MainActivity");
+
private static final Bitmap TEST_BITMAP = Bitmap.createBitmap(32, 32, Bitmap.Config.ARGB_8888);
private MockitoSession mMockingSession;
@@ -131,6 +132,7 @@ public final class GameServiceProviderInstanceImplTest {
private FakeGameSessionService mFakeGameSessionService;
private FakeServiceConnector<IGameSessionService> mFakeGameSessionServiceConnector;
private ArrayList<ITaskStackListener> mTaskStackListeners;
+ private ArrayList<TaskSystemBarsListener> mTaskSystemBarsListeners;
private ArrayList<RunningTaskInfo> mRunningTaskInfos;
@Mock
@@ -159,15 +161,25 @@ public final class GameServiceProviderInstanceImplTest {
mTaskStackListeners.add(invocation.getArgument(0));
return null;
}).when(mMockActivityTaskManager).registerTaskStackListener(any());
+ doAnswer(invocation -> {
+ mTaskStackListeners.remove(invocation.getArgument(0));
+ return null;
+ }).when(mMockActivityTaskManager).unregisterTaskStackListener(any());
+
+ mTaskSystemBarsListeners = new ArrayList<>();
+ doAnswer(invocation -> {
+ mTaskSystemBarsListeners.add(invocation.getArgument(0));
+ return null;
+ }).when(mMockWindowManagerInternal).registerTaskSystemBarsListener(any());
+ doAnswer(invocation -> {
+ mTaskSystemBarsListeners.remove(invocation.getArgument(0));
+ return null;
+ }).when(mMockWindowManagerInternal).unregisterTaskSystemBarsListener(any());
mRunningTaskInfos = new ArrayList<>();
when(mMockActivityTaskManager.getTasks(anyInt(), anyBoolean(), anyBoolean())).thenReturn(
mRunningTaskInfos);
- doAnswer(invocation -> {
- mTaskStackListeners.remove(invocation.getArgument(0));
- return null;
- }).when(mMockActivityTaskManager).unregisterTaskStackListener(any());
mGameServiceProviderInstance = new GameServiceProviderInstanceImpl(
new UserHandle(USER_ID),
@@ -394,7 +406,60 @@ public final class GameServiceProviderInstanceImplTest {
.complete(new CreateGameSessionResult(gameSession10, mockSurfacePackage10));
verify(mMockWindowManagerInternal).addTaskOverlay(eq(10), eq(mockSurfacePackage10));
- verifyNoMoreInteractions(mMockWindowManagerInternal);
+ }
+
+ @Test
+ public void taskSystemBarsListenerChanged_noAssociatedGameSession_doesNothing() {
+ mGameServiceProviderInstance.start();
+
+ dispatchTaskSystemBarsEvent(taskSystemBarsListener -> {
+ taskSystemBarsListener.onTransientSystemBarsVisibilityChanged(
+ 10,
+ /* areVisible= */ false,
+ /* wereRevealedFromSwipeOnSystemBar= */ false);
+ });
+ }
+
+ @Test
+ public void systemBarsTransientShownDueToGesture_hasGameSession_propagatesToGameSession() {
+ mGameServiceProviderInstance.start();
+ startTask(10, GAME_A_MAIN_ACTIVITY);
+ mFakeGameService.requestCreateGameSession(10);
+
+ FakeGameSession gameSession10 = new FakeGameSession();
+ SurfacePackage mockSurfacePackage10 = Mockito.mock(SurfacePackage.class);
+ mFakeGameSessionService.removePendingFutureForTaskId(10)
+ .complete(new CreateGameSessionResult(gameSession10, mockSurfacePackage10));
+
+ dispatchTaskSystemBarsEvent(taskSystemBarsListener -> {
+ taskSystemBarsListener.onTransientSystemBarsVisibilityChanged(
+ 10,
+ /* areVisible= */ true,
+ /* wereRevealedFromSwipeOnSystemBar= */ true);
+ });
+
+ assertThat(gameSession10.mAreTransientSystemBarsVisibleFromRevealGesture).isTrue();
+ }
+
+ @Test
+ public void systemBarsTransientShownButNotGesture_hasGameSession_notPropagatedToGameSession() {
+ mGameServiceProviderInstance.start();
+ startTask(10, GAME_A_MAIN_ACTIVITY);
+ mFakeGameService.requestCreateGameSession(10);
+
+ FakeGameSession gameSession10 = new FakeGameSession();
+ SurfacePackage mockSurfacePackage10 = Mockito.mock(SurfacePackage.class);
+ mFakeGameSessionService.removePendingFutureForTaskId(10)
+ .complete(new CreateGameSessionResult(gameSession10, mockSurfacePackage10));
+
+ dispatchTaskSystemBarsEvent(taskSystemBarsListener -> {
+ taskSystemBarsListener.onTransientSystemBarsVisibilityChanged(
+ 10,
+ /* areVisible= */ true,
+ /* wereRevealedFromSwipeOnSystemBar= */ false);
+ });
+
+ assertThat(gameSession10.mAreTransientSystemBarsVisibleFromRevealGesture).isFalse();
}
@Test
@@ -492,7 +557,6 @@ public final class GameServiceProviderInstanceImplTest {
verify(mMockWindowManagerInternal).addTaskOverlay(eq(10), eq(mockSurfacePackage10));
verify(mMockWindowManagerInternal).removeTaskOverlay(eq(10), eq(mockSurfacePackage10));
- verifyNoMoreInteractions(mMockWindowManagerInternal);
}
@Test
@@ -830,6 +894,13 @@ public final class GameServiceProviderInstanceImplTest {
mMockContext.setPermission(permission, PackageManager.PERMISSION_DENIED);
}
+ private void dispatchTaskSystemBarsEvent(
+ ThrowingConsumer<TaskSystemBarsListener> taskSystemBarsListenerConsumer) {
+ for (TaskSystemBarsListener listener : mTaskSystemBarsListeners) {
+ taskSystemBarsListenerConsumer.accept(listener);
+ }
+ }
+
static final class FakeGameService extends IGameService.Stub {
private IGameServiceController mGameServiceController;
@@ -944,6 +1015,7 @@ public final class GameServiceProviderInstanceImplTest {
private static class FakeGameSession extends IGameSession.Stub {
boolean mIsDestroyed = false;
boolean mIsFocused = false;
+ boolean mAreTransientSystemBarsVisibleFromRevealGesture = false;
@Override
public void onDestroyed() {
@@ -954,6 +1026,11 @@ public final class GameServiceProviderInstanceImplTest {
public void onTaskFocusChanged(boolean focused) {
mIsFocused = focused;
}
+
+ @Override
+ public void onTransientSystemBarVisibilityFromRevealGestureChanged(boolean areVisible) {
+ mAreTransientSystemBarsVisibleFromRevealGesture = areVisible;
+ }
}
private final class MockContext extends ContextWrapper {
@@ -1005,5 +1082,4 @@ public final class GameServiceProviderInstanceImplTest {
return mLastStartedIntent;
}
}
-
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt b/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
index 6ae003163e4b..4ec1641b7157 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
@@ -69,6 +69,7 @@ import com.android.server.pm.permission.PermissionManagerServiceInternal
import com.android.server.pm.pkg.parsing.ParsingPackage
import com.android.server.pm.pkg.parsing.ParsingPackageUtils
import com.android.server.pm.verify.domain.DomainVerificationManagerInternal
+import com.android.server.supplementalprocess.SupplementalProcessManagerLocal
import com.android.server.testutils.TestHandler
import com.android.server.testutils.mock
import com.android.server.testutils.nullable
@@ -335,6 +336,7 @@ class MockSystem(withSession: (StaticMockitoSessionBuilder) -> Unit = {}) {
stageServicesExtensionScan()
stageSystemSharedLibraryScan()
stagePermissionsControllerScan()
+ stageSupplementalProcessScan()
stageInstantAppResolverScan()
}
@@ -569,6 +571,22 @@ class MockSystem(withSession: (StaticMockitoSessionBuilder) -> Unit = {}) {
}
@Throws(Exception::class)
+ private fun stageSupplementalProcessScan() {
+ stageScanNewPackage("com.android.supplemental.process",
+ 1L, systemPartitions[0].privAppFolder,
+ withPackage = { pkg: PackageImpl ->
+ val applicationInfo: ApplicationInfo = createBasicApplicationInfo(pkg)
+ mockQueryServices(SupplementalProcessManagerLocal.SERVICE_INTERFACE,
+ createBasicServiceInfo(
+ pkg, applicationInfo, "SupplementalProcessService"))
+ pkg
+ },
+ withSetting = { setting: PackageSettingBuilder ->
+ setting.setPkgFlags(ApplicationInfo.FLAG_SYSTEM)
+ })
+ }
+
+ @Throws(Exception::class)
private fun stageSystemSharedLibraryScan() {
stageScanNewPackage("android.ext.shared",
1L, systemPartitions[0].appFolder,
diff --git a/services/tests/servicestests/src/com/android/server/attention/AttentionManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/attention/AttentionManagerServiceTest.java
index 9ee1205b4325..3890d4d006e2 100644
--- a/services/tests/servicestests/src/com/android/server/attention/AttentionManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/attention/AttentionManagerServiceTest.java
@@ -24,14 +24,20 @@ import static com.android.server.attention.AttentionManagerService.KEY_STALE_AFT
import static com.google.common.truth.Truth.assertThat;
+import static junit.framework.Assert.fail;
+
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.verifyZeroInteractions;
import android.attention.AttentionManagerInternal.AttentionCallbackInternal;
+import android.attention.AttentionManagerInternal.ProximityCallbackInternal;
import android.content.ComponentName;
import android.content.Context;
import android.os.IBinder;
@@ -42,6 +48,7 @@ import android.os.RemoteException;
import android.provider.DeviceConfig;
import android.service.attention.IAttentionCallback;
import android.service.attention.IAttentionService;
+import android.service.attention.IProximityCallback;
import androidx.test.filters.SmallTest;
@@ -49,6 +56,7 @@ import com.android.server.attention.AttentionManagerService.AttentionCheck;
import com.android.server.attention.AttentionManagerService.AttentionCheckCache;
import com.android.server.attention.AttentionManagerService.AttentionCheckCacheBuffer;
import com.android.server.attention.AttentionManagerService.AttentionHandler;
+import com.android.server.attention.AttentionManagerService.ProximityUpdate;
import org.junit.Before;
import org.junit.Test;
@@ -59,10 +67,13 @@ import org.mockito.MockitoAnnotations;
/**
* Tests for {@link com.android.server.attention.AttentionManagerService}
*/
+@SuppressWarnings("GuardedBy")
@SmallTest
public class AttentionManagerServiceTest {
+ private static final double PROXIMITY_SUCCESS_STATE = 1.0;
private AttentionManagerService mSpyAttentionManager;
private final int mTimeout = 1000;
+ private final Object mLock = new Object();
@Mock
private AttentionCallbackInternal mMockAttentionCallbackInternal;
@Mock
@@ -73,6 +84,8 @@ public class AttentionManagerServiceTest {
private IThermalService mMockIThermalService;
@Mock
Context mContext;
+ @Mock
+ private ProximityCallbackInternal mMockProximityCallbackInternal;
@Before
public void setUp() throws RemoteException {
@@ -84,7 +97,6 @@ public class AttentionManagerServiceTest {
doReturn(true).when(mMockIPowerManager).isInteractive();
mPowerManager = new PowerManager(mContext, mMockIPowerManager, mMockIThermalService, null);
- Object mLock = new Object();
// setup a spy on attention manager
AttentionManagerService attentionManager = new AttentionManagerService(
mContext,
@@ -100,6 +112,119 @@ public class AttentionManagerServiceTest {
mSpyAttentionManager);
mSpyAttentionManager.mCurrentAttentionCheck = attentionCheck;
mSpyAttentionManager.mService = new MockIAttentionService();
+ doNothing().when(mSpyAttentionManager).freeIfInactiveLocked();
+ }
+
+ @Test
+ public void testRegisterProximityUpdates_returnFalseWhenServiceDisabled() {
+ mSpyAttentionManager.mIsServiceEnabled = false;
+
+ assertThat(mSpyAttentionManager.onStartProximityUpdates(mMockProximityCallbackInternal))
+ .isFalse();
+ }
+
+ @Test
+ public void testRegisterProximityUpdates_returnFalseWhenServiceUnavailable() {
+ mSpyAttentionManager.mIsServiceEnabled = true;
+ doReturn(false).when(mSpyAttentionManager).isServiceAvailable();
+
+ assertThat(mSpyAttentionManager.onStartProximityUpdates(mMockProximityCallbackInternal))
+ .isFalse();
+ }
+
+ @Test
+ public void testRegisterProximityUpdates_returnFalseWhenPowerManagerNotInteract()
+ throws RemoteException {
+ mSpyAttentionManager.mIsServiceEnabled = true;
+ doReturn(true).when(mSpyAttentionManager).isServiceAvailable();
+ doReturn(false).when(mMockIPowerManager).isInteractive();
+
+ assertThat(mSpyAttentionManager.onStartProximityUpdates(mMockProximityCallbackInternal))
+ .isFalse();
+ }
+
+ @Test
+ public void testRegisterProximityUpdates_callOnSuccess() throws RemoteException {
+ mSpyAttentionManager.mIsServiceEnabled = true;
+ doReturn(true).when(mSpyAttentionManager).isServiceAvailable();
+ doReturn(true).when(mMockIPowerManager).isInteractive();
+
+ assertThat(mSpyAttentionManager.onStartProximityUpdates(mMockProximityCallbackInternal))
+ .isTrue();
+ verify(mMockProximityCallbackInternal, times(1))
+ .onProximityUpdate(PROXIMITY_SUCCESS_STATE);
+ }
+
+ @Test
+ public void testRegisterProximityUpdates_callOnSuccessTwiceInARow() throws RemoteException {
+ mSpyAttentionManager.mIsServiceEnabled = true;
+ doReturn(true).when(mSpyAttentionManager).isServiceAvailable();
+ doReturn(true).when(mMockIPowerManager).isInteractive();
+
+ assertThat(mSpyAttentionManager.onStartProximityUpdates(mMockProximityCallbackInternal))
+ .isTrue();
+
+ ProximityUpdate prevProximityUpdate = mSpyAttentionManager.mCurrentProximityUpdate;
+ assertThat(mSpyAttentionManager.onStartProximityUpdates(mMockProximityCallbackInternal))
+ .isTrue();
+ assertThat(mSpyAttentionManager.mCurrentProximityUpdate).isEqualTo(prevProximityUpdate);
+ verify(mMockProximityCallbackInternal, times(1))
+ .onProximityUpdate(PROXIMITY_SUCCESS_STATE);
+ }
+
+ @Test
+ public void testUnregisterProximityUpdates_noCrashWhenNoCallbackIsRegistered() {
+ mSpyAttentionManager.onStopProximityUpdates(mMockProximityCallbackInternal);
+ verifyZeroInteractions(mMockProximityCallbackInternal);
+ }
+
+ @Test
+ public void testUnregisterProximityUpdates_noCrashWhenCallbackMismatched()
+ throws RemoteException {
+ mSpyAttentionManager.mIsServiceEnabled = true;
+ doReturn(true).when(mSpyAttentionManager).isServiceAvailable();
+ doReturn(true).when(mMockIPowerManager).isInteractive();
+ mSpyAttentionManager.onStartProximityUpdates(mMockProximityCallbackInternal);
+ verify(mMockProximityCallbackInternal, times(1))
+ .onProximityUpdate(PROXIMITY_SUCCESS_STATE);
+
+ ProximityCallbackInternal mismatchedCallback = new ProximityCallbackInternal() {
+ @Override
+ public void onProximityUpdate(double distance) {
+ fail("Callback shouldn't have responded.");
+ }
+ };
+ mSpyAttentionManager.onStopProximityUpdates(mismatchedCallback);
+
+ verifyNoMoreInteractions(mMockProximityCallbackInternal);
+ }
+
+ @Test
+ public void testUnregisterProximityUpdates_cancelRegistrationWhenMatched()
+ throws RemoteException {
+ mSpyAttentionManager.mIsServiceEnabled = true;
+ doReturn(true).when(mSpyAttentionManager).isServiceAvailable();
+ doReturn(true).when(mMockIPowerManager).isInteractive();
+ mSpyAttentionManager.onStartProximityUpdates(mMockProximityCallbackInternal);
+ mSpyAttentionManager.onStopProximityUpdates(mMockProximityCallbackInternal);
+
+ assertThat(mSpyAttentionManager.mCurrentProximityUpdate).isNull();
+ }
+
+ @Test
+ public void testUnregisterProximityUpdates_noCrashWhenTwiceInARow() throws RemoteException {
+ // Attention Service registers proximity updates.
+ mSpyAttentionManager.mIsServiceEnabled = true;
+ doReturn(true).when(mSpyAttentionManager).isServiceAvailable();
+ doReturn(true).when(mMockIPowerManager).isInteractive();
+ mSpyAttentionManager.onStartProximityUpdates(mMockProximityCallbackInternal);
+ verify(mMockProximityCallbackInternal, times(1))
+ .onProximityUpdate(PROXIMITY_SUCCESS_STATE);
+
+ // Attention Service unregisters the proximity update twice in a row.
+ mSpyAttentionManager.onStopProximityUpdates(mMockProximityCallbackInternal);
+ mSpyAttentionManager.onStopProximityUpdates(mMockProximityCallbackInternal);
+ verifyNoMoreInteractions(mMockProximityCallbackInternal);
}
@Test
@@ -127,7 +252,6 @@ public class AttentionManagerServiceTest {
mSpyAttentionManager.mIsServiceEnabled = true;
doReturn(true).when(mSpyAttentionManager).isServiceAvailable();
doReturn(true).when(mMockIPowerManager).isInteractive();
- doNothing().when(mSpyAttentionManager).freeIfInactiveLocked();
mSpyAttentionManager.mCurrentAttentionCheck = null;
AttentionCallbackInternal callback = Mockito.mock(AttentionCallbackInternal.class);
@@ -213,6 +337,13 @@ public class AttentionManagerServiceTest {
public void cancelAttentionCheck(IAttentionCallback callback) {
}
+ public void onStartProximityUpdates(IProximityCallback callback) throws RemoteException {
+ callback.onProximityUpdate(PROXIMITY_SUCCESS_STATE);
+ }
+
+ public void onStopProximityUpdates() throws RemoteException {
+ }
+
public IBinder asBinder() {
return null;
}
diff --git a/services/tests/servicestests/src/com/android/server/display/AutomaticBrightnessControllerTest.java b/services/tests/servicestests/src/com/android/server/display/AutomaticBrightnessControllerTest.java
index 4caa85cee7db..f5a56891b5f5 100644
--- a/services/tests/servicestests/src/com/android/server/display/AutomaticBrightnessControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/AutomaticBrightnessControllerTest.java
@@ -81,6 +81,7 @@ public class AutomaticBrightnessControllerTest {
@Mock HysteresisLevels mScreenBrightnessThresholds;
@Mock Handler mNoOpHandler;
@Mock HighBrightnessModeController mHbmController;
+ @Mock BrightnessThrottler mBrightnessThrottler;
@Before
public void setUp() {
@@ -128,12 +129,15 @@ public class AutomaticBrightnessControllerTest {
INITIAL_LIGHT_SENSOR_RATE, BRIGHTENING_LIGHT_DEBOUNCE_CONFIG,
DARKENING_LIGHT_DEBOUNCE_CONFIG, RESET_AMBIENT_LUX_AFTER_WARMUP_CONFIG,
mAmbientBrightnessThresholds, mScreenBrightnessThresholds,
- mContext, mHbmController, mIdleBrightnessMappingStrategy,
+ mContext, mHbmController, mBrightnessThrottler, mIdleBrightnessMappingStrategy,
AMBIENT_LIGHT_HORIZON_SHORT, AMBIENT_LIGHT_HORIZON_LONG
);
when(mHbmController.getCurrentBrightnessMax()).thenReturn(BRIGHTNESS_MAX_FLOAT);
when(mHbmController.getCurrentBrightnessMin()).thenReturn(BRIGHTNESS_MIN_FLOAT);
+ // Disable brightness throttling by default. Individual tests can enable it as needed.
+ when(mBrightnessThrottler.getBrightnessCap()).thenReturn(BRIGHTNESS_MAX_FLOAT);
+ when(mBrightnessThrottler.isThrottled()).thenReturn(false);
// Configure the brightness controller and grab an instance of the sensor listener,
// through which we can deliver fake (for test) sensor values.
@@ -420,4 +424,47 @@ public class AutomaticBrightnessControllerTest {
assertEquals(600f, hysteresisLevels.getBrighteningThreshold(500f), EPSILON);
assertEquals(250f, hysteresisLevels.getDarkeningThreshold(500f), EPSILON);
}
+
+ @Test
+ public void testBrightnessGetsThrottled() throws Exception {
+ Sensor lightSensor = TestUtils.createSensor(Sensor.TYPE_LIGHT, "Light Sensor");
+ mController = setupController(lightSensor);
+
+ ArgumentCaptor<SensorEventListener> listenerCaptor =
+ ArgumentCaptor.forClass(SensorEventListener.class);
+ verify(mSensorManager).registerListener(listenerCaptor.capture(), eq(lightSensor),
+ eq(INITIAL_LIGHT_SENSOR_RATE * 1000), any(Handler.class));
+ SensorEventListener listener = listenerCaptor.getValue();
+
+ // Set up system to return max brightness at 100 lux
+ final float normalizedBrightness = BRIGHTNESS_MAX_FLOAT;
+ final float lux = 100.0f;
+ when(mAmbientBrightnessThresholds.getBrighteningThreshold(lux))
+ .thenReturn(lux);
+ when(mAmbientBrightnessThresholds.getDarkeningThreshold(lux))
+ .thenReturn(lux);
+ when(mBrightnessMappingStrategy.getBrightness(eq(lux), eq(null), anyInt()))
+ .thenReturn(normalizedBrightness);
+
+ // Sensor reads 100 lux. We should get max brightness.
+ listener.onSensorChanged(TestUtils.createSensorEvent(lightSensor, (int) lux));
+ assertEquals(BRIGHTNESS_MAX_FLOAT, mController.getAutomaticScreenBrightness(), 0.0f);
+
+ // Apply throttling and notify ABC (simulates DisplayPowerController#updatePowerState())
+ final float throttledBrightness = 0.123f;
+ when(mBrightnessThrottler.getBrightnessCap()).thenReturn(throttledBrightness);
+ when(mBrightnessThrottler.isThrottled()).thenReturn(true);
+ mController.configure(AUTO_BRIGHTNESS_ENABLED, null /* configuration */,
+ BRIGHTNESS_MAX_FLOAT /* brightness */, false /* userChangedBrightness */,
+ 0 /* adjustment */, false /* userChanged */, DisplayPowerRequest.POLICY_BRIGHT);
+ assertEquals(throttledBrightness, mController.getAutomaticScreenBrightness(), 0.0f);
+
+ // Remove throttling and notify ABC again
+ when(mBrightnessThrottler.getBrightnessCap()).thenReturn(BRIGHTNESS_MAX_FLOAT);
+ when(mBrightnessThrottler.isThrottled()).thenReturn(false);
+ mController.configure(AUTO_BRIGHTNESS_ENABLED, null /* configuration */,
+ BRIGHTNESS_MAX_FLOAT /* brightness */, false /* userChangedBrightness */,
+ 0 /* adjustment */, false /* userChanged */, DisplayPowerRequest.POLICY_BRIGHT);
+ assertEquals(BRIGHTNESS_MAX_FLOAT, mController.getAutomaticScreenBrightness(), 0.0f);
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/FakeHdmiCecConfig.java b/services/tests/servicestests/src/com/android/server/hdmi/FakeHdmiCecConfig.java
index d441143272d9..0028969d85a0 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/FakeHdmiCecConfig.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/FakeHdmiCecConfig.java
@@ -165,6 +165,17 @@ final class FakeHdmiCecConfig extends HdmiCecConfig {
R.bool.config_cecTvSendStandbyOnSleepDisabled_default);
doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecSetMenuLanguage_userConfigurable);
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecSetMenuLanguageEnabled_allowed);
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecSetMenuLanguageEnabled_default);
+ doReturn(true).when(resources).getBoolean(
+ R.bool.config_cecSetMenuLanguageDisabled_allowed);
+ doReturn(false).when(resources).getBoolean(
+ R.bool.config_cecSetMenuLanguageDisabled_default);
+
+ doReturn(true).when(resources).getBoolean(
R.bool.config_cecRcProfileTv_userConfigurable);
doReturn(true).when(resources).getBoolean(
R.bool.config_cecRcProfileTvNone_allowed);
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecConfigTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecConfigTest.java
index 85d30a6dbc36..ae7b494fffbb 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecConfigTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecConfigTest.java
@@ -83,6 +83,7 @@ public final class HdmiCecConfigTest {
HdmiControlManager.CEC_SETTING_NAME_VOLUME_CONTROL_MODE,
HdmiControlManager.CEC_SETTING_NAME_TV_WAKE_ON_ONE_TOUCH_PLAY,
HdmiControlManager.CEC_SETTING_NAME_TV_SEND_STANDBY_ON_SLEEP,
+ HdmiControlManager.CEC_SETTING_NAME_SET_MENU_LANGUAGE,
HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_TV,
HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_ROOT_MENU,
HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_SETUP_MENU,
@@ -121,6 +122,7 @@ public final class HdmiCecConfigTest {
HdmiControlManager.CEC_SETTING_NAME_VOLUME_CONTROL_MODE,
HdmiControlManager.CEC_SETTING_NAME_TV_WAKE_ON_ONE_TOUCH_PLAY,
HdmiControlManager.CEC_SETTING_NAME_TV_SEND_STANDBY_ON_SLEEP,
+ HdmiControlManager.CEC_SETTING_NAME_SET_MENU_LANGUAGE,
HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_TV,
HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_ROOT_MENU,
HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_SETUP_MENU,
@@ -159,6 +161,7 @@ public final class HdmiCecConfigTest {
HdmiControlManager.CEC_SETTING_NAME_VOLUME_CONTROL_MODE,
HdmiControlManager.CEC_SETTING_NAME_TV_WAKE_ON_ONE_TOUCH_PLAY,
HdmiControlManager.CEC_SETTING_NAME_TV_SEND_STANDBY_ON_SLEEP,
+ HdmiControlManager.CEC_SETTING_NAME_SET_MENU_LANGUAGE,
HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_TV,
HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_ROOT_MENU,
HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_SETUP_MENU,
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
index 7751ef564138..c48a974ddbb2 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
@@ -42,6 +42,7 @@ import android.hardware.hdmi.HdmiControlManager;
import android.hardware.hdmi.HdmiPortInfo;
import android.hardware.hdmi.IHdmiCecVolumeControlFeatureListener;
import android.hardware.hdmi.IHdmiControlStatusChangeListener;
+import android.hardware.hdmi.IHdmiVendorCommandListener;
import android.os.Binder;
import android.os.Looper;
import android.os.RemoteException;
@@ -747,6 +748,114 @@ public class HdmiControlServiceTest {
}
@Test
+ public void addVendorCommandListener_receiveCallback_VendorCmdNoIdTest() {
+ int destAddress = mHdmiControlServiceSpy.playback().getDeviceInfo().getLogicalAddress();
+ int sourceAddress = Constants.ADDR_TV;
+ byte[] params = {0x00, 0x01, 0x02, 0x03};
+ int vendorId = 0x123456;
+
+ VendorCommandListener vendorCmdListener =
+ new VendorCommandListener(sourceAddress, destAddress, params, vendorId);
+ mHdmiControlServiceSpy.addVendorCommandListener(vendorCmdListener, vendorId);
+ mTestLooper.dispatchAll();
+
+ HdmiCecMessage vendorCommandNoId =
+ HdmiCecMessageBuilder.buildVendorCommand(sourceAddress, destAddress, params);
+ mNativeWrapper.onCecMessage(vendorCommandNoId);
+ mTestLooper.dispatchAll();
+ assertThat(vendorCmdListener.mVendorCommandCallbackReceived).isTrue();
+ assertThat(vendorCmdListener.mParamsCorrect).isTrue();
+ assertThat(vendorCmdListener.mHasVendorId).isFalse();
+ }
+
+ @Test
+ public void addVendorCommandListener_receiveCallback_VendorCmdWithIdTest() {
+ int destAddress = mHdmiControlServiceSpy.playback().getDeviceInfo().getLogicalAddress();
+ int sourceAddress = Constants.ADDR_TV;
+ byte[] params = {0x00, 0x01, 0x02, 0x03};
+ int vendorId = 0x123456;
+
+ VendorCommandListener vendorCmdListener =
+ new VendorCommandListener(sourceAddress, destAddress, params, vendorId);
+ mHdmiControlServiceSpy.addVendorCommandListener(vendorCmdListener, vendorId);
+ mTestLooper.dispatchAll();
+
+ HdmiCecMessage vendorCommandWithId =
+ HdmiCecMessageBuilder.buildVendorCommandWithId(
+ sourceAddress, destAddress, vendorId, params);
+ mNativeWrapper.onCecMessage(vendorCommandWithId);
+ mTestLooper.dispatchAll();
+ assertThat(vendorCmdListener.mVendorCommandCallbackReceived).isTrue();
+ assertThat(vendorCmdListener.mParamsCorrect).isTrue();
+ assertThat(vendorCmdListener.mHasVendorId).isTrue();
+ }
+
+ @Test
+ public void addVendorCommandListener_noCallback_VendorCmdDiffIdTest() {
+ int destAddress = mHdmiControlServiceSpy.playback().getDeviceInfo().getLogicalAddress();
+ int sourceAddress = Constants.ADDR_TV;
+ byte[] params = {0x00, 0x01, 0x02, 0x03};
+ int vendorId = 0x123456;
+ int diffVendorId = 0x345678;
+
+ VendorCommandListener vendorCmdListener =
+ new VendorCommandListener(sourceAddress, destAddress, params, vendorId);
+ mHdmiControlServiceSpy.addVendorCommandListener(vendorCmdListener, vendorId);
+ mTestLooper.dispatchAll();
+
+ HdmiCecMessage vendorCommandWithDiffId =
+ HdmiCecMessageBuilder.buildVendorCommandWithId(
+ sourceAddress, destAddress, diffVendorId, params);
+ mNativeWrapper.onCecMessage(vendorCommandWithDiffId);
+ mTestLooper.dispatchAll();
+ assertThat(vendorCmdListener.mVendorCommandCallbackReceived).isFalse();
+ }
+
+ private static class VendorCommandListener extends IHdmiVendorCommandListener.Stub {
+ boolean mVendorCommandCallbackReceived = false;
+ boolean mParamsCorrect = false;
+ boolean mHasVendorId = false;
+
+ int mSourceAddress;
+ int mDestAddress;
+ byte[] mParams;
+ int mVendorId;
+
+ VendorCommandListener(int sourceAddress, int destAddress, byte[] params, int vendorId) {
+ this.mSourceAddress = sourceAddress;
+ this.mDestAddress = destAddress;
+ this.mParams = params.clone();
+ this.mVendorId = vendorId;
+ }
+
+ @Override
+ public void onReceived(
+ int sourceAddress, int destAddress, byte[] params, boolean hasVendorId) {
+ mVendorCommandCallbackReceived = true;
+ if (mSourceAddress == sourceAddress && mDestAddress == destAddress) {
+ byte[] expectedParams;
+ if (hasVendorId) {
+ // If the command has vendor ID, we have to add it to mParams.
+ expectedParams = new byte[params.length];
+ expectedParams[0] = (byte) ((mVendorId >> 16) & 0xFF);
+ expectedParams[1] = (byte) ((mVendorId >> 8) & 0xFF);
+ expectedParams[2] = (byte) (mVendorId & 0xFF);
+ System.arraycopy(mParams, 0, expectedParams, 3, mParams.length);
+ } else {
+ expectedParams = params.clone();
+ }
+ if (Arrays.equals(expectedParams, params)) {
+ mParamsCorrect = true;
+ }
+ }
+ mHasVendorId = hasVendorId;
+ }
+
+ @Override
+ public void onControlStateChanged(boolean enabled, int reason) {}
+ }
+
+ @Test
public void dispatchMessageToLocalDevice_broadcastMessage_returnsHandled() {
HdmiCecMessage message = HdmiCecMessageBuilder.buildStandby(
Constants.ADDR_TV,
diff --git a/services/wallpapereffectsgeneration/Android.bp b/services/wallpapereffectsgeneration/Android.bp
new file mode 100644
index 000000000000..4dbb0fd82db1
--- /dev/null
+++ b/services/wallpapereffectsgeneration/Android.bp
@@ -0,0 +1,22 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
+filegroup {
+ name: "services.wallpapereffectsgeneration-sources",
+ srcs: ["java/**/*.java"],
+ path: "java",
+ visibility: ["//frameworks/base/services"],
+}
+
+java_library_static {
+ name: "services.wallpapereffectsgeneration",
+ defaults: ["platform_service_defaults"],
+ srcs: [":services.wallpapereffectsgeneration-sources"],
+ libs: ["services.core"],
+}
diff --git a/services/wallpapereffectsgeneration/java/com/android/server/wallpapereffectsgeneration/RemoteWallpaperEffectsGenerationService.java b/services/wallpapereffectsgeneration/java/com/android/server/wallpapereffectsgeneration/RemoteWallpaperEffectsGenerationService.java
new file mode 100644
index 000000000000..c228dafcee8e
--- /dev/null
+++ b/services/wallpapereffectsgeneration/java/com/android/server/wallpapereffectsgeneration/RemoteWallpaperEffectsGenerationService.java
@@ -0,0 +1,113 @@
+/*
+ * 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.wallpapereffectsgeneration;
+
+import android.annotation.NonNull;
+import android.content.ComponentName;
+import android.content.Context;
+import android.os.IBinder;
+import android.service.wallpapereffectsgeneration.IWallpaperEffectsGenerationService;
+import android.service.wallpapereffectsgeneration.WallpaperEffectsGenerationService;
+import android.text.format.DateUtils;
+
+import com.android.internal.infra.AbstractMultiplePendingRequestsRemoteService;
+
+
+/**
+ * Proxy to the
+ * {@link android.service.wallpapereffectsgeneration.WallpaperEffectsGenerationService}
+ * implementation in another process.
+ */
+public class RemoteWallpaperEffectsGenerationService extends
+ AbstractMultiplePendingRequestsRemoteService<RemoteWallpaperEffectsGenerationService,
+ IWallpaperEffectsGenerationService> {
+
+ private static final String TAG =
+ RemoteWallpaperEffectsGenerationService.class.getSimpleName();
+
+ private static final long TIMEOUT_REMOTE_REQUEST_MILLIS = 2 * DateUtils.SECOND_IN_MILLIS;
+
+ private final RemoteWallpaperEffectsGenerationServiceCallback mCallback;
+
+ public RemoteWallpaperEffectsGenerationService(Context context,
+ ComponentName componentName, int userId,
+ RemoteWallpaperEffectsGenerationServiceCallback callback,
+ boolean bindInstantServiceAllowed,
+ boolean verbose) {
+ super(context, WallpaperEffectsGenerationService.SERVICE_INTERFACE,
+ componentName, userId, callback,
+ context.getMainThreadHandler(),
+ bindInstantServiceAllowed ? Context.BIND_ALLOW_INSTANT : 0,
+ verbose, /* initialCapacity= */ 1);
+ mCallback = callback;
+ }
+
+ @Override
+ protected IWallpaperEffectsGenerationService getServiceInterface(IBinder service) {
+ return IWallpaperEffectsGenerationService.Stub.asInterface(service);
+ }
+
+ @Override
+ protected long getTimeoutIdleBindMillis() {
+ return PERMANENT_BOUND_TIMEOUT_MS;
+ }
+
+ @Override
+ protected long getRemoteRequestMillis() {
+ return TIMEOUT_REMOTE_REQUEST_MILLIS;
+ }
+
+ /**
+ * Schedules a request to bind to the remote service.
+ */
+ public void reconnect() {
+ super.scheduleBind();
+ }
+
+ /**
+ * Schedule async request on remote service.
+ */
+ public void scheduleOnResolvedService(
+ @NonNull AsyncRequest<IWallpaperEffectsGenerationService> request) {
+ scheduleAsyncRequest(request);
+ }
+
+ /**
+ * Execute async request on remote service immediately instead of sending it to Handler queue.
+ */
+ public void executeOnResolvedService(
+ @NonNull AsyncRequest<IWallpaperEffectsGenerationService> request) {
+ executeAsyncRequest(request);
+ }
+
+ /**
+ * Notifies server (WallpaperEffectsGenerationPerUserService) about unexpected events..
+ */
+ public interface RemoteWallpaperEffectsGenerationServiceCallback
+ extends VultureCallback<RemoteWallpaperEffectsGenerationService> {
+ /**
+ * Notifies change in connected state of the remote service.
+ */
+ void onConnectedStateChanged(boolean connected);
+ }
+
+ @Override // from AbstractRemoteService
+ protected void handleOnConnectedStateChanged(boolean connected) {
+ if (mCallback != null) {
+ mCallback.onConnectedStateChanged(connected);
+ }
+ }
+}
diff --git a/services/wallpapereffectsgeneration/java/com/android/server/wallpapereffectsgeneration/WallpaperEffectsGenerationManagerService.java b/services/wallpapereffectsgeneration/java/com/android/server/wallpapereffectsgeneration/WallpaperEffectsGenerationManagerService.java
new file mode 100644
index 000000000000..0d0b3e098750
--- /dev/null
+++ b/services/wallpapereffectsgeneration/java/com/android/server/wallpapereffectsgeneration/WallpaperEffectsGenerationManagerService.java
@@ -0,0 +1,185 @@
+/*
+ * 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.wallpapereffectsgeneration;
+
+import static android.Manifest.permission.MANAGE_WALLPAPER_EFFECTS_GENERATION;
+import static android.app.ActivityManagerInternal.ALLOW_NON_FULL;
+import static android.content.Context.WALLPAPER_EFFECTS_GENERATION_SERVICE;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.UserIdInt;
+import android.app.ActivityManagerInternal;
+import android.app.wallpapereffectsgeneration.CinematicEffectRequest;
+import android.app.wallpapereffectsgeneration.CinematicEffectResponse;
+import android.app.wallpapereffectsgeneration.ICinematicEffectListener;
+import android.app.wallpapereffectsgeneration.IWallpaperEffectsGenerationManager;
+import android.content.Context;
+import android.os.Binder;
+import android.os.RemoteException;
+import android.os.ResultReceiver;
+import android.os.ShellCallback;
+import android.util.Slog;
+
+import com.android.server.LocalServices;
+import com.android.server.infra.AbstractMasterSystemService;
+import com.android.server.infra.FrameworkResourcesServiceNameResolver;
+import com.android.server.wm.ActivityTaskManagerInternal;
+
+import java.io.FileDescriptor;
+import java.util.function.Consumer;
+
+/**
+ * A service used to return wallpaper effect given a request.
+ */
+public class WallpaperEffectsGenerationManagerService extends
+ AbstractMasterSystemService<WallpaperEffectsGenerationManagerService,
+ WallpaperEffectsGenerationPerUserService> {
+ private static final String TAG =
+ WallpaperEffectsGenerationManagerService.class.getSimpleName();
+ private static final boolean DEBUG = false;
+ private static final int MAX_TEMP_SERVICE_DURATION_MS = 1_000 * 60 * 2; // 2 minutes
+ private final ActivityTaskManagerInternal mActivityTaskManagerInternal;
+
+ public WallpaperEffectsGenerationManagerService(Context context) {
+ super(context,
+ new FrameworkResourcesServiceNameResolver(context,
+ com.android.internal.R.string.config_defaultWallpaperEffectsGenerationService),
+ null,
+ PACKAGE_UPDATE_POLICY_NO_REFRESH | PACKAGE_RESTART_POLICY_NO_REFRESH);
+ mActivityTaskManagerInternal = LocalServices.getService(ActivityTaskManagerInternal.class);
+ }
+
+ @Override
+ protected WallpaperEffectsGenerationPerUserService newServiceLocked(int resolvedUserId,
+ boolean disabled) {
+ return new WallpaperEffectsGenerationPerUserService(this, mLock, resolvedUserId);
+ }
+
+ @Override
+ public void onStart() {
+ publishBinderService(WALLPAPER_EFFECTS_GENERATION_SERVICE,
+ new WallpaperEffectsGenerationManagerStub());
+ }
+
+ @Override
+ protected void enforceCallingPermissionForManagement() {
+ getContext().enforceCallingPermission(MANAGE_WALLPAPER_EFFECTS_GENERATION, TAG);
+ }
+
+ @Override // from AbstractMasterSystemService
+ protected void onServicePackageUpdatedLocked(@UserIdInt int userId) {
+ final WallpaperEffectsGenerationPerUserService service = peekServiceForUserLocked(userId);
+ if (service != null) {
+ service.onPackageUpdatedLocked();
+ }
+ }
+
+ @Override // from AbstractMasterSystemService
+ protected void onServicePackageRestartedLocked(@UserIdInt int userId) {
+ final WallpaperEffectsGenerationPerUserService service = peekServiceForUserLocked(userId);
+ if (service != null) {
+ service.onPackageRestartedLocked();
+ }
+ }
+
+ @Override
+ protected int getMaximumTemporaryServiceDurationMs() {
+ return MAX_TEMP_SERVICE_DURATION_MS;
+ }
+
+ private class WallpaperEffectsGenerationManagerStub
+ extends IWallpaperEffectsGenerationManager.Stub {
+ @Override
+ public void generateCinematicEffect(@NonNull CinematicEffectRequest request,
+ @NonNull ICinematicEffectListener listener) {
+ if (!runForUserLocked("generateCinematicEffect", (service) ->
+ service.onGenerateCinematicEffectLocked(request, listener))) {
+ try {
+ listener.onCinematicEffectGenerated(
+ new CinematicEffectResponse.Builder(
+ CinematicEffectResponse.CINEMATIC_EFFECT_STATUS_ERROR,
+ request.getTaskId()).build());
+ } catch (RemoteException e) {
+ if (DEBUG) {
+ Slog.d(TAG, "fail to invoke cinematic effect listener for task["
+ + request.getTaskId() + "]");
+ }
+ }
+ }
+ }
+
+ @Override
+ public void returnCinematicEffectResponse(@NonNull CinematicEffectResponse response) {
+ runForUserLocked("returnCinematicResponse", (service) ->
+ service.onReturnCinematicEffectResponseLocked(response));
+ }
+
+ public void onShellCommand(@Nullable FileDescriptor in, @Nullable FileDescriptor out,
+ @Nullable FileDescriptor err,
+ @NonNull String[] args, @Nullable ShellCallback callback,
+ @NonNull ResultReceiver resultReceiver) {
+ new WallpaperEffectsGenerationManagerServiceShellCommand(
+ WallpaperEffectsGenerationManagerService.this)
+ .exec(this, in, out, err, args, callback, resultReceiver);
+ }
+
+ /**
+ * Execute the operation for the user locked. Return true if
+ * WallpaperEffectsGenerationPerUserService is found for the user.
+ * Otherwise return false.
+ */
+ private boolean runForUserLocked(@NonNull final String func,
+ @NonNull final Consumer<WallpaperEffectsGenerationPerUserService> c) {
+ ActivityManagerInternal am = LocalServices.getService(ActivityManagerInternal.class);
+ final int userId = am.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
+ Binder.getCallingUserHandle().getIdentifier(), false, ALLOW_NON_FULL,
+ null, null);
+ if (DEBUG) {
+ Slog.d(TAG, "runForUserLocked:" + func + " from pid=" + Binder.getCallingPid()
+ + ", uid=" + Binder.getCallingUid());
+ }
+ Context ctx = getContext();
+ if (!(ctx.checkCallingPermission(MANAGE_WALLPAPER_EFFECTS_GENERATION)
+ == PERMISSION_GRANTED
+ || mServiceNameResolver.isTemporary(userId)
+ || mActivityTaskManagerInternal.isCallerRecents(Binder.getCallingUid()))) {
+ String msg = "Permission Denial: Cannot call " + func + " from pid="
+ + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid();
+ Slog.w(TAG, msg);
+ throw new SecurityException(msg);
+ }
+ final long origId = Binder.clearCallingIdentity();
+ boolean accepted = false;
+ try {
+ synchronized (mLock) {
+ final WallpaperEffectsGenerationPerUserService service =
+ getServiceForUserLocked(userId);
+ if (service != null) {
+ accepted = true;
+ c.accept(service);
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(origId);
+ }
+
+ return accepted;
+ }
+ }
+}
diff --git a/services/wallpapereffectsgeneration/java/com/android/server/wallpapereffectsgeneration/WallpaperEffectsGenerationManagerServiceShellCommand.java b/services/wallpapereffectsgeneration/java/com/android/server/wallpapereffectsgeneration/WallpaperEffectsGenerationManagerServiceShellCommand.java
new file mode 100644
index 000000000000..fc6f75fc254e
--- /dev/null
+++ b/services/wallpapereffectsgeneration/java/com/android/server/wallpapereffectsgeneration/WallpaperEffectsGenerationManagerServiceShellCommand.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.wallpapereffectsgeneration;
+
+import android.annotation.NonNull;
+import android.os.ShellCommand;
+
+import java.io.PrintWriter;
+
+/**
+ * The shell command implementation for the WallpaperEffectsGenerationService.
+ */
+public class WallpaperEffectsGenerationManagerServiceShellCommand extends ShellCommand {
+
+ private static final String TAG =
+ WallpaperEffectsGenerationManagerServiceShellCommand.class.getSimpleName();
+
+ private final WallpaperEffectsGenerationManagerService mService;
+
+ public WallpaperEffectsGenerationManagerServiceShellCommand(
+ @NonNull WallpaperEffectsGenerationManagerService service) {
+ mService = service;
+ }
+
+ @Override
+ public int onCommand(String cmd) {
+ if (cmd == null) {
+ return handleDefaultCommands(cmd);
+ }
+ final PrintWriter pw = getOutPrintWriter();
+ switch (cmd) {
+ case "set": {
+ final String what = getNextArgRequired();
+ switch (what) {
+ case "temporary-service": {
+ final int userId = Integer.parseInt(getNextArgRequired());
+ String serviceName = getNextArg();
+ if (serviceName == null) {
+ mService.resetTemporaryService(userId);
+ pw.println("WallpaperEffectsGenerationService temporarily reset. ");
+ return 0;
+ }
+ final int duration = Integer.parseInt(getNextArgRequired());
+ mService.setTemporaryService(userId, serviceName, duration);
+ pw.println("WallpaperEffectsGenerationService temporarily set to "
+ + serviceName + " for " + duration + "ms");
+ break;
+ }
+ }
+ }
+ break;
+ default:
+ return handleDefaultCommands(cmd);
+ }
+ return 0;
+ }
+
+ @Override
+ public void onHelp() {
+ try (PrintWriter pw = getOutPrintWriter()) {
+ pw.println("WallpaperEffectsGenerationService commands:");
+ pw.println(" help");
+ pw.println(" Prints this help text.");
+ pw.println("");
+ pw.println(" set temporary-service USER_ID [COMPONENT_NAME DURATION]");
+ pw.println(" Temporarily (for DURATION ms) changes the service implemtation.");
+ pw.println(" To reset, call with just the USER_ID argument.");
+ pw.println("");
+ }
+ }
+}
diff --git a/services/wallpapereffectsgeneration/java/com/android/server/wallpapereffectsgeneration/WallpaperEffectsGenerationPerUserService.java b/services/wallpapereffectsgeneration/java/com/android/server/wallpapereffectsgeneration/WallpaperEffectsGenerationPerUserService.java
new file mode 100644
index 000000000000..d541051e5ab2
--- /dev/null
+++ b/services/wallpapereffectsgeneration/java/com/android/server/wallpapereffectsgeneration/WallpaperEffectsGenerationPerUserService.java
@@ -0,0 +1,274 @@
+/*
+ * 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.wallpapereffectsgeneration;
+
+import android.Manifest;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.AppGlobals;
+import android.app.wallpapereffectsgeneration.CinematicEffectRequest;
+import android.app.wallpapereffectsgeneration.CinematicEffectResponse;
+import android.app.wallpapereffectsgeneration.ICinematicEffectListener;
+import android.content.ComponentName;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.ServiceInfo;
+import android.os.RemoteException;
+import android.util.Slog;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.server.infra.AbstractPerUserSystemService;
+
+/**
+ * Per-user instance of {@link WallpaperEffectsGenerationManagerService}.
+ */
+public class WallpaperEffectsGenerationPerUserService extends
+ AbstractPerUserSystemService<WallpaperEffectsGenerationPerUserService,
+ WallpaperEffectsGenerationManagerService> implements
+ RemoteWallpaperEffectsGenerationService.RemoteWallpaperEffectsGenerationServiceCallback {
+
+ private static final String TAG =
+ WallpaperEffectsGenerationPerUserService.class.getSimpleName();
+
+ @GuardedBy("mLock")
+ private CinematicEffectListenerWrapper mCinematicEffectListenerWrapper;
+
+ @Nullable
+ @GuardedBy("mLock")
+ private RemoteWallpaperEffectsGenerationService mRemoteService;
+
+ protected WallpaperEffectsGenerationPerUserService(
+ WallpaperEffectsGenerationManagerService master,
+ Object lock, int userId) {
+ super(master, lock, userId);
+ }
+
+ @Override // from PerUserSystemService
+ protected ServiceInfo newServiceInfoLocked(@NonNull ComponentName serviceComponent)
+ throws NameNotFoundException {
+ ServiceInfo si;
+ try {
+ si = AppGlobals.getPackageManager().getServiceInfo(serviceComponent,
+ PackageManager.GET_META_DATA, mUserId);
+ } catch (RemoteException e) {
+ throw new NameNotFoundException("Could not get service for " + serviceComponent);
+ }
+ if (!Manifest.permission.BIND_WALLPAPER_EFFECTS_GENERATION_SERVICE.equals(si.permission)) {
+ Slog.w(TAG, "WallpaperEffectsGenerationService from '" + si.packageName
+ + "' does not require permission "
+ + Manifest.permission.BIND_WALLPAPER_EFFECTS_GENERATION_SERVICE);
+ throw new SecurityException("Service does not require permission "
+ + Manifest.permission.BIND_WALLPAPER_EFFECTS_GENERATION_SERVICE);
+ }
+ return si;
+ }
+
+ @GuardedBy("mLock")
+ @Override // from PerUserSystemService
+ protected boolean updateLocked(boolean disabled) {
+ final boolean enabledChanged = super.updateLocked(disabled);
+ updateRemoteServiceLocked();
+ return enabledChanged;
+ }
+
+ /**
+ * Notifies the service of a new cinematic effect generation request.
+ */
+ @GuardedBy("mLock")
+ public void onGenerateCinematicEffectLocked(
+ @NonNull CinematicEffectRequest cinematicEffectRequest,
+ @NonNull ICinematicEffectListener cinematicEffectListener) {
+ String newTaskId = cinematicEffectRequest.getTaskId();
+ // Previous request is still being processed.
+ if (mCinematicEffectListenerWrapper != null) {
+ if (mCinematicEffectListenerWrapper.mTaskId.equals(newTaskId)) {
+ invokeCinematicListenerAndCleanup(
+ new CinematicEffectResponse.Builder(
+ CinematicEffectResponse.CINEMATIC_EFFECT_STATUS_PENDING, newTaskId)
+ .build()
+ );
+ } else {
+ invokeCinematicListenerAndCleanup(
+ new CinematicEffectResponse.Builder(
+ CinematicEffectResponse.CINEMATIC_EFFECT_STATUS_TOO_MANY_REQUESTS,
+ newTaskId).build()
+ );
+ }
+ return;
+ }
+ RemoteWallpaperEffectsGenerationService remoteService = ensureRemoteServiceLocked();
+ if (remoteService != null) {
+ remoteService.executeOnResolvedService(
+ s -> s.onGenerateCinematicEffect(cinematicEffectRequest));
+ mCinematicEffectListenerWrapper =
+ new CinematicEffectListenerWrapper(newTaskId, cinematicEffectListener);
+ } else {
+ if (isDebug()) {
+ Slog.d(TAG, "Remote service not found");
+ }
+ try {
+ cinematicEffectListener.onCinematicEffectGenerated(
+ createErrorCinematicEffectResponse(newTaskId));
+ } catch (RemoteException e) {
+ if (isDebug()) {
+ Slog.d(TAG, "Failed to invoke cinematic effect listener for task [" + newTaskId
+ + "]");
+ }
+ }
+ }
+ }
+
+ /**
+ * Notifies the service of a generated cinematic effect response.
+ */
+ @GuardedBy("mLock")
+ public void onReturnCinematicEffectResponseLocked(
+ @NonNull CinematicEffectResponse cinematicEffectResponse) {
+ invokeCinematicListenerAndCleanup(cinematicEffectResponse);
+ }
+
+ @GuardedBy("mLock")
+ private void updateRemoteServiceLocked() {
+ if (mRemoteService != null) {
+ mRemoteService.destroy();
+ mRemoteService = null;
+ }
+ // End existing response and clean up listener for next request.
+ if (mCinematicEffectListenerWrapper != null) {
+ invokeCinematicListenerAndCleanup(
+ createErrorCinematicEffectResponse(mCinematicEffectListenerWrapper.mTaskId));
+ }
+
+ }
+
+ void onPackageUpdatedLocked() {
+ if (isDebug()) {
+ Slog.v(TAG, "onPackageUpdatedLocked()");
+ }
+ destroyAndRebindRemoteService();
+ }
+
+ void onPackageRestartedLocked() {
+ if (isDebug()) {
+ Slog.v(TAG, "onPackageRestartedLocked()");
+ }
+ destroyAndRebindRemoteService();
+ }
+
+ private void destroyAndRebindRemoteService() {
+ if (mRemoteService == null) {
+ return;
+ }
+
+ if (isDebug()) {
+ Slog.d(TAG, "Destroying the old remote service.");
+ }
+ mRemoteService.destroy();
+ mRemoteService = null;
+ mRemoteService = ensureRemoteServiceLocked();
+ if (mRemoteService != null) {
+ if (isDebug()) {
+ Slog.d(TAG, "Rebinding to the new remote service.");
+ }
+ mRemoteService.reconnect();
+ }
+ // Clean up listener for next request.
+ if (mCinematicEffectListenerWrapper != null) {
+ invokeCinematicListenerAndCleanup(
+ createErrorCinematicEffectResponse(mCinematicEffectListenerWrapper.mTaskId));
+ }
+ }
+
+ private CinematicEffectResponse createErrorCinematicEffectResponse(String taskId) {
+ return new CinematicEffectResponse.Builder(
+ CinematicEffectResponse.CINEMATIC_EFFECT_STATUS_ERROR,
+ taskId).build();
+ }
+
+ @GuardedBy("mLock")
+ private void invokeCinematicListenerAndCleanup(
+ CinematicEffectResponse cinematicEffectResponse) {
+ try {
+ if (mCinematicEffectListenerWrapper != null
+ && mCinematicEffectListenerWrapper.mListener != null) {
+ mCinematicEffectListenerWrapper.mListener.onCinematicEffectGenerated(
+ cinematicEffectResponse);
+ } else {
+ if (isDebug()) {
+ Slog.w(TAG, "Cinematic effect listener not found for task["
+ + mCinematicEffectListenerWrapper.mTaskId + "]");
+ }
+ }
+ } catch (RemoteException e) {
+ if (isDebug()) {
+ Slog.w(TAG, "Error invoking cinematic effect listener for task["
+ + mCinematicEffectListenerWrapper.mTaskId + "]");
+ }
+ } finally {
+ mCinematicEffectListenerWrapper = null;
+ }
+ }
+
+ @GuardedBy("mLock")
+ @Nullable
+ private RemoteWallpaperEffectsGenerationService ensureRemoteServiceLocked() {
+ if (mRemoteService == null) {
+ final String serviceName = getComponentNameLocked();
+ if (serviceName == null) {
+ if (mMaster.verbose) {
+ Slog.v(TAG, "ensureRemoteServiceLocked(): not set");
+ }
+ return null;
+ }
+ ComponentName serviceComponent = ComponentName.unflattenFromString(serviceName);
+
+ mRemoteService = new RemoteWallpaperEffectsGenerationService(getContext(),
+ serviceComponent, mUserId, this,
+ mMaster.isBindInstantServiceAllowed(), mMaster.verbose);
+ }
+
+ return mRemoteService;
+ }
+
+ @Override // from RemoteWallpaperEffectsGenerationService
+ public void onServiceDied(RemoteWallpaperEffectsGenerationService service) {
+ Slog.w(TAG, "remote wallpaper effects generation service died");
+ updateRemoteServiceLocked();
+ }
+
+ @Override // from RemoteWallpaperEffectsGenerationService
+ public void onConnectedStateChanged(boolean connected) {
+ if (!connected) {
+ Slog.w(TAG, "remote wallpaper effects generation service disconnected");
+ updateRemoteServiceLocked();
+ }
+ }
+
+ private static final class CinematicEffectListenerWrapper {
+ @NonNull
+ private final String mTaskId;
+ @NonNull
+ private final ICinematicEffectListener mListener;
+
+ CinematicEffectListenerWrapper(
+ @NonNull final String taskId,
+ @NonNull final ICinematicEffectListener listener) {
+ mTaskId = taskId;
+ mListener = listener;
+ }
+ }
+}
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index e0e791321819..3c277b7de018 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -4540,9 +4540,7 @@ public class CarrierConfigManager {
* Passing this value as {@link #KEY_SUBSCRIPTION_GROUP_UUID_STRING} will remove the
* subscription from a group instead of adding it to a group.
*
- * TODO: Expose in a future release.
- *
- * @hide
+ * <p>This value will work all the way back to {@link android.os.Build.VERSION_CODES#Q}.
*/
public static final String REMOVE_GROUP_UUID_STRING = "00000000-0000-0000-0000-000000000000";
@@ -4555,9 +4553,7 @@ public class CarrierConfigManager {
* <p>If set to {@link #REMOVE_GROUP_UUID_STRING}, then the subscription will be removed from
* its current group.
*
- * TODO: unhide this key.
- *
- * @hide
+ * <p>This key will work all the way back to {@link android.os.Build.VERSION_CODES#Q}.
*/
public static final String KEY_SUBSCRIPTION_GROUP_UUID_STRING =
"subscription_group_uuid_string";
@@ -4605,17 +4601,15 @@ public class CarrierConfigManager {
"data_switch_validation_min_gap_long";
/**
- * A boolean property indicating whether this subscription should be managed as an opportunistic
- * subscription.
- *
- * If true, then this subscription will be selected based on available coverage and will not be
- * available for a user in settings menus for selecting macro network providers. If unset,
- * defaults to “false”.
- *
- * TODO: unhide this key.
- *
- * @hide
- */
+ * A boolean property indicating whether this subscription should be managed as an opportunistic
+ * subscription.
+ *
+ * If true, then this subscription will be selected based on available coverage and will not be
+ * available for a user in settings menus for selecting macro network providers. If unset,
+ * defaults to “false”.
+ *
+ * <p>This key will work all the way back to {@link android.os.Build.VERSION_CODES#Q}.
+ */
public static final String KEY_IS_OPPORTUNISTIC_SUBSCRIPTION_BOOL =
"is_opportunistic_subscription_bool";